Auth & Identity8 min read

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.

Published April 29, 2026
01Overview

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.


02The case for integration

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.


03Architecture

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.


04Use cases

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.


05Implementation

Step-by-step integration

  1. 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. 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. 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. 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. 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. 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.


06Code

Code example

typescriptapp/api/sanity-stytch/route.ts
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 });
}

07Why Sanity

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 →

08Comparison

CMS approaches to Stytch

CapabilityTraditional CMSSanity
Gated content rulesAccess rules live as typed documents in the Content Lake, with references to plans, regions, products, and routes.
Sync to Stytch on publishWebhooks or Functions can trigger on specific content mutations and call Stytch from server-side code without polling.
Field-level payload controlGROQ fetches only the Stytch payload, including joined references, in one query.
Tenant-aware B2B contentSanity Studio can expose editor-friendly fields for Stytch organization IDs, plan rules, regional access, and review tasks.
Frontend enforcementYour app can validate the Stytch session server-side, read synced account context, and query Sanity for only allowed content.
AI-ready account experiencesAgent Context can give scoped, read-only access to structured content for production agents that also respect Stytch-authenticated user context.

09Next steps

Keep building

Explore related integrations to complete your content stack.

Ready to try Sanity?

See how Sanity's Content Operating System powers integrations with Stytch and 200+ other tools.