React
Flags in the browser, bootstrapped for the first paint and updating live.
A page whose flags change without a reload, and no flash of the wrong branch.
- A client-side ID from Settings → Project
Flags in the browser, updating on an open page without a reload.
npm install @varia-bly/react
Use the client-side ID
import { VariablyProvider, useFlags } from '@varia-bly/react';
export function App({ children, bootstrappedFlags }) {
return (
<VariablyProvider
clientSideId={process.env.NEXT_PUBLIC_VARIABLY_CLIENT_ID}
options={{ baseUri: process.env.NEXT_PUBLIC_VARIABLY_BASE_URL }}
flags={bootstrappedFlags}
>
{children}
</VariablyProvider>
);
}
Not the API key. This runs where anyone can read the bundle. The client-side ID is publishable and reaches flag evaluation only; the API key also reaches prompts, dynamic configs and LLM execution. Find it under Settings → Project.
With a client-side ID the provider evaluates on mount and holds a socket open, so a flag toggled in the dashboard reaches this page in about a second.
Reading flags
function Checkout() {
const { checkoutRedesign } = useFlags();
// Three states, and they differ. undefined means "not resolved yet"; treating it as
// false renders the off branch while values are still loading.
if (checkoutRedesign === undefined) return <Spinner />;
return checkoutRedesign ? <NewCheckout /> : <CurrentCheckout />;
}
Bootstrap, so the first paint is right
flags seeds the provider with values your server already resolved. Without it the first render
happens before the browser has evaluated, and anything reading a flag flashes through undefined.
Resolve with the Node SDK on the server, pass the set as a page prop, and hand it to the provider. On a server-rendered page this is what stops the wrong branch appearing for a moment.
Per-user evaluation
useIdentify re-evaluates when the context changes — after a login, say:
useIdentify(user ? { key: user.id, custom: { plan: user.plan } } : null);
Also available: useVariablyClient() for the client itself, and withVariably(config) if you would
rather wrap a component than nest a provider.
Without a credential
Given no clientSideId, the provider is bootstrap-only: it serves the flags handed to it and never
calls variA/Bly. That suits a deployment whose key is server-side only — the server evaluates, passes
the result down, and nothing reaches the browser. You lose live updates, not correctness.
A flag reading undefined here but fine on the server
The browser sees only gates available to client-side SDKs. Open the gate and check that Hide from client-side SDKs is unticked. A hidden flag is absent from the browser's set, which is indistinguishable from one that does not exist — deliberately, so a public credential cannot be used to list your flag names.