Headless CMS SEO: the fields to model, the HTML to render and the gaps between the two

A headless CMS stores content and leaves the title tag, canonical, sitemap and status codes to your front end, so here is how to build each one on purpose.

Published by AI Knows Us · Updated 22 October 2026

Headless CMS SEO works when two jobs are done well: the content model stores every SEO field an editor needs, and the front end turns those fields into complete HTML on the first response. A headless CMS such as Contentful, Sanity, Storyblok or Strapi only stores and serves content through an API. It does not print a title tag, a canonical link or a sitemap for you. Done that way, a headless site is as easy to rank as any other site, and often easier, because nothing is left to a plugin's defaults.

Why headless changes who owns SEO

In a coupled CMS the same system stores the words and renders the page, so SEO settings live in one screen. The .NET platforms Sitecore, Umbraco and Kentico can run either way, and our page on Sitecore, Umbraco and Kentico SEO covers each one's defaults. In a headless setup the work splits in two:

  • The CMS side holds the content and the SEO fields: slugs, meta titles, descriptions, canonical overrides, noindex flags, image alt text and social images.
  • The front end (Next.js, Astro, Nuxt, a custom app) fetches that content and decides what HTML a crawler receives, which URLs exist, which status code each one returns, and what goes into the sitemap.

Most headless SEO problems happen in the gap between the two, so treat every field in the model as a promise the rendered page has to keep. An editor fills in a meta description that the front end never reads. A developer builds a sitemap from routes and forgets the pages that come from the CMS. A deleted entry leaves a URL that returns a blank page with a 200 status.

Model the SEO fields in the CMS

Add a reusable SEO group or component to every content type that becomes a page. A practical set looks like this:

FieldTypeRule worth enforcing
SlugSlug or UID fieldRequired, unique, lowercase, generated from the title but editable
Meta titleShort textFalls back to the page title when empty
Meta descriptionShort textWritten for the searcher, one per page
Canonical URLURLEmpty by default, so the page points at itself
NoindexBooleanOff by default, and visible to editors
Social imageImage referenceFalls back to the main image
Image alt textText on every imageRequired on content images

The CMS vendors give you the building blocks for this. Sanity's slug field type, per its documentation read on 22 October 2026, has a source option that derives the slug from another field, a maxLength option and an isUnique function for custom uniqueness checks. Strapi's Content-type Builder docs model page slugs with a UID field. Storyblok's field settings include Required and Translatable options, which matter when the same entry serves several languages. Use required and validation settings so the CMS refuses to publish a page with no slug or title.

Render complete HTML on the first response

Google's JavaScript SEO guide (last updated 4 March 2026) says Google processes JavaScript pages in three phases: crawling, rendering and indexing. Rendering happens in a queue, and the guide adds that server-side or pre-rendering "is still a great idea because it makes your website faster for users and crawlers, and not all bots can run JavaScript." So the safest headless build sends the title, meta description, canonical link, main text and links in the HTML the server returns, not after a client-side fetch to the CMS API.

Dynamic rendering, where bots get a different server-rendered copy, is not the answer either. Google's own page now calls it "a workaround and not a long-term solution" and recommends server-side rendering, static rendering or hydration instead. We cover the rendering choices in more depth in our guide to how Google renders JavaScript sites. For a headless CMS the short version is: build the page on the server or at build time, and fetch CMS content there.

Next.js

Next.js exports a metadata object or a generateMetadata function from a page or layout, and both run only in Server Components. A typical headless pattern reads the SEO group from the CMS entry:

export async function generateMetadata({ params }) { const { slug } = await params const entry = await getEntryBySlug(slug) return { title: entry.seo?.metaTitle || entry.title, description: entry.seo?.metaDescription, alternates: { canonical: entry.seo?.canonical || 'https://example.com/blog/' + slug, }, robots: entry.seo?.noindex ? { index: false } : undefined, }
}

One detail is worth knowing. The Next.js docs describe streaming metadata: when generateMetadata is slow, the tags can be appended to the body after the first UI is sent. The docs say this is read correctly by bots that run JavaScript, such as Googlebot, while HTML-limited bots like facebookexternalhit still get the tags in the head. The htmlLimitedBots setting in the Next.js config controls that list, and setting it to match every user agent turns streaming metadata off.

Astro

Astro fetches CMS content at build time by default, which suits SEO well. Its sitemap integration, per the Astro docs, needs the site option set to your deployed URL and builds the sitemap from statically generated routes. The docs also state that it cannot generate entries for dynamic routes in SSR mode. If some CMS pages are rendered on demand, build those sitemap entries yourself from the CMS API.

URLs, status codes and deleted content

