How to Integrate Swell with Your Headless CMS
Sync product storytelling, buying guides, and merchandising content from structured content into Swell so commerce teams can publish faster without copying product data by hand.
What is Swell?
Swell is an API-first commerce platform for brands that need custom storefronts, flexible product models, subscriptions, B2B pricing, carts, checkout, and order workflows. Teams use Swell when they want commerce APIs without being locked into a fixed storefront system. Its core role is handling commerce data and transactions, while your content layer handles the editorial, merchandising, and multi-channel experience around those products.
Why integrate Swell with a headless CMS?
Commerce teams usually hit the same wall: product data lives in Swell, but the story around the product lives somewhere else. A product detail page may need specs, SEO copy, comparison tables, care instructions, collection narratives, ingredient callouts, and localized buying guides. If that content is copied into Swell by hand, every launch creates duplicate work and a higher chance that the storefront, email campaign, and product feed disagree.
Architecture overview
A typical Sanity and Swell integration starts when an editor publishes a product content document in Sanity Studio. A Sanity webhook fires on the publish event, or a Sanity Function runs directly on the content mutation. The handler receives the changed document ID, uses @sanity/client to query the Content Lake with GROQ, and selects the exact fields Swell needs, such as title, slug, SEO description, product badges, image URLs, related category references, and a stored Swell product ID. The handler then calls Swell's Admin API through the swell-node SDK, usually with swell.put('/products/{id}', payload) for an existing product or swell.post('/products', payload) for a new one. Swell updates the commerce record, and the storefront reads from Swell for transactional product data while also querying Sanity for richer content. The end user sees one product experience, even though pricing, checkout, and editorial content are handled by the systems best suited for each job.
Common use cases
Merchandised product detail pages
Publish editorial product copy, badges, comparison modules, and care notes from Sanity while Swell handles variants, prices, carts, and checkout.
Catalog enrichment
Add buying guides, ingredient details, sizing notes, and SEO fields to Swell products without asking commerce admins to edit long-form content.
Localized commerce content
Keep Swell product records stable while Sanity supplies market-specific descriptions, campaigns, and landing page modules for each locale.
Shopping agents with product context
Use Agent Context to let AI shopping agents read structured product education, FAQs, and comparison data alongside Swell commerce data.
Step-by-step integration
- 1
Set up Swell and get API credentials
Create a Swell store, add at least one product or product type, and copy your store ID plus a secret API key from the Swell dashboard. Install the Admin API client with npm install swell-node.
- 2
Model product content in Sanity Studio
Create a product content schema with fields like title, slug, swellProductId, shortDescription, seoTitle, seoDescription, badges, productImages, and references to categories or buying guides. Keep Swell-owned fields, such as price, SKU, and inventory, out of the editorial schema unless you have a specific sync rule.
- 3
Query only the fields Swell needs
Write a GROQ projection that returns the published product content, resolves image asset URLs, and joins referenced category slugs. This keeps the Swell update payload small and predictable.
- 4
Create the sync mechanism
Use a Sanity Function for server-side sync logic triggered by content mutations, or create a webhook listener in your app. Filter the trigger to product content publish events so draft edits don't update Swell.
- 5
Call Swell's Admin API
Initialize swell-node with your store ID and secret key, map Sanity fields to Swell product fields, and call swell.put('/products/{id}', payload) for updates. If your flow creates products from Sanity, call swell.post('/products', payload) and write the returned Swell ID back to Sanity.
- 6
Test the storefront experience
Publish a test product in Sanity Studio, confirm the Swell product record updates, and check your frontend. A common pattern is to fetch price, variants, and cart state from Swell, then fetch editorial modules, SEO fields, and content references from Sanity.
Code example
import {createClient} from '@sanity/client'
import swell from 'swell-node'
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,
})
swell.init(process.env.SWELL_STORE_ID!, process.env.SWELL_SECRET_KEY!)
export async function POST(req: Request) {
const body = await req.json()
const id = body._id?.replace('drafts.', '')
const product = await sanity.fetch(`
*[_type == "product" && _id == $id][0]{
title,
"slug": slug.current,
swellProductId,
shortDescription,
seoTitle,
seoDescription,
"images": images[]{"file": asset->url, alt},
"categories": categories[]->{"slug": slug.current}
}
`, {id})
if (!product?.swellProductId) {
return Response.json({skipped: true, reason: 'Missing swellProductId'})
}
await swell.put(`/products/${product.swellProductId}`, {
name: product.title,
slug: product.slug,
description: product.shortDescription,
meta_title: product.seoTitle,
meta_description: product.seoDescription,
images: product.images,
content: {
category_slugs: product.categories?.map((c: any) => c.slug) || []
}
})
return Response.json({ok: true})
}How Sanity + Swell works
Build your Swell integration on Sanity
Sanity's AI Content Operating System gives you the structured content foundation, real-time event system, and flexible APIs to connect editorial product content with Swell commerce workflows.
Start building free →CMS approaches to Swell
| Capability | Traditional CMS | Sanity |
|---|---|---|
| Product content modeling | Product storytelling often lives inside pages, which makes reuse across Swell, storefronts, and campaigns harder. | Schema-as-code lets you model product stories, badges, comparison blocks, localized fields, and Swell IDs as typed content. |
| Sync on publish | Updates often depend on manual exports, plugins, or scheduled jobs that can lag behind product launches. | GROQ-filtered webhooks and Functions can trigger a Swell update when specific product content changes. |
| Field-level API control | APIs may return page-shaped content, which means the integration has to remove fields Swell doesn't need. | GROQ can project Swell-ready payloads with joined references, image URLs, and localized fields in one query. |
| Commerce ownership boundaries | Editors may end up changing commerce fields and editorial fields in the same screen, increasing risk. | Sanity Studio can show editorial teams only the fields they should own, while Swell remains the source for SKU, price, inventory behavior, and checkout. |
| Multi-channel delivery | Content is usually shaped for the website first, then adapted for other channels later. | The same structured product content can feed web, mobile, Swell enrichment, email, and production AI agents through Agent Context. |
Keep building
Explore related integrations to complete your content stack.
Sanity + Shopify
Pair structured product content with Shopify commerce data for custom storefronts, campaigns, and localized product pages.
Sanity + Stripe
Connect pricing, subscription, and payment flows with structured plan pages, FAQs, and onboarding content.
Sanity + Medusa
Build custom commerce experiences where Medusa handles commerce logic and Sanity structures the content around it.