Featurely Docs
SDKs

featurely-site-manager

Maintenance mode, feature flags, status banners, version management, and analytics.

featurely-site-manager

Installation

npm install featurely-site-manager

Requires a public:read API key.

Configuration options

OptionTypeDefaultDescription
apiKeystring—Required. API key with public:read permission
projectIdstring—Required. Your project ID
apiUrlstring—Custom API endpoint
environmentstring—Hostname override or environment slug (useful server-side)
pollIntervalnumber60000Config polling interval in ms
userEmailstring—Current user's email (for maintenance whitelist checks)
userIdstring—Current user's ID
customAttributesRecord<string, string | number | boolean>—Targeting attributes for feature flag rules
bootstrapFlagsRecord<string, boolean>—Pre-loaded flag values for SSR to avoid layout shift
enableAnalyticsbooleantrueEnable automatic analytics tracking
analyticsFlushIntervalnumber60000How often to flush analytics events (ms)
autoCaptureClicksbooleanfalseAuto-track clicks on elements with data-featurely-click
autoInjectBannersbooleantrueAuto-inject status message banners into the page DOM
enableHeatmapsbooleanfalseEnable click heatmap tracking with coordinates
enableRageClickDetectionbooleanfalseDetect rage clicks (multiple rapid clicks)
enableScrollTrackingbooleanfalseTrack scroll depth per page
enablePerformanceTrackingbooleanfalseTrack resource timing and long tasks
heatmapSampleRatenumber10Percentage of sessions to collect heatmap data from (0–100)
appVersionstring—Current application version
enableVersionCheckbooleanfalseEnable automatic version checking
versionCheckIntervalnumber3600000Version check interval in ms
platformstring—web, ios, android, electron, or tauri
updateRulesVersionUpdateRules—Override how SemVer change types are classified
debugModebooleanfalseEnable the floating debug overlay panel
debugSecretstring—Token for the production debug handshake (?ft_debug=<token>)
bypassCheck() => boolean—Custom function — return true to bypass maintenance mode
onMaintenanceEnabled(config: MaintenanceConfig) => void—Callback when maintenance mode activates
onMaintenanceDisabled() => void—Callback when maintenance mode deactivates
onMessageReceived(message: StatusMessage) => void—Callback when a new status message arrives
onMessageDismissed(messageId: string) => void—Callback when a message is dismissed
onFeatureFlagsUpdated(flags: FeatureFlag[]) => void—Callback when feature flags update
onUpdateAvailable(info: VersionCheckResponse) => void—Callback when a new version is available
onUpdateRequired(info: VersionCheckResponse) => void—Callback when an update is required
onError(error: Error) => void—Callback when the SDK encounters an error

Basic usage

import SiteManager from 'featurely-site-manager';

const siteManager = new SiteManager({
  apiKey: process.env.NEXT_PUBLIC_FEATURELY_API_KEY!,
  projectId: process.env.NEXT_PUBLIC_FEATURELY_PROJECT_ID!,
});

await siteManager.init();

Maintenance mode

import SiteManager from 'featurely-site-manager';

const siteManager = new SiteManager({
  apiKey: 'ft_live_your_api_key_here',
  projectId: 'your-project-id',
  onMaintenanceEnabled: () => {
    // Redirect or show maintenance page
    window.location.href = '/maintenance';
  },
  onMaintenanceDisabled: () => {
    // Site is back up
    window.location.reload();
  },
});

await siteManager.init();

console.log(siteManager.isInMaintenanceMode()); // false

Status messages

Status messages are automatically injected as banners when autoInjectBanners: true (the default). Each message has:

  • 4 types: info, warning, error, success
  • 2 positions: top, bottom
  • 2 styles: banner, toast
  • Optional start and end schedule
  • Dismissible by users

To handle messages manually instead:

import SiteManager from 'featurely-site-manager';

const siteManager = new SiteManager({
  apiKey: 'ft_live_your_api_key_here',
  projectId: 'your-project-id',
  autoInjectBanners: false,
  onMessageReceived: (message) => {
    console.log('New message:', message.title);
  },
});

await siteManager.init();

const messages = siteManager.getActiveMessages();

Feature flags

For a walkthrough of using Featurely feature flags on indie and small-team stacks, see Feature flags without LaunchDarkly.

import SiteManager from 'featurely-site-manager';

const siteManager = new SiteManager({
  apiKey: 'ft_live_your_api_key_here',
  projectId: 'your-project-id',
});

await siteManager.init();

// Simple boolean flag
if (siteManager.isFeatureEnabled('new_dashboard')) {
  // Show new dashboard
}

