Why can't my browser SDK see a feature flag?
Last updated:
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 flag resolves from your backend and comes back empty in the browser. The client SDK reports it as not found rather than raising.
A client SDK key ships to the browser, where anyone can read it. Everything about the design follows from that one constraint, because a client key must never be able to pull down flags you did not intend to publish, along with whatever targeting rules are 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 narrows things down usefully. The key might not exist, the client might still be initializing, or the flag is not client-side visible. Rule out the first two and you have your answer. The analytics integration guide carries the full reason table.
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. If you are unsure which kind of key your process is holding, Environments covers how the two divide.
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.
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.