How to Integrate Statsig with Your Headless CMS
Connect Statsig to your headless CMS so experiments, feature gates, and personalized content use the same structured copy your editors publish.
What is Statsig?
Statsig is a feature flagging, experimentation, and product analytics platform for product and engineering teams. It evaluates Feature Gates, Dynamic Configs, Experiments, Layers, and Autotune settings per user or account through server, client, and mobile SDKs. Teams use Statsig to control rollouts, run A/B tests, and measure exposure and event data in one workflow.
Why integrate Statsig with a headless CMS?
Personalization gets messy when experiment logic and content live in separate places. A growth team might define a Statsig experiment with variants A, B, and C, while editors update landing page headlines, CTAs, and hero images somewhere else. If someone copies the wrong CTA into a Dynamic Config, the experiment still runs, but the result is noisy because the content doesn’t match the test plan.
Connecting Statsig to a headless CMS solves that handoff. Editors publish structured variants, developers sync only the fields Statsig needs, and Statsig handles assignment, bucketing, and measurement. With Sanity, content in the Content Lake is typed JSON, so a GROQ query can pull a config name, variant keys, headlines, CTA labels, image URLs, and audience metadata without scraping HTML or parsing page blobs.
The alternative is usually manual and brittle. Someone exports copy into a spreadsheet, pastes it into Statsig, waits for a deploy, or asks an engineer to update a config file. Webhooks and Functions remove that lag. When content is published, the sync can run immediately, call the Statsig Console API, and keep the frontend experience tied to the exact content editors approved.
Architecture overview
A typical Sanity and Statsig integration starts with an experiment document in Sanity Studio. The schema includes fields like statsigConfigName, experimentKey, variants, audience notes, CTA copy, and references to shared content such as products, plans, or articles. When that document is published, a Sanity webhook fires with the document ID and mutation details. A webhook handler or Sanity Function receives the event, verifies the request, and uses @sanity/client to fetch the published document from the Content Lake. GROQ selects only the fields Statsig needs, including joined reference data such as image asset URLs or product slugs. The server-side handler then calls the Statsig Console API, for example PATCH https://statsigapi.net/console/v1/dynamic_configs/{configName}, using a Console API key stored as a server-side secret. The payload can update a Dynamic Config default value or experiment metadata with Sanity-authored variants. On the frontend, your app initializes the Statsig SDK, evaluates the experiment or Dynamic Config for the current user, and renders the matching Sanity content. Statsig handles allocation and exposure logging. Sanity remains the source for the content itself. There’s one important trade-off. Don’t sync drafts, personal data, or large content payloads into Statsig. Keep Statsig payloads small, usually variant keys, labels, IDs, and URLs, then fetch full content from Sanity when needed.
Common use cases
A/B test homepage messaging
Publish headline and CTA variants in Sanity, sync them to a Statsig Dynamic Config, and let Statsig assign users to each variant.
Gate content launches
Use Statsig Feature Gates to show a new pricing page, campaign module, or onboarding step only to beta accounts or a percentage rollout.
Personalize by account or audience
Send audience-safe variant keys from Sanity to Statsig, then render different content for free users, enterprise accounts, or trial users.
Measure content variant results
Connect Statsig exposure and event data to specific Sanity variant IDs so teams know which headline, CTA, or layout won.
Step-by-step integration
- 1
Set up Statsig keys and SDKs
Create or open a Statsig project, copy a Server Secret Key for SDK evaluation, copy a Console API key for config updates, and install the SDK you need, such as statsig-node on the server or @statsig/js-client in the browser.
- 2
Model experiment content in Sanity Studio
Create a schema for experiment content with fields such as statsigConfigName, experimentKey, variants, key, headline, ctaLabel, image, and targetPage. Keep variant keys stable, such as control, short_headline, and benefit_led.
- 3
Create a publish webhook
In Sanity, add a webhook that triggers on publish events for your experiment document type. Send the document ID and type to your webhook handler, Sanity Function, or middleware endpoint.
- 4
Fetch the published content with GROQ
In the handler, use @sanity/client with useCdn set to false so you read the latest published data. Use GROQ to select only fields Statsig should receive, such as variant keys, CTA labels, and image URLs.
- 5
Update Statsig through the Console API
Call the Statsig Console API with your Console API key and update the matching Dynamic Config or experiment metadata. Keep secrets server-side, and avoid sending draft content or user data.
- 6
Test assignment and rendering
Initialize the Statsig SDK in your app, evaluate the Dynamic Config or experiment for a test user, confirm exposure events appear in Statsig, and verify the rendered content matches the Sanity variant.
Code example
import {createClient} from '@sanity/client'
import {NextRequest, NextResponse} from 'next/server'
const sanity = createClient({
projectId: process.env.SANITY_PROJECT_ID!,
dataset: process.env.SANITY_DATASET!,
apiVersion: '2025-02-19',
token: process.env.SANITY_READ_TOKEN!,
useCdn: false,
})
export async function POST(req: NextRequest) {
if (req.headers.get('x-webhook-secret') !== process.env.SANITY_WEBHOOK_SECRET) {
return NextResponse.json({error: 'Unauthorized'}, {status: 401})
}
const {_id} = await req.json()
const id = _id.replace(/^drafts\./, '')
const experiment = await sanity.fetch(`*[_id == $id][0]{
"configName": statsigConfigName,
"variants": variants[]{key, headline, ctaLabel, "imageUrl": image.asset->url}
}`, {id})
if (!experiment?.configName) {
return NextResponse.json({ok: true, skipped: true})
}
const statsigRes = await fetch(
`https://statsigapi.net/console/v1/dynamic_configs/${encodeURIComponent(experiment.configName)}`,
{
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'STATSIG-API-KEY': process.env.STATSIG_CONSOLE_API_KEY!,
},
body: JSON.stringify({defaultValue: {variants: experiment.variants}}),
}
)
if (!statsigRes.ok) {
throw new Error(`Statsig update failed: ${await statsigRes.text()}`)
}
return NextResponse.json({ok: true})
}How Sanity + Statsig works
Build your Statsig integration on Sanity
Sanity gives you the structured content foundation, real-time event system, and flexible APIs to connect published content with Statsig experiments and feature gates.
Start building free →CMS approaches to Statsig
| Capability | Traditional CMS | Sanity |
|---|---|---|
| Experiment content structure | Often stores test copy inside pages, which makes variant reuse across apps hard. | Schema-as-code models experiments, variants, references, and approval fields as typed content. |
| Sync timing after publish | Usually needs manual copy-paste, scheduled exports, or deploy steps. | Webhooks and Functions can trigger Statsig updates on publish without a separate worker service. |
| Payload control for Statsig | Page HTML or large content blobs can include fields Statsig doesn’t need. | GROQ returns only the config name, variant keys, labels, URLs, and IDs required for the Statsig call. |
| Editor workflow for test variants | Editors may need developer help to create new experiment variants safely. | Sanity Studio can give editors custom fields, validation, previews, Comments, Tasks, and Content Releases for planned tests. |
| Multi-channel personalization | Experiments are often tied to one website template. | The same structured variant content can feed web, mobile, Statsig configs, and AI agents from the Content Lake. |
Keep building
Explore related integrations to complete your content stack.
Sanity + LaunchDarkly
Pair structured content with feature flags to control staged content launches and progressive rollouts.
Sanity + Optimizely
Run digital experiments with Sanity-authored variants while keeping approved content in one structured source.
Sanity + Dynamic Yield
Connect product, campaign, and editorial content to personalization campaigns across commerce experiences.