How to Integrate Phrase with Your Headless CMS
Connect Phrase to your headless CMS so published source content becomes translation-ready keys, approved translations return to your content model, and every locale ships from the same structured source.
What is Phrase?
Phrase is a translation and localization platform for product, marketing, documentation, and engineering teams. It includes tools such as Phrase Strings and Phrase TMS for translation memory, terminology, machine translation, review workflows, and API-based localization pipelines. Teams use Phrase when they need repeatable translation workflows across websites, apps, help centers, and product UI.
Why integrate Phrase with a headless CMS?
A launch with 40 landing pages, 12 locales, and 3 review steps gets messy fast when source content lives in one place and translation work happens somewhere else. Editors export copy, translators work from spreadsheets or ZIP files, developers copy translated text back into fields, and nobody is fully sure which locale is current.
Connecting Phrase to a headless CMS changes that handoff. Source fields can be sent to Phrase as structured translation keys, translators can work with Phrase translation memory and terminology, and approved translations can come back into locale-specific fields or documents. With Sanity's AI Content Operating System, content in the Content Lake is structured JSON, so you can send Phrase exactly the fields that need translation instead of scraping HTML or parsing page blobs.
The trade-off is that you need to decide your localization model up front. Field-level locales, document-level locales, and Phrase key naming all affect your sync logic. Once that's mapped, real-time webhooks and Functions let you trigger translation syncs on publish events instead of running nightly exports or asking editors to remember another manual step.
Architecture overview
A typical Sanity and Phrase integration starts when an editor publishes source content in Sanity Studio. A Sanity webhook, filtered to specific document types such as article, product, or landingPage, fires on the publish event. The webhook can call a Sanity Function or your own endpoint. That handler uses @sanity/client to fetch the published document from the Content Lake with a GROQ projection. For example, it can select title, excerpt, body blocks, SEO fields, and referenced category names while skipping internal notes, analytics IDs, and non-translatable values. The handler then converts those fields into a Phrase-compatible JSON payload, usually with stable keys such as article.my-post.title or product.sku-123.description. Next, the handler calls the Phrase Strings API. For many workflows, that means POST /v2/projects/{project_id}/uploads with multipart form data, including file, file_format, locale_id, update_translations, and tags. Phrase creates or updates translation keys in the project, applies translation memory and terminology rules during translation, and lets localization teams review target locales in their normal Phrase workflow. When translations are ready, you have two common options. Phrase can call back to your endpoint with a webhook, then your code downloads the translated file from Phrase and patches localized fields in Sanity. Or your frontend can use a scheduled sync that writes approved translations into the Content Lake before release. The end user never sees the handoff. They request /de/products/running-shoe, your frontend queries the localized Sanity document, and the page renders the approved German content.
Common use cases
Multi-locale product launches
Send product names, descriptions, feature bullets, and SEO copy to Phrase when a source product is published, then write approved translations back before launch.
Phrase key sync from structured content
Map Sanity fields to stable Phrase Strings keys so translators work with context instead of loose spreadsheet rows.
Translation QA before release
Use Phrase review, terminology, and quality checks before localized landing pages are included in a Sanity Content Release.
Localized documentation updates
Trigger Phrase uploads only when source documentation fields change, so translators don't rework unchanged code samples, metadata, or references.
Step-by-step integration
- 1
Set up Phrase
Create a Phrase project, add your source locale and target locales, create an API access token, and note the project ID and source locale ID. Install the packages you'll need with npm install @sanity/client phrase-js, or call the Phrase REST API directly from your webhook handler.
- 2
Model localized content in Sanity Studio
Choose field-level localization, document-level localization, or a hybrid model. Add stable identifiers such as slug.current, sku, or translationKey so your Phrase keys don't change when editors rewrite titles.
- 3
Create the trigger
Add a Sanity webhook filtered to publish events for the document types you want to translate. For server-side processing without a separate service, point the webhook at a Sanity Function.
- 4
Fetch only translatable fields with GROQ
Use a GROQ projection to select fields Phrase needs, including referenced labels when useful. Skip fields such as image asset IDs, feature flags, internal notes, and timestamps.
- 5
Push source content to Phrase
Convert the GROQ result into simple JSON or another Phrase-supported file format, then call the Phrase Uploads API with file_format, locale_id, update_translations, and tags like sanity or product.
- 6
Test the frontend path
Publish one source document, confirm the upload appears in Phrase, complete one target locale, sync the approved translation back to Sanity, and query the localized content in your frontend by locale.
How Sanity + Phrase works
Build your Phrase integration on Sanity
Sanity gives you the structured content foundation, real-time event system, and flexible APIs to connect Phrase with your localization workflow.
Start building free βCMS approaches to Phrase
| Capability | Traditional CMS | Sanity |
|---|---|---|
| Source content handoff to Phrase | Often exports whole pages or HTML, so translators may receive layout markup mixed with copy. | GROQ projects typed fields from the Content Lake into stable Phrase keys, including referenced content when needed. |
| Sync timing | Translation exports are often manual or scheduled, which can miss late edits before launch. | Webhooks and Functions can run the Phrase upload when specific document types are published. |
| Locale modeling | Locale structure is usually tied to pages, which can make field reuse across channels harder. | Schema-as-code lets you model field-level locales, document-level locales, or both, then build the Sanity Studio UI editors need. |
| Translator context | Context may be limited to exported page titles, screenshots, or notes added by hand. | GROQ can send surrounding fields, reference labels, slugs, and content type tags to Phrase in one payload. |
| Publishing approved translations | Editors often paste translated copy back into pages, which creates room for copy errors. | Phrase callbacks can patch localized fields, and Content Releases can group translated updates for review before publish. |
Keep building
Explore related integrations to complete your content stack.
Sanity + Lokalise
Connect structured Sanity content with Lokalise projects for app, website, and product localization workflows.
Sanity + Crowdin
Send source fields from Sanity to Crowdin and sync reviewed translations back into locale-specific content.
Sanity + Smartling
Use Sanity as the structured source for Smartling translation jobs across enterprise websites and documentation.