How to Integrate n8n with Your Headless CMS
Connect n8n to structured content so a publish event can update CRMs, notify Slack, translate fields, refresh search indexes, or start approval workflows in seconds.
What is n8n?
n8n is a workflow automation platform used by operations, engineering, marketing, and data teams to connect apps, APIs, and internal systems. It supports visual workflows, custom JavaScript, self-hosting, n8n Cloud, hundreds of app nodes, Webhook triggers, and HTTP Request nodes for services without a prebuilt connector. Teams choose n8n when they need more control than simple if-this-then-that automation, especially for multi-step flows with branching, retries, and custom API calls.
Why integrate n8n with a headless CMS?
Content rarely stops at the website. A product launch might need to update a search index, create a campaign task in Asana, post to Slack, send localized copy to a translation service, and notify a sales team when a partner page goes live. If those steps live in spreadsheets, chat threads, and manual checklists, publishing becomes slow and error-prone.
Architecture overview
A common setup starts in Sanity Studio, where editors publish a document such as a product, article, landing page, or release note. That mutation is written to the Content Lake. A Sanity webhook, filtered with GROQ, triggers only for the document types and events you care about. The webhook calls a small handler, or a Sanity Function, with the document ID. The handler uses @sanity/client to fetch the full document with a GROQ projection, including referenced data such as author names, category slugs, product SKUs, and locale metadata. The handler then sends a POST request to an n8n Webhook Trigger production URL, for example https://your-workspace.app.n8n.cloud/webhook/sanity-publish, with a JSON payload that matches the workflow contract. Inside n8n, the Webhook node passes the payload to nodes such as IF, Switch, HTTP Request, Slack, Google Sheets, HubSpot, Airtable, Jira, or OpenAI. The final result might be a customer-facing search update, a CRM activity, a localization job, a support article notification, or an internal approval task.
Common use cases
Publish-to-Slack release alerts
When a release note is published in Sanity, n8n formats the title, version, changelog URL, and audience, then posts it to the right Slack channels.
Localization handoff workflows
A Sanity publish event sends source fields to n8n, which creates translation tasks, waits for completion, and writes translated drafts back through the Sanity API.
Search index updates
When product or documentation content changes, n8n receives a compact GROQ-shaped payload and updates Algolia, Meilisearch, Elasticsearch, or a custom index.
CRM and campaign sync
Publishing a partner page, webinar, or case study can trigger n8n to update HubSpot, Salesforce, Airtable, or campaign planning boards with approved content data.
Step-by-step integration
- 1
Set up n8n
Create an n8n Cloud workspace or start a self-hosted instance. Build a workflow with a Webhook Trigger node, set the method to POST, choose a path such as sanity-publish, and copy the Production URL after activating the workflow. If you want to create or inspect workflows programmatically, create an n8n API key in Settings, then call the REST API with the X-N8N-API-KEY header. For webhook-triggered content events, you usually don't need an n8n SDK. Install the code packages for your handler with npm install @sanity/client.
- 2
Model the content in Sanity Studio
Define the fields n8n needs as schema fields, not rich text blobs. For a product launch workflow, that might include title, slug, sku, launchDate, locale, status, relatedProducts, heroImage, and notificationChannels. Because the schema is code, you can version changes alongside the integration.
- 3
Create a GROQ-shaped webhook
In Sanity, create a webhook filtered to the content events you want, such as _type == "product" && defined(slug.current). Send the document ID and type to your handler. Keep the webhook payload small, then fetch the full projection server-side so secrets stay out of the browser.
- 4
Add a handler or Sanity Function
Use a Sanity Function for server-side logic triggered by content mutations, or use your own endpoint on Vercel, Netlify, AWS Lambda, or a small Node service. The handler should verify the request, fetch the document from the Content Lake with GROQ, transform it into the payload n8n expects, and POST it to the n8n Webhook Trigger URL.
- 5
Build the n8n workflow
Connect the Webhook node to the actions you need. Use Set nodes to map fields, IF or Switch nodes for locale or content type branching, HTTP Request nodes for APIs without native nodes, and error workflows for retries or alerts. Add a header auth credential to the Webhook node if you want the handler to send a shared secret.
- 6
Test end to end
Publish a draft in a staging dataset first. Check the Sanity webhook delivery log, your handler logs, and the n8n execution view. Confirm that deletes, unpublishes, draft changes, and duplicate retries behave the way your team expects before switching the workflow to production content.
Code example
import {createClient} from '@sanity/client';
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 default async function handler(req: any, res: any) {
if (req.method !== 'POST') return res.status(405).end();
const { _id } = req.body;
if (!_id) return res.status(400).json({ error: 'Missing document _id' });
const doc = await sanity.fetch(`
*[_id == $id][0]{
_id,
_type,
title,
"slug": slug.current,
locale,
"author": author->name,
"categories": categories[]->slug.current
}
`, { id: _id });
if (!doc) return res.status(404).json({ error: 'Document not found' });
const response = await fetch(process.env.N8N_WEBHOOK_URL!, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.N8N_WEBHOOK_SECRET}`
},
body: JSON.stringify({ event: 'sanity.publish', document: doc })
});
if (!response.ok) {
const text = await response.text();
return res.status(502).json({ error: 'n8n webhook failed', detail: text });
}
return res.status(200).json({ ok: true });
}How Sanity + n8n works
Build your n8n integration on Sanity
Sanity gives you the structured content foundation, real-time event system, GROQ queries, and flexible APIs you need to connect content operations with n8n workflows.
Start building free โCMS approaches to n8n
| Capability | Traditional CMS | Sanity |
|---|---|---|
| Workflow trigger quality | Often depends on plugin events or scheduled exports, which can miss field-level context. | GROQ-filtered webhooks trigger on specific mutations, document types, and publish events. |
| Payload structure for n8n | Content often arrives as rendered HTML, page fields, or plugin-specific formats. | Content Lake stores typed JSON, and GROQ can join references into one workflow-ready payload. |
| Server-side sync logic | Custom sync code often lives in plugins or external cron jobs. | Functions can run server-side logic on content mutations, with 500K invocations per month included. |
| Schema change control | Field changes can happen through admin screens, which makes integration contracts harder to review. | Schema-as-code lets teams review field changes before they affect n8n mappings. |
| Multi-destination delivery | Workflows often start from pages, so reuse across web, apps, and automation takes extra mapping. | One structured source can feed web, mobile, n8n workflows, Agent API jobs, and Agent Context. |
Keep building
Explore related integrations to complete your content stack.
Sanity + Zapier
Send Sanity publish events to common business apps when your team wants simple no-code automations.
Sanity + Make (Integromat)
Build visual content workflows with routers, scheduled runs, and app connectors for marketing and operations teams.
Sanity + Pipedream
Run developer-focused workflows that combine Sanity webhooks, Node.js or Python steps, and API calls.