// A/B variant
const variant = siteManager.getFeatureVariant('checkout_flow'); // 'control' | 'variant_a' | ...

// Local override (useful for testing) — pass null to remove the override
siteManager.overrideFlag('new_dashboard', true);

// URL param override (applies automatically): ?ft_new_dashboard=true

Targeting with custom attributes

const siteManager = new SiteManager({
  apiKey: 'ft_live_your_api_key_here',
  projectId: 'your-project-id',
  customAttributes: {
    plan: 'pro',
    country: 'no',
    beta: true,
  },
});

SSR / Bootstrap flags

Pre-load flag values on the server to avoid layout shift:

// Pass pre-fetched flags to avoid a loading state on the client
const siteManager = new SiteManager({
  apiKey: 'ft_live_your_api_key_here',
  projectId: 'your-project-id',
  bootstrapFlags: {
    new_dashboard: true,
    checkout_v2: false,
  },
});

User identity

Call setUser() after login to associate analytics events and feature flag targeting with the current user:

siteManager.setUser('user@example.com', 'usr_123', { plan: 'pro' });

Version management

import SiteManager from 'featurely-site-manager';

const siteManager = new SiteManager({
  apiKey: 'ft_live_your_api_key_here',
  projectId: 'your-project-id',
  appVersion: '1.2.3',
  enableVersionCheck: true,
  updateRules: {
    major: 'required',   // major bump → force update
    minor: 'available',  // minor bump → optional
    patch: 'recommended', // patch → recommended
  },
  onUpdateAvailable: (info) => {
    console.log('Update available:', info.latestVersion?.version);
  },
  onUpdateRequired: async (info) => {
    await siteManager.forceUpdateWeb();
  },
});

await siteManager.init();

updateRules fields:

  • major: "required" | "available" (default: "required")
  • minor: "required" | "available" (default: "available")
  • patch: "required" | "recommended" | "available" (default: "recommended")

Supported version formats: SemVer (1.2.3) and git hashes.

Analytics

The following events are tracked automatically:

EventTrigger
session_startSDK init
page_viewPage navigation
page_exitPage unload
outbound_link_clickClicks on external links
web_vitalCore Web Vitals
feature_flag_evaluatedFirst flag evaluation per session
user_loginWhen setUser() is called for the first time
// Custom event
siteManager.trackEvent('signup_completed', { plan: 'pro' });

// Revenue event
siteManager.trackRevenue('purchase_completed', 49.99, 'USD', { productId: 'pro_plan' });

// Track 404s — call this in your 404 page component on mount
siteManager.track404();

To track clicks automatically, add data-featurely-click attributes to elements and enable autoCaptureClicks: true in the config:

<button data-featurely-click="upgrade_button">Upgrade</button>

Analytics are privacy-friendly: data is stored in localStorage, no cookies are used, and IP addresses are never stored.

Debug overlay

When debugMode is enabled, a floating panel appears with tabs for SDK state, feature flags, logs, network calls, events, and a test panel. In production, the overlay can be activated for a single page load via a URL parameter handshake:

?ft_debug=your_debug_secret

Set debugSecret in your config to enable this.

All instance methods

MethodDescription
init()Initialize the SDK, fetch config, and start polling
destroy()Stop polling, flush analytics, and clean up
setUser(email, userId?, customAttributes?)Set user identity for targeting and analytics
isInMaintenanceMode()Returns whether maintenance mode is currently active
getActiveMessages()Returns active status messages
isFeatureEnabled(key, default?)Returns flag boolean for the current user
getFeatureVariant(key)Returns the A/B variant string for a flag
overrideFlag(key, value | null)Override a flag locally; pass null to remove
getAllFeatureFlags()Returns all flag objects from the loaded config
getEnabledFeatures()Returns keys of all flags enabled for the current user
trackEvent(name, props?)Track a custom analytics event
trackRevenue(name, amount, currency, props?)Track a revenue event
track404(path?)Track a page-not-found event
checkVersion(version?)Manually trigger a version check
forceUpdateWeb()Force a full page reload to apply an update
getLastVersionCheck()Returns the last version check result
getActiveEnvironment()Returns the matched environment config
isErrorLoggingEnabled()Returns whether error logging is on for the matched environment
refresh()Force re-fetch config from the API

TypeScript exports

SiteManager (default), SiteManagerConfig, VersionUpdateRules, FeatureFlag, StatusMessage, MaintenanceConfig, VersionCheckResponse, SiteConfig, AnalyticsConfig, AppVersion