Why can't my browser SDK see a feature flag?

Last updated:

Because the flag is not marked client-side visible. Client SDK keys are public by design, so they only ever receive flags you have explicitly opted in. A server key sees every flag in the project, which is why the same key works from your backend and fails in the browser. The client SDK reports the flag as not found rather than raising.

A client SDK key ships to the browser. Anyone can read it. That constraint drives the whole design: a client key must never be able to pull down flags you did not intend to publish, along with the targeting rules attached to them.

So visibility is opt-in per flag. Until you tick Client-side visible, a client key receives nothing for that key, and the SDK synthesizes a flag-not-found locally because the flag is simply absent from its snapshot.

How to tell this is what you have

The signature is a flag that works from one runtime and not the other, with no error in either.

// Backend, server key: works
client.boolVariation('new-checkout', false); // -> true
// Browser, client key: returns the default
client.boolVariation('new-checkout', false); // -> false

If the reason string is available to you, flag-not-found from a client SDK means one of three things: the key does not exist, the client has not finished initializing, or the flag is not client-side visible. Rule out the first two and you have your answer.

The fix

Open the flag in the dashboard and enable client-side visibility. The change reaches connected clients over the existing stream within seconds. No redeploy.

Why this is worth keeping on

It is tempting to mark everything visible and move on. Consider what that publishes. Targeting rules travel with a flag, so a rule that serves a feature to plan == "enterprise" tells anyone reading your bundle that an enterprise plan exists and what unlocks it. Internal kill switches and pricing gates are the usual regrets.

If a flag would embarrass you in a public repository, keep it server-side.

Naming helps

Prefixing client-visible flags makes the boundary visible in code review. A key like web-new-checkout reads as public at the call site, which is exactly where someone is deciding whether to add a targeting rule to it.

Key handling and per-environment separation are covered in Environments, and the full reason table in the analytics integration guide.

Still stuck?

The docs cover every SDK, and the free Solo plan is enough to reproduce most of these locally.