Platform
PricingSign inBook a demo
← All articles
PersonalizationJuly 14, 2026

Headless CMS Personalization: How to Personalize Content in a Composable Stack

P
Personyze TeamPersonalization experts
Headless CMS Personalization: How to Personalize Content in a Composable Stack

Headless and composable stacks split the content (an API-first CMS) from the front end that renders it. That’s great for flexibility — one content source feeding a website, an app, and the edge — but it complicates personalization, which used to rely on a single page and a script tag swapping elements in the browser.

In a headless setup, personalization has to become a decision layer: something that decides who sees what for a given slot, and hands that decision to whatever front end is doing the rendering. Here’s a practical architecture for headless CMS personalization with Personyze — the building blocks, two ways to integrate, and the questions to settle before you build.

Why headless changes personalization

A traditional CMS renders the page and a personalization script rewrites the DOM after load. Headless breaks that model: the CMS is just a content API, and your front end — Next.js, Nuxt, a mobile app, an edge function — fetches content and renders it. There is no single page to inject into.

So personalization splits into three jobs: define audiences (who), decide the content or variant for this visitor and slot (what), and render it wherever your front end lives. Personyze handles the first two and hands the decision to your stack — on the server or in the browser.

The building blocks: audiences, placements, decisions

Audiences define who. The easiest path is to embed the Personyze Audience Builder in an iframe inside your own UI: editors define rules using your customer and account fields, and Personyze returns a compiled audience id/definition. You get a full rules engine without rebuilding audience UI or logic yourself. Audiences can combine on-site behavior, CRM data, and first-party signals.

Placements mark where personalized content goes. Each is a placement_id — you can create a universal placement or one scoped strictly to a given page or URL.

Decisions tie it together: given a visitor_id and the placement_ids on a page, Personyze resolves the visitor’s audience and returns the content_id and variant to show. The same decision flow powers A/B tests, so testing is not a separate system.

Two ways to wire it up

There’s no single “right” integration — it comes down mostly to whether you render on the server or in the browser.

Three integration options for headless personalization
Server to server client side or Personyze led with CMS content import

Option A — Server-to-server (recommended)

Your CMS/back end stores the content_id, the placement_id (universal or page-scoped), and the audience id/definition. On each request, your server reports the visitor_id plus the placement_ids on the page to Personyze; Personyze returns the content_id and variant (the same flow as A/B tests); and your app renders the content.

Server to server request flow
The server reports visitor and placements Personyze returns the content and variant to render

Benefits: no coupling to content type, more control over content management, and a workflow that stays simple even when an update requires content edits. It fits server rendering, SSR, and edge cleanly.

The trade-off: server-to-server means you send Personyze the visitor context it needs to decide — the current page and URL, the referrer, the user agent, and the behavior events that build the visitor’s profile. The client-side option collects all of that automatically from a single Personyze tag (70+ attributes out of the box); server-to-server trades that convenience for control, keeping decisions on your backend. It’s the right call for many teams — just budget for the extra integration work.

Option B — Client-side rendering

Your front end sends the actual content payload to Personyze, and Personyze places it on the page in the browser. Use this when you want client-only rendering or rapid UI experiments without server hooks.

Because it runs through the Personyze tag, it also captures the visitor context for you — page, referrer, device, and on-site behavior — so there’s far less to wire up than the server-to-server path.

A/B testing comes along for free

Because the decision flow is “visitor_id + placement_id → variant,” the same wiring runs A/B and multivariate tests. Test content variants per placement and audience, and let Personyze close out losers and roll traffic to winners — no separate testing integration.

Server-side or client-side rendering?

Both work, and Personyze supports both a server-side REST API and a client-side JSON API. Server-side (during page generation, SSR, or at the edge) decides before render, so there’s no flicker and it works for SEO, apps, and email. Client-side decides in the browser, which is faster to iterate for SPA experiments. Many teams mix the two.

Dynamic content, recommendations, and JSON

The same decision layer does more than swap static blocks. Dynamic content — a hero, banner, message, or CTA — can be personalized by audience, with your own custom fields (name, industry, location, account type) inserted as personalization tags right into the content or the recommendation set.

