How to Integrate Clerk with Your Headless CMS
Connect Clerk to your headless CMS so user identity, memberships, and gated content rules stay in sync the moment content changes.
What is Clerk?
Clerk is an authentication and user management platform for React, Next.js, Remix, Expo, and other application frameworks. It provides sign-up, sign-in, session management, organizations, user profiles, MFA, webhooks, and SDKs for frontend and backend code. Product teams use Clerk when they want hosted auth flows plus developer control over user metadata, roles, and organization-based access.
Why integrate Clerk with a headless CMS?
Auth rarely lives in one place. Your app may use Clerk for identity, while your editorial team defines pricing pages, member-only articles, course access, account onboarding copy, or organization-specific content in a headless CMS. If those systems donโt talk, developers end up hard-coding access rules, editors wait on deploys, and support teams manually fix mismatched user permissions.
Architecture overview
A typical Sanity and Clerk integration starts with structured documents in the Content Lake, such as plans, entitlements, courses, onboarding steps, or organization-specific resources. When an editor publishes or updates one of those documents in Sanity Studio, a webhook triggers immediately. The webhook can call your API route, or a Sanity Function can run the server-side sync without separate infrastructure. The handler receives the mutation payload, uses @sanity/client and GROQ to fetch exactly the fields Clerk needs, such as clerkUserId, clerkOrganizationId, plan, role, and allowed course slugs, then calls Clerkโs Backend SDK. For a user-based flow, the handler calls clerkClient.users.updateUserMetadata(userId, { publicMetadata }). For a team-based flow, it can update organization metadata instead. The end user signs in through Clerk, your frontend reads the session claims, and your app uses those claims to decide which Sanity content to query and render.
Common use cases
Member-only content
Publish gated articles, videos, or lessons in Sanity, then sync compact access flags to Clerk user metadata.
Organization-based portals
Map Sanity documents to Clerk organizations so each customer account sees the right onboarding steps, docs, and resources.
Course and cohort access
Use Sanity to model courses and cohorts, then update Clerk metadata with allowed course slugs when access changes.
Personalized onboarding
Let editors update onboarding content in Sanity while Clerk identifies the signed-in user, role, and workspace.
Step-by-step integration
- 1
Set up Clerk
Create a Clerk application, choose your sign-in methods, copy CLERK_SECRET_KEY from the Clerk dashboard, and install the SDKs you need. For a Next.js app, that usually means @clerk/nextjs for the frontend and @clerk/backend for server-side updates.
- 2
Model access content in Sanity Studio
Create schemas for the content that affects access. For example, an entitlement document might include clerkUserId, clerkOrganizationId, plan, role, and references to allowed course documents. Keep the fields typed and small enough to map cleanly into Clerk metadata.
- 3
Create a Sanity webhook or Function
Trigger on create, update, and publish events for entitlement, plan, course, or organization content. Use a GROQ filter so the integration only runs for documents that affect identity or access, not every content edit.
- 4
Fetch the exact fields Clerk needs
Inside the handler, use @sanity/client with a GROQ projection to pull only IDs, slugs, plan names, roles, and other compact access data. Donโt send rich text, images, or full page content to Clerk metadata.
- 5
Update Clerk through the Backend SDK
Use createClerkClient from @clerk/backend and call users.updateUserMetadata for user-level access or organizations.updateOrganizationMetadata for workspace-level access. Store small public metadata when the frontend needs to read it from session claims, and private metadata when only backend code should use it.
- 6
Test the signed-in experience
Publish a test entitlement in Sanity Studio, confirm the webhook runs, inspect the user or organization in Clerk, then sign in and verify that your app shows the correct content. Also test deletion or downgrade paths, because stale access is the bug users will notice first.
Code example
import {createClient} from '@sanity/client'
import {createClerkClient} from '@clerk/backend'
const sanity = createClient({
projectId: process.env.SANITY_PROJECT_ID!,
dataset: process.env.SANITY_DATASET!,
apiVersion: '2025-01-01',
token: process.env.SANITY_READ_TOKEN!,
useCdn: false,
})
const clerk = createClerkClient({secretKey: process.env.CLERK_SECRET_KEY!})
export async function POST(req: Request) {
const {documentId} = await req.json()
const entitlement = await sanity.fetch(
`*[_id == $id][0]{
clerkUserId,
plan,
role,
"courseSlugs": courses[]->slug.current
}`,
{id: documentId}
)
if (!entitlement?.clerkUserId) {
return Response.json({skipped: true})
}
await clerk.users.updateUserMetadata(entitlement.clerkUserId, {
publicMetadata: {
plan: entitlement.plan,
role: entitlement.role,
courseSlugs: entitlement.courseSlugs ?? [],
},
})
return Response.json({synced: true})
}How Sanity + Clerk works
Build your Clerk integration on Sanity
Use Sanityโs structured content foundation, real-time event system, GROQ queries, and flexible APIs to connect Clerk identity with the content your users are allowed to see.
Start building free โCMS approaches to Clerk
| Capability | Traditional CMS | Sanity |
|---|---|---|
| Access rules as content | Models plans, roles, organizations, courses, and entitlements as structured documents with references that developers can version as code. | |
| Sync to Clerk on publish | Webhooks trigger on filtered content events, and Functions can run the server-side Clerk sync without a separate service. | |
| Field-level control for metadata | GROQ can fetch a compact projection in one request, including referenced slugs, IDs, and labels that fit Clerk metadata. | |
| Personalized frontend delivery | Your app can read Clerk session claims, query Sanity for matching structured content, and render the same content across web and mobile. | |
| AI agent access to gated knowledge | Agent Context gives production AI agents read-only, scoped access to structured content, while Clerk continues to handle user identity in your app. |
Keep building
Explore related integrations to complete your content stack.
Sanity + Auth0
Connect structured content with Auth0 tenants, roles, and user metadata for enterprise sign-in flows.
Sanity + Firebase Auth
Pair Firebase Auth user sessions with Sanity content for mobile apps, prototypes, and user-specific experiences.
Sanity + WorkOS
Use WorkOS for SSO and directory sync while Sanity structures customer-specific onboarding, docs, and portal content.