CodeeoInsightsSEO

Headless SEO Implementation: Schema, Sitemaps and Canonicals

Headless SEO at build stage: render metadata on the server, generate canonicals and a dynamic sitemap from your CMS, and output JSON-LD schema you can test.

MY PLACES: Sharing the events feed with a friend

Headless SEO comes down to one rule: everything a traditional CMS used to print into the page for you, your front end now has to generate on purpose. That means canonical tags, XML sitemaps, robots directives and JSON-LD schema must be built from your content model and checked in the raw HTML, not assumed. This guide covers the build stage, with the checks a developer or SEO lead can run before launch.

If the team is still deciding whether to go headless at all, start with our article on the SEO risks of headless CMS sites. What follows assumes the decision is made and the work is now in sprints.

What changes for headless SEO at build time

In a monolithic CMS, a plugin or theme usually owns the head of the page. In a headless build, the CMS only stores content and serves it through an API. The front end framework, often Next.js, decides what HTML is returned to a crawler. If nobody writes the code for a canonical tag, there is no canonical tag.

That shifts SEO from a settings screen into the definition of done for each template. In practice the work splits into four areas:

  • Rendering: make sure the important content and metadata exist in the HTML the server returns.
  • Canonicals and indexing: give every indexable URL one clear preferred version.
  • Sitemaps: generate them from the same data source that creates the pages.
  • Structured data: output JSON-LD that matches what is visible on the page.

Each area needs fields in the CMS, logic in the front end and a test in the release pipeline.

Start with rendering, because every other check depends on it

Google can render JavaScript, but its own JavaScript SEO basics guide still describes server side rendering or pre-rendering as a good idea because it makes a site faster for users and crawlers, and it notes that not every bot runs JavaScript. Social preview bots and many SEO tools read only the first HTML response.

Rendering checks before anything else

  1. Fetch a sample of each template with a plain HTTP request (curl or a crawler with JavaScript turned off) and confirm the title, meta description, canonical, main heading and body copy are present.
  2. Compare that raw HTML with the rendered HTML in the URL Inspection tool in Search Console. The two should agree on canonical and robots values.
  3. Confirm that routes which should not exist return a real 404 status, not a 200 page that says "not found". Google's guide describes soft 404s as a common single page app problem.
  4. Check that internal links are ordinary anchor elements with an href, so crawlers can follow them without clicking.

In the Next.js App Router, metadata defined with the metadata object or the generateMetadata function is resolved on the server. The Next.js generateMetadata reference also explains streaming metadata: on dynamic pages, tags can be sent after the initial UI for bots that execute JavaScript, while bots it recognises as HTML limited still receive them in the head. That behaviour is configurable, so record the team's choice and test both the raw and rendered output.

Canonical tags in a headless build

Canonical tags headless teams ship tend to fail in predictable ways: missing on some templates, relative when they should be absolute, pointing at a staging domain, or set by client side JavaScript after load. Google's documentation on consolidating duplicate URLs treats redirects and rel canonical as strong signals and sitemaps as a weak one, and it recommends absolute URLs.

Model the canonical in the CMS

Give each content type a computed canonical path based on its slug and its position in the site structure, plus an optional override field for editors. The override covers edge cases such as syndicated articles or landing page variants. Lock the domain and protocol in the front end configuration, not in the CMS, so an editor cannot type a staging address.

Generate it in one place

In Next.js, set metadataBase once in the root layout using an environment variable for the production origin. Each page then returns its canonical through alternates.canonical as a path, and the framework composes the full absolute URL. Using a relative path without metadataBase causes a build error, which is a useful safety net.

Canonical rules to enforce in code review

  • Every indexable page has a self referencing canonical.
  • Query strings from tracking, sorting and filtering are stripped from the canonical unless the filtered page is meant to rank.
  • Trailing slash and letter case follow one convention, and the other form redirects to it.
  • Paginated pages keep their own canonical rather than pointing every page to page one.
  • The canonical, the sitemap entry and the internal links all use the same URL.
  • Pages marked noindex are not listed in the sitemap, and noindex is not used as a way to choose a canonical.

Hypothetical example: a Dubai retailer moves to a Next.js storefront with a headless CMS. Product pages are reachable at a clean path and at a version carrying a campaign parameter. Because the developer built the canonical from the slug alone, the campaign version declares the clean path as canonical, and Search Console reports the parameter URLs as duplicates that Google has correctly folded together.

Building a dynamic sitemap from the content source

A dynamic sitemap in a headless stack should be generated from the same API that builds the pages. If the sitemap is a static file someone exports, it drifts out of date within weeks.

Google's guide to building a sitemap sets the limits: up to 50,000 URLs and 50MB uncompressed per file, with larger sites split across several files and, optionally, a sitemap index. It also says Google ignores changefreq and priority, and uses lastmod only when it is consistently accurate.

How to implement it in Next.js

Next.js supports a sitemap file convention in the app directory. A sitemap.ts file exports a function that returns a list of URL objects. For large catalogues, the generateSitemaps function splits output into numbered files, so products, articles and landing pages can each have their own sitemap.

