LaunchDarkly JS Client SDK: Setup Guide for v4
The LaunchDarkly JavaScript client SDK is the browser SDK for evaluating feature flags in front-end code. As of October 2026 the current version is v4, published as @launchdarkly/js-client-sdk (4.11.2); the older launchdarkly-js-client-sdk package (v3.9) still works and is still documented, but new projects should use v4. You create a client with your environment's client-side ID and a context, call start(), wait for initialization, then read flags with variation().
This guide covers install, setup, flag changes, switching users, bootstrapping and the v3-to-v4 migration, with code checked against the official SDK docs.
Which package: launchdarkly/js-client-sdk v4 or v3?
| v4 (current) | v3 (legacy) | |
|---|---|---|
| npm package | @launchdarkly/js-client-sdk |
launchdarkly-js-client-sdk |
| Source repo | launchdarkly/js-core monorepo | launchdarkly/js-client-sdk |
| Create a client | createClient(id, context, options) then client.start() |
LDClient.initialize(id, context, options) |
| Wait for ready | waitForInitialization({ timeout: 5 }) resolves with a status |
waitForInitialization(5) rejects on failure |
| Flag change events | change gives (context, changedKeys) |
change included flag values |
If you search for "launchdarkly/js-client-sdk" you'll land on either; check your package.json to see which one your project uses. For React apps, LaunchDarkly also publishes launchdarkly-react-client-sdk, a wrapper with hooks and providers.
Before you start: two settings people miss
- Use the client-side ID, not the SDK key or the mobile key. Find it under your project's environments in LaunchDarkly. The client-side ID is safe to ship in browser code; the SDK key is not.
- Make each flag available to client-side SDKs. A flag that isn't marked this way returns your fallback value in the browser, with no error. Tick SDKs using Client-side ID when you create the flag or in the flag's sidebar, or enable it for every new flag on the project's Flag settings page (docs).
Install and initialize the SDK
Install the package:
npm install @launchdarkly/js-client-sdkCreate the client with a context, register listeners, then start it:
import { createClient } from '@launchdarkly/js-client-sdk'; const context = { kind: 'user', key: 'user-key-123', email: 'sandy@example.com', plan: 'pro', }; const client = createClient('YOUR_CLIENT_SIDE_ID', context); client.on('error', (err) => console.warn('LaunchDarkly error', err)); client.start();You must pass a valid context; without one, LaunchDarkly returns a 400 error. For logged-out visitors, use an anonymous context:
{ kind: 'user', anonymous: true }.Wait for flags before you render anything that depends on them:
const result = await client.waitForInitialization({ timeout: 5 }); if (result.status !== 'complete') { // 'failed' or 'timeout': variation() will return your fallback values console.warn('LaunchDarkly not ready:', result.status); }LaunchDarkly recommends a timeout of five seconds or less. In v4,
waitForInitializationnever rejects; it always resolves withstatusset tocomplete,failedortimeout.
Evaluate feature flags
Call variation(flagKey, fallback). The fallback is returned if the client isn't ready, the flag doesn't exist, or the flag isn't available to client-side SDKs.
const showNewCheckout = client.boolVariation('new-checkout', false);
const bannerText = client.stringVariation('promo-banner-text', '');
const maxItems = client.numberVariation('cart-max-items', 20);
if (showNewCheckout) {
renderNewCheckout();
} else {
renderOldCheckout();
}
The typed methods (boolVariation, stringVariation, numberVariation, jsonVariation) return the fallback if the flag's value has the wrong type. Use variationDetail() when you need to know why a value was served, for example while debugging targeting rules.
Each evaluation sends an analytics event so the flag's Insights and experiments get data. Avoid calling variation() for flags you don't use; in v4, allFlags() no longer sends events.
Listen for flag changes
By default the browser SDK doesn't stream updates. Subscribing to a change event opens a streaming connection, so flags update live without a page reload (flag change docs):
// One flag
client.on('change:new-checkout', () => {
const enabled = client.boolVariation('new-checkout', false);
toggleCheckout(enabled);
});
// Any flag
client.on('change', (context, changedKeys) => {
console.log('Flags changed:', changedKeys);
});
In v4, change callbacks don't receive flag values; call variation() inside the handler. Calling client.off('change:new-checkout', handler) removes the listener. To force streaming on or off, set streaming: true or false in the options.
Switch users with identify
When a visitor logs in, swap the anonymous context for the real one:
await client.identify({
kind: 'user',
key: user.id,
email: user.email,
plan: user.plan,
});
// variation() now returns values for the new context
Until identify finishes, variation() keeps returning values for the previous context.
Bootstrap flags to avoid a flicker
Without bootstrapping, the page renders before flags arrive, then switches. If you have a server, evaluate flags there and pass them to the browser. The bootstrapping docs show this v4 form:
// Server (Node.js server SDK): get client-side flags for the same context
const state = await ldServerClient.allFlagsState(context, { clientSideOnly: true });
const bootstrapData = JSON.stringify(state.toJSON());
// Browser
const client = createClient('YOUR_CLIENT_SIDE_ID', context);
client.start({ bootstrap: JSON.parse(bootstrapData) });
A bootstrapped client is ready immediately. v4 also caches flags in localStorage by default, so repeat visits start with the last known values.
Track events and shut down
client.track('checkout-completed', { cartId: 'c_42' }, 59.99); // custom metric
window.addEventListener('pagehide', () => {
client.flush(); // send buffered analytics events
});
await client.close(); // when your app tears down
Migrating from v3 (launchdarkly-js-client-sdk) to v4
The migration guide lists the breaking changes. The main ones:
- Replace the package
launchdarkly-js-client-sdkwith@launchdarkly/js-client-sdk. - Replace
initialize()withcreateClient()plusclient.start(). Register listeners beforestart()so you don't miss events. - Change
waitForInitialization(5)towaitForInitialization({ timeout: 5 })and checkresult.statusinstead of catching a rejection.waitUntilReady()is gone. - Move
bootstrapfrom the client options tostart()oridentify(). - Rename
baseUrl,streamUrlandeventsUrltobaseUri,streamUriandeventsUri. - Update
changehandlers to callvariation()instead of reading values from the event.
Upgrade to the latest v3 release first: anything removed in v4 shows up as a deprecation warning there.
Limits and costs
- Pricing: LaunchDarkly's Developer plan is free with 5 service connections and 1,000 client-side monthly active users; paid plans bill per service connection and per 1,000 client-side MAU (pricing, as of October 2026). Browser users count toward client-side MAU, so anonymous traffic adds up.
- Flag values are public: the browser receives the evaluated value of every client-side flag for the current context (not your targeting rules), so never put secrets in flag variations.
- Node.js and other servers need the server-side SDK (
@launchdarkly/node-server-sdk) with an SDK key, not this package.
If the MAU pricing doesn't fit, see free alternatives to LaunchDarkly or the LaunchDarkly listing on DevHunt. For other tools in your release pipeline, browse DevOps tools.
FAQ
What is the LaunchDarkly JS client SDK?
It's LaunchDarkly's SDK for evaluating feature flags in the browser. It downloads flag values for one context (a user, device or organization) using your client-side ID, and can stream updates live.
What's the difference between launchdarkly-js-client-sdk and @launchdarkly/js-client-sdk?
launchdarkly-js-client-sdk is the v3 package; @launchdarkly/js-client-sdk is v4, built on LaunchDarkly's shared js-core libraries. v4 changes initialization to createClient() plus start() and returns a status from waitForInitialization.
Why does variation() always return my fallback value?
The usual causes: the flag isn't marked available to client-side SDKs, you used the SDK key instead of the client-side ID, you're reading flags before initialization completes, or the flag key is misspelled.
Can I use the JS client SDK in Node.js?
No. It's for browsers. Use the Node.js server-side SDK on servers, and the React Native SDK for mobile apps.
Is LaunchDarkly free?
There's a free Developer plan with 5 service connections and 1,000 client-side MAU per month. Paid plans start with the Foundation tier and a 14-day trial.