Browse docs

Explore by section, then jump directly into a page.

Node.js / Backend

Core / Node.js SDK

The base SDK for Node.js services, backend workers, CLIs, and any custom JavaScript integration.

@flash-analytics/sdk is the shared core used by all browser wrappers. Use it directly when you need server-side tracking — background jobs, payment webhooks, admin scripts, or any non-browser runtime.

Installation

1

Install the package

Terminal
npm install @flash-analytics/sdk@2.2.4
Terminal
pnpm add @flash-analytics/sdk@2.2.4
2

Set environment variables

.envTerminal
FLASH_ANALYTICS_CLIENT_ID=00000000-0000-4000-8000-000000000000
FLASH_ANALYTICS_SECRET_KEY=your-secret-key
The secret key is safe to use server-side. Never expose it in browser bundles or public environment variables.
3

Create the SDK instance

lib/analytics.tsTypeScript
import { FlashAnalytics } from '@flash-analytics/sdk';

export const analytics = new FlashAnalytics({
  appId: process.env.FLASH_ANALYTICS_CLIENT_ID!,
  secretKey: process.env.FLASH_ANALYTICS_SECRET_KEY,
  platform: 'node',
  appVersion: process.env.npm_package_version,
  deliveryStrategy: {
    strategy: 'batching',
    config: {
      size: 25,
      timeout: 5000,
      fallbackToIndividual: true,
    },
  },
});
4

Track events

TypeScript
import { analytics } from './lib/analytics';

// Identify a user (attach a profileId to future events)
await analytics.identify({ profileId: 'user_123', email: 'user@example.com' });

// Track a named event with properties
await analytics.track('invoice_paid', {
  profileId: 'user_123',
  invoiceId: 'inv_456',
  amount: 99.00,
  currency: 'USD',
});

// Flush the batch before the process exits
await analytics.flushBatch();

Core APIs

track(name, props?)

Send a named event

identify(payload)

Set profileId and user properties

setGlobalProperties(props)

Merge into every subsequent event

revenue(amount, props?)

Record a charge or purchase

increment(payload)

Add to a numeric user property

decrement(payload)

Subtract from a numeric user property

getSession()

Read session ID and expiry

fetchRemoteConfig(opts)

Pull feature flag values

assignExperiment(id)

Get an A/B assignment

flushBatch()

Force-send queued events

Global properties

Call setGlobalProperties once at startup to tag every event with context.

TypeScript
analytics.setGlobalProperties({
  service: 'billing-worker',
  environment: process.env.NODE_ENV,
  version: process.env.npm_package_version,
});

Session updates

Use getSession() when you need to read the latest session synchronously. Use onSessionUpdated when another layer needs the session as soon as the SDK receives, restores, or refreshes it.

TypeScript
const analytics = new FlashAnalytics({
  appId: process.env.FLASH_ANALYTICS_CLIENT_ID!,
  secretKey: process.env.FLASH_ANALYTICS_SECRET_KEY,
  onSessionUpdated(session) {
    console.log(session.id);
    console.log(session.estimatedExpiresAt);
    console.log(session.estimatedTtlMs);
  },
});

const session = analytics.getSession();
console.log(session?.id);

The callback runs after successful tracking responses return session data. In browser wrappers it can also run during initialization when a valid cached session is restored.

Batching

Enable batching for high-throughput workers. Events are timestamped when they enter the queue, not when the batch is flushed, so ordering reflects real activity time. Batch responses update the same session cache used by getSession() and onSessionUpdated.

TypeScript
const analytics = new FlashAnalytics({
  appId: process.env.FLASH_ANALYTICS_CLIENT_ID!,
  deliveryStrategy: {
    strategy: 'batching',
    config: {
      size: 25,                     // flush after 25 events
      timeout: 5000,                // or every 5 seconds
      fallbackToIndividual: true,   // retry individually if batch fails
    },
  },
});

// Always flush at process exit
process.on('beforeExit', async () => {
  await analytics.flushBatch();
});

Dashboard collection controls

Supported SDKs automatically sync collection settings from the Flash dashboard. You can allow or block event names, allow or block event properties, set project-wide blocked properties, and define client-level overrides for specific apps or environments. Rules are applied before network delivery, so blocked events are dropped locally and blocked properties are removed before payloads leave your process.

TypeScript
const analytics = new FlashAnalytics({
  appId: process.env.FLASH_ANALYTICS_CLIENT_ID!,
  secretKey: process.env.FLASH_ANALYTICS_SECRET_KEY,

  // Defaults to true. Leave enabled to use dashboard-managed rules.
  collectionConfig: true,

  // Optional local override. Also sent to the backend and cached per client.
  maxSessionTimeoutInMin: 15,
});

sdk_initialized and sdk_heartbeat bypass user collection filters so session maintenance continues even when normal product events are restricted.

Dashboard rule exampleTEXT
Allow events:
  checkout.started
  checkout.completed
  account.*

Block events:
  debug.*
  internal_test

For checkout.completed, allow only:
  orderId
  amount
  currency
  plan

Block these properties everywhere:
  password
  token
  ssn
  rawCardNumber

Client-level override for backend-prod:
  block property internalTraceId
  max session timeout: 15 minutes
  batching: 25 events or 5 seconds

The same dashboard area can manage SDK defaults such as batching size, flush interval, session timeout, remote config values, and experiment assignment behavior. Code-level options are still available when you need an explicit environment override.

SDK-side allow and block rules

Add local rules when filtering must live in code. These rules are useful for dev builds, one-off clients, or guardrails that should run before the request is sent.

TypeScript
const analytics = new FlashAnalytics({
  appId: process.env.FLASH_ANALYTICS_CLIENT_ID!,
  secretKey: process.env.FLASH_ANALYTICS_SECRET_KEY,

  allowEvents: [
    {
      name: 'invoice.paid',
      allowProperties: ['invoiceId', 'amount', 'currency'],
      blockProperties: ['internalLedgerId'],
    },
    { name: 'account.*' },
  ],
  blockEvents: ['debug.*', 'internal_test'],
  blockProperties: ['password', 'authToken', 'ssn'],

  shouldTrack(payload) {
    if (payload.type === 'track' && payload.payload.name === 'health_check') {
      return false;
    }
    return true;
  },

  shouldCaptureRequest(url, payload) {
    return !url.includes('/track') || payload.type !== 'track' || process.env.NODE_ENV === 'production';
  },
});

Remote config

TypeScript
const config = await analytics.fetchRemoteConfig({
  profileId: 'user_123',
  userProperties: { plan: 'pro' },
  country: 'US',
});

const enabled  = config.getBoolean('new_checkout', false);
const title    = config.getString('checkout_title', 'Checkout');
const maxItems = config.getNumber('max_cart_items', 50);
const theme    = config.getJson('theme_config', {});

Experiments

TypeScript
// Enable auto-assignment at init
const analytics = new FlashAnalytics({
  appId: process.env.FLASH_ANALYTICS_CLIENT_ID!,
  captureVariants: true,
});

// Cache first, API fallback
const assignment = await analytics.getExperimentById('checkout-cta');
console.log(assignment?.variantName);

// Manual assignment (always calls the API)
const variant = await analytics.assignExperiment('checkout-cta', {
  profileId: 'user_123',
});

Server-side tracking tip

Always pass profileId in your track calls when you know the user. Server-side events without a profileId are linked by session only, which may result in fragmented user journeys in the dashboard.