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: worksclient.boolVariation('new-checkout', false); // -> true
// Browser, client key: returns the defaultclient.boolVariation('new-checkout', false); // -> falseIf 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.
Related questions
Why is my feature flag returning the default value?
Six reasons a Featureflip flag falls back to the default you passed, ordered by how often each one is the real cause, with the check for each.
Can I use one SDK key for every environment?
No. The SDK key is what selects the environment, so sharing one collapses dev and production onto the same flag configuration.
Do I need a user ID to evaluate a feature flag?
Only for percentage rollouts. Without a stable identifier a server SDK serves the control variation, and the hosted endpoint spreads traffic with no stickiness.
Still stuck?
The docs cover every SDK, and the free Solo plan is enough to reproduce most of these locally.