How to Integrate Stytch with Your Headless CMS
Connect Stytch to your headless CMS so gated content, account rules, and member experiences stay in sync with your authentication layer.
What is Stytch?
Stytch is an authentication and user infrastructure platform for consumer and B2B applications. It provides APIs and SDKs for passkeys, magic links, OTPs, OAuth, SSO, MFA, session handling, organizations, and roles. Product and engineering teams use Stytch when they want to ship authentication flows without building credential storage, session logic, and account security from scratch.
Why integrate Stytch with a headless CMS?
Auth rules and content rules often drift apart. Your app may use Stytch to decide who a user is, while your content team controls pricing pages, customer portals, documentation, and member-only articles somewhere else. If those systems don't talk, engineers end up hard-coding access tiers, copying plan names into config files, or waiting for a nightly job to catch up.
Connecting Stytch to a headless CMS solves that gap for Auth & Identity use cases. A content editor can publish an access rule, a plan definition, or a gated route, and your integration can push the right identifiers into Stytch organization metadata, user metadata, or your own authorization service. The frontend then uses Stytch sessions to identify the user and uses structured content rules to decide what to show.
With Sanity, the content side is structured JSON in the Content Lake, not HTML pages that need parsing. GROQ selects only the fields Stytch needs, and webhooks can fire on publish, update, or delete events. The trade-off is that you still need to design your authorization model carefully. Stytch should handle identity and sessions, while Sanity should provide clear, typed content rules that your app enforces on the server.
Architecture overview
A typical flow starts in Sanity Studio, where an editor publishes an access rule document with fields such as stytchOrganizationId, plan, region, allowedContentTypes, gatedRoutes, and requiresMfa. The published document is written to the Content Lake as typed JSON. A Sanity webhook listens for publish events, for example _type == "accessRule" and not draft documents, then sends the document ID to a Sanity Function or webhook route. That server-side handler uses @sanity/client and GROQ to fetch the exact rule, including any referenced plan or product data. It then calls Stytch's server-side SDK. For a B2B app, the handler can call Stytch Organizations and update trusted_metadata on the matching organization. For a consumer app, the same pattern can update user trusted_metadata with client.users.update, or write the entitlement to your own authorization service after Stytch identifies the user. When an end user signs in, your frontend uses Stytch's JavaScript, React, or Next.js SDK to create and validate the session. Your app reads the user's Stytch session and organization context, checks the synced metadata or authorization record, and queries Sanity for the content that matches the user's allowed tiers. Stytch isn't the content delivery layer. It proves identity and carries trusted account context, while Sanity delivers the structured content.
Common use cases
Member-only content
Publish access tiers in Sanity and sync them to Stytch metadata so signed-in users see the right articles, videos, or reports.
B2B customer portals
Map Sanity customer portal sections to Stytch Organizations so each tenant gets docs, onboarding steps, and notices for its plan and region.
Passkey-first onboarding
Use Stytch for passkeys and sessions, while Sanity controls the onboarding copy, legal text, and plan-specific next steps.
Role-aware documentation
Sync role and plan rules from Sanity so admins, developers, finance users, and guests land on documentation that matches their account context.
Step-by-step integration
- 1
Set up Stytch
Create a Stytch project, choose Consumer or B2B, add your redirect URLs, and copy the project ID, secret, and public token. Install the server SDK with npm install stytch, and add the frontend SDK that fits your stack, such as @stytch/nextjs for Next.js.
- 2
Model access rules in Sanity Studio
Create a schema for accessRule with fields like stytchOrganizationId, plan, region, allowedContentTypes, gatedRoutes, and requiresMfa. Keep Stytch metadata small. Sync IDs, slugs, and booleans instead of full documents.
- 3
Create the publish trigger
Add a Sanity webhook or Function trigger for published accessRule documents. A common filter is _type == "accessRule" && !(_id in path("drafts.**")). Include a shared secret so random requests can't update Stytch.
- 4
Fetch the Sanity document with GROQ
In the handler, use @sanity/client with useCdn: false and a read token. Query only the fields Stytch needs, including joined plan or product references if your access rule points to other documents.
- 5
Call the Stytch API
For B2B apps, use Stytch's B2BClient and organizations.update to write trusted_metadata on the matching organization. For consumer apps, use client.users.update for user-level trusted_metadata, or update your own authorization service after Stytch validates the user.
- 6
Test the frontend and server checks
Sign in with Stytch, read the session and organization context, and request gated content through a server route. Test publish, update, delete, draft, and unauthorized states. Don't enforce access only in the browser.
Code example
import {createClient} from '@sanity/client';
import * as stytch from 'stytch';
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,
});
const stytchClient = new stytch.B2BClient({
project_id: process.env.STYTCH_PROJECT_ID!,
secret: process.env.STYTCH_SECRET!,
});
export async function POST(req: Request) {
const { _id } = await req.json();
const rule = await sanity.fetch(`*[_id == $id][0]{
stytchOrganizationId,
plan,
region,
allowedContentTypes,
"routes": gatedRoutes[].path,
requiresMfa
}`, { id: _id.replace(/^drafts\./, '') });
if (!rule?.stytchOrganizationId) {
return new Response('No Stytch organization mapped', { status: 202 });
}
await stytchClient.organizations.update({
organization_id: rule.stytchOrganizationId,
trusted_metadata: {
sanityPlan: rule.plan,
sanityRegion: rule.region,
allowedContentTypes: rule.allowedContentTypes ?? [],
gatedRoutes: rule.routes ?? [],
requiresMfa: Boolean(rule.requiresMfa),
syncedAt: new Date().toISOString(),
},
});
return Response.json({ ok: true });
}How Sanity + Stytch works
Build your Stytch integration on Sanity
Sanity's AI Content Operating System gives you the structured content foundation, real-time event system, and flexible APIs to connect Stytch with your authenticated experiences.
Start building free →CMS approaches to Stytch
| Capability | Traditional CMS | Sanity |
|---|---|---|
| Gated content rules | Access rules live as typed documents in the Content Lake, with references to plans, regions, products, and routes. | |
| Sync to Stytch on publish | Webhooks or Functions can trigger on specific content mutations and call Stytch from server-side code without polling. | |
| Field-level payload control | GROQ fetches only the Stytch payload, including joined references, in one query. | |
| Tenant-aware B2B content | Sanity Studio can expose editor-friendly fields for Stytch organization IDs, plan rules, regional access, and review tasks. | |
| Frontend enforcement | Your app can validate the Stytch session server-side, read synced account context, and query Sanity for only allowed content. | |
| AI-ready account experiences | Agent Context can give scoped, read-only access to structured content for production agents that also respect Stytch-authenticated user context. |
Keep building
Explore related integrations to complete your content stack.
Sanity + Auth0
Connect structured content with Auth0 identity, roles, and enterprise login flows for gated apps and portals.
Sanity + Clerk
Build signed-in product experiences where Clerk handles users and Sanity controls profile-driven content.
Sanity + WorkOS
Pair B2B auth, SSO, and directory sync from WorkOS with tenant-aware content modeled in Sanity.