JavaScript SDK

switchbox-js — the Switchbox class, methods, and options.

The browser SDK is published to npm as switchbox-js. It has zero runtime dependencies — only the browser's fetch and Web Crypto APIs. Using React? See the React SDK, which wraps this one.

npm install switchbox-js

The same reference ships in the package README on npm.

Switchbox.create(options)

import { Switchbox } from 'switchbox-js';
const client = await Switchbox.create({
sdkKey: 'your-sdk-key',
});

The recommended entry point. It constructs the client and awaits the first config fetch, resolving to a client that's ready to evaluate. Create one and reuse it.

Background refreshes are conditional requests: the SDK sends back the ETag the edge gave it, so a poll that finds nothing changed returns an empty 304 with no config body. In a browser that means steady-state polling costs your users almost no bandwidth, whatever the size of your config. This is automatic, with nothing to configure.

For advanced control you can split the two steps:

const client = new Switchbox({ sdkKey: 'your-sdk-key' });
await client.init();

Options

OptionTypeDefaultDescription
sdkKeystringThe environment's SDK key from the dashboard. Required.
cdnBaseUrlstringSwitchbox edgeOverride the CDN base URL (advanced).
pollIntervalnumber10Seconds between background config refreshes.
onError(error: Error) => voidCalled when a fetch or parse fails, or a hook you supplied throws.
onEvaluation(flagKey, result, user?) => voidCalled after every evaluation — wire it into your analytics. See Measure in your own analytics.
telemetrybooleantrueAnonymous usage telemetry (see below). false disables it.

client.enabled(flagKey, user?)

if (await client.enabled('new_checkout', { user_id: '42' })) {
showNewCheckout();
}

Resolves to whether a boolean flag is enabled. Returns false if the flag is absent. Async — evaluation uses Web Crypto for rollout hashing, so await it.

client.getValue(flagKey, user?, defaultValue?)

const algo = await client.getValue('search_algorithm', { user_id: '42' }, 'v1');

Resolves to a string, number, or JSON flag's value (a json flag comes back as a parsed object/array), or defaultValue if the flag is absent.

client.getAllFlags(user?)

const all = await client.getAllFlags({ user_id: '42' });
// { dark_mode: true, search_algorithm: 'v2', max_results: 50 }

Resolves to every flag's value for the user. Empty object if no config is loaded.

client.onConfigChange(callback)

const unsubscribe = client.onConfigChange(() => {
// a new config version arrived — re-read any flags you're displaying
});

Subscribes to config-version changes (fired after each successful background poll). Returns an unsubscribe function. This is what the React hooks use to re-render on a flag change.

client.destroy()

client.destroy();

Stops background polling. Call it when tearing down the client.

The onEvaluation hook

const client = await Switchbox.create({
sdkKey: 'your-sdk-key',
onEvaluation: (flagKey, value, user) => {
// forward the exposure to your analytics
},
});

Fires after every enabled() and getValue() call with the flag key, the resolved value, and the user context you passed in. It is fire-and-forget: an exception inside your handler never breaks the flag check (it is reported through onError), and the hook carries no evaluation logic. Ready-made handlers for PostHog, Amplitude, Segment, and GA4 are in Measure in your own analytics.

Anonymous usage telemetry

The SDK reports anonymous aggregate usage — per-flag evaluation counts and value distribution, with no identity, no user context, and no cookies — which powers the dashboard's flag usage panel. On by default; pass telemetry: false to disable it. Exactly what is sent and shown is documented in Connection & usage.

Why evaluation is async

enabled() and getValue() return promises because rollout bucketing uses the browser's asynchronous Web Crypto digest. After the first fetch there's no network involved — the await resolves on the same tick — but the methods stay async to keep one hashing implementation across platforms.

Offline behaviour

If a fetch fails, the SDK keeps serving the last good config. If it has never fetched one, enabled() resolves to false and getValue() to your default. Errors are routed to onError rather than thrown.

Next