How to Integrate Tolgee with Your Headless CMS
Connect Tolgee to your headless CMS so published content moves into translation workflows as structured keys, not copied text in spreadsheets.
What is Tolgee?
Tolgee is an open-source localization platform for translating app strings, product copy, and content across languages. Teams use Tolgee Cloud or self-host Tolgee to work with translation keys, machine translation, translation memory, screenshots, namespaces, and in-context editing through SDKs. It fits teams that want developer-friendly localization without handing every text update to engineers.
Why integrate Tolgee with a headless CMS?
Localization gets messy when your source content lives in one system, UI strings live in Git, and translators work from exported files. A Tolgee integration gives you one repeatable path: publish source content, create or update translation keys, let translators work in Tolgee, and ship localized experiences without copy-paste handoffs.
A headless CMS category tool can help here when content is structured. With Sanity, the AI Content Operating System, content in the Content Lake is typed JSON, so you can send Tolgee exactly the fields that need translation, such as product titles, feature labels, SEO descriptions, and CTA text. GROQ selects those fields, webhooks trigger when content is published, and Functions can run the sync logic without a separate worker.
The alternative is usually a weekly export: someone copies 300 product descriptions into a sheet, translators edit columns, and a developer imports the results. That can work for a small site, but it breaks down when you publish daily, rename fields, or need five locales updated before a campaign goes live. The trade-off is that Tolgee works best when you define stable key names and namespaces up front. If your content keys change every time a title changes, translators will lose history and translation memory value.
Architecture overview
A typical Sanity and Tolgee integration starts when an editor publishes content in Sanity Studio. A Sanity webhook fires on the publish event and sends a small payload, usually the document ID, type, and revision. A Sanity Function or webhook handler receives that payload, uses @sanity/client to fetch the current document from the Content Lake with GROQ, and projects only translatable fields. The sync layer then maps each field to a Tolgee key. For example, a Sanity product with _id "product.shoe-123" could become Tolgee keys like "product.shoe-123.title", "product.shoe-123.shortDescription", and "product.shoe-123.seoTitle" in a "sanity" namespace. The handler calls Tolgee's REST API with an X-API-Key header to create or update the source-language values in the Tolgee project. From there, translators work in Tolgee using its editor, machine translation, translation memory, and review states. Your frontend can read localized UI strings through the Tolgee SDK and combine them with localized Sanity content, or you can export translations from Tolgee into your build pipeline. The end user sees the right locale on the website, app, or agent response, while the source content stays structured in Sanity.
Common use cases
Localized product launches
Push new product names, short descriptions, and SEO copy from Sanity to Tolgee as soon as the launch content is published.
UI strings plus editorial copy
Keep app labels in Tolgee and sync selected Sanity fields into the same translation workflow for one release checklist.
In-context translation review
Use Tolgee SDKs to show translators where strings appear in the app while Sanity remains the source for structured content.
Locale readiness checks
Compare Tolgee translation states against Sanity publish plans before shipping a campaign in English, German, French, and Spanish.
Step-by-step integration
- 1
Set up Tolgee
Create a Tolgee Cloud project or self-host Tolgee, add your source language, add target languages, create an API key with project access, and note the project ID. For frontend apps, install the SDK you need, such as @tolgee/react, @tolgee/vue, or @tolgee/web.
- 2
Model translatable content in Sanity Studio
Define fields that should become translation keys, such as title, subtitle, seoDescription, and CTA labels. Keep non-translatable fields, such as price, SKU, inventory status, and internal notes, separate so your sync code doesn't send noise to Tolgee.
- 3
Create a publish trigger
Add a Sanity webhook that fires on create and update events for the document types you localize, such as product, landingPage, or article. Set the webhook payload to include the document ID and type, then point it to a Sanity Function, Next.js route, or small middleware service.
- 4
Fetch exactly what Tolgee needs
In the handler, use @sanity/client and GROQ to fetch only translatable fields. Include referenced content when needed, for example a product category title or reusable CTA document.
- 5
Create or update Tolgee keys
Map each Sanity field to a stable Tolgee key, call the Tolgee REST API with your API key, and send the source-language text into a namespace such as sanity. Use document IDs or slugs for key stability, not editable titles.
- 6
Test the localized frontend
Run through one document in two target languages. Publish in Sanity, confirm keys appear in Tolgee, translate one value, load the locale in your frontend, and check fallback behavior when a translation is missing.
Code example
import {createClient} from '@sanity/client';
import {NextRequest, NextResponse} from 'next/server';
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 tolgeeBase = process.env.TOLGEE_API_URL ?? 'https://app.tolgee.io';
async function upsertTolgeeKey(name: string, text: string) {
const res = await fetch(`${tolgeeBase}/v2/projects/${process.env.TOLGEE_PROJECT_ID}/keys/create`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.TOLGEE_API_KEY!,
},
body: JSON.stringify({
name,
namespace: 'sanity',
translations: {
en: {text, state: 'TRANSLATED'},
},
}),
});
if (!res.ok && res.status !== 409) {
throw new Error(`Tolgee key sync failed: ${res.status} ${await res.text()}`);
}
}
export async function POST(req: NextRequest) {
const {id} = await req.json();
const doc = await sanity.fetch(
`*[_id == $id][0]{_id, _type, title, seoDescription}`,
{id},
);
if (!doc) return NextResponse.json({skipped: true}, {status: 404});
const entries = {
[`${doc._type}.${doc._id}.title`]: doc.title,
[`${doc._type}.${doc._id}.seoDescription`]: doc.seoDescription,
};
for (const [key, value] of Object.entries(entries)) {
if (typeof value === 'string' && value.trim()) {
await upsertTolgeeKey(key, value);
}
}
return NextResponse.json({synced: Object.keys(entries).length});
}How Sanity + Tolgee works
Build your Tolgee integration on Sanity
Sanity gives you the structured content foundation, real-time event system, and flexible APIs to connect Tolgee to your localization workflow.
Start building free →CMS approaches to Tolgee
| Capability | Traditional CMS | Sanity |
|---|---|---|
| Source text quality for translation | Content is often mixed with layout markup, so translation exports may include HTML, shortcodes, or page-builder fragments. | The Content Lake stores typed JSON, and GROQ can return clean text fields and referenced values in one query. |
| Sync timing after publish | Teams often run scheduled exports or wait for plugins, which can delay translation work by hours or days. | Webhooks and Functions can send new or changed fields to Tolgee when content is published, updated, or deleted. |
| Field-level control | Exports can be page-based, which sends too much text and makes it harder to avoid internal fields. | GROQ can select exact fields, filter by locale readiness, and join references before the Tolgee API call. |
| Key stability | Keys are often generated from page paths or titles, so renames can create duplicate translation work. | Schema-as-code lets you build stable key rules from document IDs, slugs, field names, and content types. |
| Editorial workflow fit | Editors may need to export files, send them to translators, then import finished translations manually. | Sanity Studio can show source fields, sync status, review tasks, and release timing in a custom editorial interface. |
Keep building
Explore related integrations to complete your content stack.
Sanity + Lokalise
Send structured Sanity content to Lokalise for translation workflows, review steps, and multi-platform string delivery.
Sanity + Crowdin
Connect Sanity content models to Crowdin projects for translator collaboration, approval flows, and locale exports.
Sanity + Phrase
Use Sanity as the structured source for content and Phrase for translation jobs, terminology, and locale rollout.