Sitemap checklist

CheckWhat good looks like
Source of truthBuilt from the CMS or commerce API, filtered by publish status
URLsAbsolute, canonical, on the production domain, returning 200
ExclusionsNo noindex pages, redirects, drafts, preview routes or internal search results
lastmodTaken from a real content update field, not the build time
SizeSplit before reaching the documented limits
FreshnessRegenerated or revalidated when content is published
DiscoveryListed in robots.txt and submitted in Search Console

The lastmod point matters more than it looks. Setting every entry to the current date on each deploy tells Google nothing useful and can make the field unreliable. Store a modified date on each entry in the CMS and only update it for meaningful changes to content, structured data or links.

Sitemap routes are often cached by default. Decide how they refresh: on a schedule, through on demand revalidation triggered by a CMS webhook, or both. For a news section or a catalogue with frequent stock changes, webhook revalidation keeps the sitemap close to real time without rebuilding the whole site.

JSON-LD schema from structured content

Headless builds have an advantage here. Content is already stored as fields, so JSON-LD schema can be assembled from real data rather than typed by hand. Google generally recommends JSON-LD where a site's setup allows it, and structured data makes pages eligible for rich results but does not guarantee them.

Map types to templates

  • Organisation and WebSite: once, in the root layout, with name, logo and official profiles.
  • BreadcrumbList: on every page deeper than the home page, built from the same data as the visible breadcrumb.
  • Article: on blog and news templates, with headline, author, dates and image.
  • Product: on product templates, with offers, price and availability pulled live from the commerce system.
  • LocalBusiness: on location pages, if the business has physical branches in Dubai, Abu Dhabi or elsewhere.

Implementation rules

Render the JSON-LD in a script tag of type application/ld+json from a server component, so it appears in the first HTML response. Google's JavaScript guide confirms that JSON-LD injected by JavaScript can work, but server output is simpler to test and is read by more tools.

Keep markup honest. Every value in the schema should be visible on the page or clearly true for it. Prices and availability must match what the shopper sees, and review markup should only describe reviews the page actually shows. Write a typed helper for each schema type so the same function is reused across templates and validated in one place.

Test with the Rich Results Test for the types Google supports, and with the Schema Markup Validator for general syntax. Add a check to the pipeline that parses the JSON on a sample of pages and fails the build on invalid output.

Teachers Lunch by Codeeo
Teachers Lunch, a food ordering app Codeeo built, shown on a phone; when one content source feeds both an app and a website, the web front end still needs its own crawlable URLs, canonicals and schema.

Robots, redirects and environments

Headless projects usually run several environments: local, preview, staging and production. Each one is a chance to leak an indexable copy of the site or to ship a noindex tag to production.

  • Generate robots.txt and robots meta values from an environment variable. Production allows crawling; every other environment blocks it and, ideally, sits behind authentication.
  • Exclude CMS preview routes and draft URLs from crawling and from the sitemap.
  • Manage redirects as data. Store old and new paths in the CMS or a config file, serve them as permanent redirects at the edge or in middleware, and test them in bulk.

A QA routine for the headless build before launch

Run this before go live and again after every major release. It works for a marketing site, a content hub or a headless commerce storefront.

  1. Crawl staging with JavaScript turned off, then on. Compare titles, canonicals, robots values and word counts between the two crawls.
  2. Export every URL from the sitemap and confirm each returns 200, is self canonical and is indexable.
  3. Crawl the old site and test every legacy URL against the redirect map.
  4. Validate JSON-LD on one page of each template.
  5. Check Core Web Vitals on key templates in the lab, then watch field data after launch.
  6. After launch, submit sitemaps and monitor the page indexing report and crawl stats weekly for the first few months.

For larger estates, the same discipline applies to enterprise platforms; see what to check on AEM sites. Commerce teams on Shopify face a related set of duplicate URL problems, covered in Shopify Plus SEO for large catalogues.

Get the headless build right before launch

Codeeo designs and builds headless websites and stores, including Next.js front ends, and reviews existing builds for the technical gaps described above. The team of 80+ across Dubai, Riyadh and Karachi has delivered 200+ projects across the UAE and the US, and UAE clients can meet the team at the Dubai office.

Explore Next.js development and headless commerce, or start with a technical SEO review of a staging or live site. If you are weighing the budget for ongoing work, our guide to what drives enterprise SEO pricing in Dubai sets out the factors. To discuss your build, contact the Codeeo team.

Frequently asked questions

Not every page needs to be rendered on each request.

Static generation and incremental regeneration also produce full HTML, and for most content they are faster. What matters is that the HTML returned to a crawler already contains the main content, title, canonical and structured data. Pure client side rendering is the pattern to avoid for any page you want to rank.

Tell us what the business needs. We will tell you what to build first.

Schedule a free consultation and get a written recommendation, with costs, before you commit to anything.

Get in touch

PROVEN RESULTS

4.7 / 5verified reviews on Google