For recommendations, Personyze returns JSON for both product and content recommendations. You pick the algorithm and map the fields you want, and Personyze returns a personalized JSON set per visitor. Your front end reads it from a JavaScript variable and renders it in your own layout — cards, carousels, widgets — which is ideal for SPAs, mobile apps, and custom front ends. Prefer not to build the display? Managed, responsive widgets are available too.

And it fits either render path from above: client-side, using the client-side JSON API read in the browser or app; or server-side, calling Personyze’s API from your backend with the visitor’s id — even their CRM id or email — to get their recommendations back. There’s a full REST API and native iOS/Android SDKs, and the same multilingual logic applies, so content and recs arrive in the visitor’s language.

Two quick examples

1. A B2B homepage hero (server-to-server)

Build: Define a “Manufacturing accounts” audience in the Audience Builder using your CRM and firmographic fields. Create a placement — home-hero — and store two hero variants in your CMS. On each homepage request, your server sends the visitor_id, home-hero, and the visitor context (page, referrer, and the company from your own data) to Personyze, gets back a content_id, and renders that hero server-side.

End result: a classic B2B personalization play — a visitor from a manufacturing account lands on a hero and CTA written for manufacturing — server-rendered, no flicker — while everyone else sees the default. Point the same placement at two variants and you’ve got an A/B test.

2. A “Recommended for you” rail in a SPA (client-side JSON)

Build: Set up a Content Recommendations JSON action with a “readers also read” or “most read by interest” algorithm, map the fields you want (title, image, URL), and assign the result to a JavaScript variable. On your article page, read that variable and render your own card layout — no server changes.

End result: every reader sees a personalized rail in your own design — the heart of publisher & media personalization. New or anonymous readers get trending and popular picks; once an interest is known it shifts to interest-based recommendations — all client-side, and in the visitor’s language.

What to align on before you build

A short discovery checklist gets a headless integration scoped quickly:

  • Render path: server-side during page generation, or client-side?
  • Tech stack: which languages and frameworks power your rendering layer?
  • Auth & events: preferred auth (API key or OAuth), and — for server-to-server — can you send Personyze the visitor context it needs (current page/URL, referrer, user agent) plus real-time view/click events (visitor_id + placement_id)?
  • Caching / CDN: any constraints for server-to-server calls — TTLs, edge caching, or personalization-vs-cache rules — to factor in?

Works with any headless CMS

The decision layer is CMS-agnostic: it operates on content_ids and placement_ids, not on a specific product. That means it slots in alongside API-first platforms like Contentful, Sanity, Strapi, Contentstack, or ButterCMS — and it can pull unified profiles from a CDP such as Segment or an integration you already run.

Headless personalization: FAQ

What is headless CMS personalization?

It’s personalizing content that a headless (API-first) CMS delivers to a decoupled front end. Instead of a script rewriting a rendered page, a decision layer decides which content or variant each visitor should see for a given slot, and your front end renders it – on the server or in the browser.

Can I personalize a headless site without rebuilding my front end?

Largely, yes. With the server-to-server pattern, your back end stores content_id, placement_id, and audience, then reports visitor_id + placement_ids and renders whatever Personyze returns. There’s no coupling to content type, so most of the work is wiring events and a decision call.

Should I render personalization server-side or client-side?

Server-side (SSR or edge) decides before render, avoids flicker, and works for SEO, apps, and email. Client-side is quicker to iterate for SPA experiments. Personyze supports both a server-side REST API and a client-side JSON API, and many teams mix them.

How are audiences defined in a headless setup?

You can embed the Personyze Audience Builder in an iframe inside your own UI so editors define rules with your customer and account fields, and Personyze returns a compiled audience definition – or build audiences directly in Personyze. Either way you avoid rebuilding audience logic.

Does A/B testing work in a headless architecture?

Yes. The same decision flow – visitor_id + placement_id returning a variant – runs A/B and multivariate tests, with automatic winner selection. Testing isn’t a separate integration.

Which headless CMSs does this work with?

Any API-first CMS. The decision layer works on content_ids and placement_ids rather than a specific product, so it fits Contentful, Sanity, Strapi, Contentstack, ButterCMS, and others, and can combine with a CDP like Segment.

Get started

Personalize your headless stack without rebuilding it. Book a demo to scope an integration, or view plans.

Let's talk

Book a demo with a personalization expert

30 minutes with a personalization expert. Bring your stack, your goals, your skepticism. We'll show you what changes when every visit feels like the only one.