The front end decides which URLs exist, so it must also decide which do not:

  • Return a real 404 when the CMS has no entry for a slug. Google's guide warns about soft 404 errors in client-side apps and suggests either redirecting to a URL the server answers with a 404, or adding a noindex robots tag to the error view.
  • Store redirects next to the content. When an editor changes a slug, the old URL needs a permanent redirect. A small redirects content type, read by the front end or the hosting layer at build time, keeps this in the editors' hands.
  • Use real URLs, not fragments. Google says it can only find links that are <a> elements with an href attribute, and that single-page apps should route with the History API rather than URL fragments.

Watch the noindex flag closely. Google's guide notes that when it sees a noindex tag it may skip rendering, so JavaScript that later removes the tag may not work as expected. If an editor's noindex toggle is off, the tag must not appear in the server HTML at all.

Rich text, internal links and images

Rich text in a headless CMS is usually stored as structured data rather than finished HTML (Sanity calls its format Portable Text), and a renderer you control turns it into HTML. That renderer is where internal links live or die. Make sure links to other entries render as plain anchor tags with a full path, that the anchor text is the editor's words, and that image blocks output the alt text field. A renderer that turns entry links into click handlers produces a site where the crawler sees no internal links at all.

Sitemaps, previews and publishing

Build the sitemap from the CMS, not from the file system, so every published entry appears with its real last-modified date. Next.js supports a sitemap.ts file that returns a list of URLs with lastModified values, which can come straight from the entry's updated timestamp. List it in robots.txt and Search Console.

Keep preview and staging environments out of the index with authentication or a noindex header, because a public preview domain is a full duplicate of the site. And trigger a rebuild or cache refresh from a CMS webhook on publish, so a corrected title reaches the live HTML in minutes rather than at the next deploy.

The answer engines read the same HTML

Everything above is about Google, and the same first-response HTML is also what AI assistants and their crawlers fetch when somebody asks them about your product. A headless site that puts its prices, plans or coverage into the page only after a client-side call can be perfectly indexed by Google and still be quoted wrongly elsewhere. Our crawler access test compares the raw and the rendered HTML for exactly this reason. Checking what ChatGPT, Gemini and Perplexity actually say about a brand is the work AI Knows Us does, and on a headless site the first thing to compare is that answer against what your server sends.

Questions about headless CMS SEO

Is a headless CMS bad for SEO?

No. A headless CMS has no SEO weakness of its own. Results depend on the front end: if it renders full HTML on the server or at build time and outputs the SEO fields from the CMS, the site can rank like any other.

Which SEO fields should a headless content model have?

At minimum a slug, meta title, meta description, canonical override, noindex flag, social image and alt text on images. Put them in one reusable SEO group and set fallbacks in the front end.

Do I need server-side rendering for a headless site?

Server-side or static rendering is the recommended approach. Google can render JavaScript, but its own guide says pre-rendering is faster for users and crawlers and that not all bots run JavaScript.

How do I handle redirects when an editor changes a slug?

Store redirects as content in the CMS and have the front end or host read them at build time. Each changed slug gets a permanent redirect from the old URL to the new one.

Read next

Simon-Kucher pricing strategy, what the firm publishes about its own method and what a Singapore buyer should ask before briefing itThe firm publishes its approach, its scale and four named service lines, and publishes no fee, so the useful work before any call is reading what it claims and deciding which decision you are buying.International pricing strategies for a Singapore company, and the corridor that stops one market undercutting anotherA converted home price is the one answer that is almost always wrong, so set a price per market and keep the gaps narrower than the cost of moving a unit between them.Premium pricing strategy for a Singapore business, and the fence that makes the higher number holdCharging permanently more than the credible alternatives works when the buyer can name what the extra money buys, and the published Singapore writing ladder shows exactly how that is built.Red Antler publishes no price, so here is what its own site does publish and how to cost the same scope from SingaporeRead on 29 October 2026, three pages of redantler.com carry a complete deliverable list, three business stages and not one figure about what any of it costs.Hiring a full service content agency, the five stages a retainer has to cover and the two handoffs where the money leaksMost content retainers buy production and quietly leave strategy and distribution with you, so price the stages rather than the word count.Hiring a branding agency for a Singapore financial services firm, and the three registers to search before you fall in love with a nameIdentity work for a licensed firm starts with a clearance search rather than a mood board, and two of the three registers are free to read in a browser today.

Or browse the whole archive.

See what AI says about you.

The first scan is free, it needs no account, and it asks the questions your buyers ask.

Free. No card. We ask 5 real buyer questions on 2 AI apps.

Already sure you want this? Start free. No card needed, and the free plan stays free. Pay only when you want the work done. Or talk to a person if you have a question first. Or read how we fix what it finds.