Server SDK
Evaluate feature flags and experiments from your backend with @rendercontext/server. Use the same raw viewerId as the browser SDK so assignments and analytics join for signed-in users. By default the SDK polls config about once a minute and evaluates locally — exposures and custom events still go to the ingest API.
1. Credentials
In the console, open your project → Environments → edit an environment. Copy the public key and generate a server secret key (sk_live_…). Store the secret in your backend secrets manager — never ship it to the browser.
2. Install and init
npm install @rendercontext/server
import { createClient } from "@rendercontext/server";
const rc = createClient({
publicKey: process.env.RC_PUBLIC_KEY!,
secretKey: process.env.RC_SECRET_KEY!,
});3. Evaluate flags
Pass the raw app user id (same value as browser setViewerId). The SDK hashes it with your environment public key.
const { flags } = await rc.evaluate({
viewerId: user.id,
flagKeys: ["image_model"],
});
const model = flags.image_model === "v2" ? "v2" : "v1";Target with backend context
Pass cohort and attribute values derived from your authenticated backend session or database. This secret-keyed path trusts those values directly; a viewer-context token is only needed when sending attributes to the browser SDK. Unknown or archived cohorts are ignored.
const { flags } = await rc.evaluate({
viewerId: user.id,
flagKeys: ["new_checkout"],
context: {
cohorts: user.cohortKeys,
attributes: { plan: user.plan, role: user.role },
},
});4. Experiments and exposure
evaluate does not record experiment exposures. When the variant affects the response, call exposure explicitly (no browser exposureToken — the secret authenticates the request).
const { experiments } = await rc.evaluate({
viewerId: user.id,
experimentKeys: ["image_model_test"],
});
const assignment = experiments.image_model_test;
if (assignment) {
// …use assignment.variant…
await rc.exposure({
viewerId: user.id,
experimentKey: "image_model_test",
variant: assignment.variant,
});
}5. Track events
await rc.event({
viewerId: user.id,
name: "image_generated",
});Limitations
- Country targeting is not applied on server evaluate (no Cloudflare country on the request). Prefer flags/experiments without country rules for server-only decisions, or evaluate those in the browser.
- Flag/experiment config is polled in-process by default (60s). Pass
configPollIntervalMs: 0to skip background polling (evaluate still loads config when needed). If config cannot be fetched, evaluate throws. The browser SDK cannot poll full defs — it stays on the edge evaluate path. - Sensitive behaviour (billing, admin, costly models) must still be enforced on your server — flags are not an authorization boundary.
Related
- Feature flags (browser)
- Experiments (browser)
- Signing tokens (viewer context attributes)