Skip to main content
NewNMC’s advertising guidelines for doctors are in force from 6 Oct 2026. See what to change, and get a free compliance auditNew NMC advertising rules for doctors: what to change
SEO

Next.js and Headless CMS for Hospital Sites: The SEO Failure Modes We Keep Finding

Five ways a Next.js and headless CMS build quietly damages hospital SEO: metadata streaming, trailing-slash loops, stale ISR pages, rewrite errors and preview URLs in the index.

Next.js and Headless CMS for Hospital Sites: The SEO Failure Modes We Keep Finding

This post is for the technical lead, agency partner or in-house SEO of a hospital that has moved, or is about to move, to a Next.js front end with a headless CMS. Headless builds are a sensible choice for hospital groups: one content source, many templates, fast pages. They also move a set of responsibilities from the CMS plugin to your own code, and those responsibilities are where the SEO failures live.

What follows are five failure modes, each with how it appears, how to confirm it with a command or a report, and how to fix it. They come from our own Next.js build for this site and from audits of sites built the same way. We do not report counts or percentages here, because the point is the diagnosis, not a league table. Version-specific behaviour is taken from the Next.js documentation current at the time of writing; check the version you run.

None of these are bugs in Next.js. Each is an interaction between the framework, a proxy or CDN, and a content workflow, which is why a staging test often misses them.

1. Metadata that streams after the first byte

In current App Router versions, generateMetadata can be streamed. The Next.js generateMetadata reference explains that streaming lets Next.js send the initial UI without waiting for metadata, and appends the resulting tags to the <body>. The documentation says this has been verified with bots that execute JavaScript and inspect the full DOM, such as Googlebot. For HTML-limited bots that cannot run JavaScript, such as facebookexternalhit, metadata continues to block rendering and appears in <head>.

The risk is not Googlebot; it is everything else that reads your title, description or canonical. A crawler that does not execute JavaScript, a link-preview service, a monitoring tool or an SEO audit script may find no <title> in the head. The documentation notes that Next.js detects HTML-limited bots by user agent and that the htmlLimitedBots option overrides the list.

How to confirm. Fetch a doctor, department and blog URL with curl and look for the title, description and canonical in the response. Repeat with a user agent from the HTML-limited list. Then compare with the rendered HTML from the URL Inspection tool in Search Console.

Fix. Decide deliberately. If any tool that matters to you reads only the raw HTML, keep metadata blocking for it by extending htmlLimitedBots, or disable streaming for the whole site, accepting the documented trade-off in response time. Also keep generateMetadata fast: a slow CMS call there delays the entire document for bots that block.

2. Trailing-slash redirect loops

By default, Next.js redirects URLs with a trailing slash to the version without. The trailingSlash configuration reverses that: with trailingSlash: true, URLs without a slash redirect to the slashed version.

The loop appears when another layer holds the opposite opinion. A web server, CDN rule or platform setting that appends a slash will fight an application that strips it. The browser shows "too many redirects"; a crawler logs a chain that ends in an error. Because each layer works correctly in isolation, the fault only shows when they run together, typically after a CDN change or a migration.

How to confirm. Run curl -sIL on a URL with and without the trailing slash and read every hop. Check the status code of each hop, the Location header, and whether the final URL differs from the canonical in the page.

Fix. Choose one form and enforce it at the outermost layer that handles the request. Make the application configuration match, list only that form in sitemaps and internal links, and make the canonical tag produce it. Test the root path, deep paths, paths with query strings, and file URLs such as the sitemap and robots.txt, which are exempt from slash rules in some setups.

3. ISR pages that stay stale

Incremental Static Regeneration serves a prerendered page and regenerates it in the background. The ISR guide describes the sequence: after the revalidate period passes, the next request still receives the cached stale page, and regeneration starts in the background; the following request gets the new page. That is the intended behaviour. For a hospital site it has consequences.

  • A page for a doctor who has left can remain live for at least one more request after the CMS record is unpublished, and longer if regeneration fails. The guide notes that when revalidation throws an error, the last successful data keeps being served.
  • The documentation says that when you run several instances, the default file-system cache is per instance, so on-demand revalidation invalidates only the instance that receives the call. Without a shared cache handler, some visitors see a new page and others see an old one.
  • The guide also notes that proxy logic is not executed for on-demand ISR requests, so revalidating a rewritten path rather than the real one does nothing.
  • Dynamic routes for unknown slugs should return a 404. Check how dynamicParams and your not-found handling behave for deleted records.

How to confirm. The x-nextjs-cache response header reports HIT, STALE, MISS or REVALIDATED, as the guide describes. Request the same URL several times from different network paths and compare header values and the page body. Change a record in the CMS, trigger your webhook, and measure the time until every instance serves the new content.

Fix. Use on-demand revalidation by path or tag on publish and unpublish events, not only time-based revalidation. Revalidate the exact public path. Use a shared cache handler if you run more than one instance. Log failed revalidations. Make sure lastmod in the sitemap changes when real content changes, not on every build.

Want this applied to your practice? Get a free seo audit.

Book my free audit

4. Rewrite and protocol errors at the proxy

Hospital sites frequently sit behind a reverse proxy: a TLS terminator, a load balancer, or Next.js proxy logic that rewrites legacy URLs. A mistake we have met in our own build is a rewrite that constructs its target from the incoming request URL, behind a layer that terminates TLS. The application sees an internal HTTP request, builds a rewrite target with the wrong protocol, and fails for URLs that are not in the route table. The visible symptom is a server error on unknown slugs instead of a clean 404, while valid pages work. A related fault with forwarded headers can break form submissions on production while working locally.

Server errors on URLs a crawler meets, whether old campaign links or typos, tell Google the site is unhealthy. They also hide real broken-link reports behind a wall of 500s.

How to confirm. Request a URL that cannot exist, with curl -I, on the production domain and on any internal host. You should see a 404. Request a legacy URL you know has a redirect and verify a single 301 to a 200. Check the server logs for 5xx responses on bot traffic.

Fix. Build rewrite and redirect targets from configuration, not from the incoming URL's protocol. Respect forwarded protocol and host headers explicitly, or set the public origin as an environment variable. Keep legacy redirect maps in code under test. Return real 404 and 410 statuses from the application.

5. Preview and staging URLs in the index

A headless CMS needs a place to preview unpublished content. Next.js Draft Mode bypasses caching for editors who hold a cookie, and the draft URL is typically opened from the CMS. The drafts themselves are not the problem; the surrounding setup is. Preview deployments, staging domains, CMS-hosted preview hosts and branch URLs from a hosting platform are all reachable by crawlers unless something stops them. If a link to one appears anywhere public, in a Slack export, a PDF or an email archive, Google can find it.

Duplicated staging copies compete with the live site, and an unpublished page that gets indexed can expose a draft treatment page, an unapproved claim or a doctor profile before clinical review. In healthcare, that last case is a compliance issue as well as an SEO issue.

How to confirm. Search for site: with your staging and preview hostnames. In Search Console, check the page indexing report for hosts you do not recognise. Request a preview URL without the cookie and check whether it returns content.

Fix. Put staging and preview hosts behind authentication, not just noindex. Add an X-Robots-Tag: noindex header at the host level as a second layer. Make absolute URLs and canonicals use the configured public origin, never the request host, so a preview deployment cannot declare itself canonical. Keep non-production hosts out of sitemaps, and set the CMS preview route to require a secret token, as the Draft Mode guide describes.

A pre-launch test sheet

CheckCommand or reportPass condition
Metadata in raw HTML for ordinary and HTML-limited user agentscurl with and without a bot user agentTitle, description, canonical present where required
One URL formcurl -sIL with and without trailing slashSingle 301 hop or none
Unknown slugcurl -I on a made-up path404, not 500 or 200
Legacy redirectsCrawl the old URL listOne hop, 301, final 200
ISR freshnessEdit and unpublish in the CMS; pollNew content on every instance within your target time
Preview hostSearch and fetchBehind login; not in the index
Canonical originView source on stagingPublic production origin
SitemapFetch and sampleOnly live, 200, indexable URLs

Where to start

If you run only one check this week, request a nonexistent URL, an old URL, a trailing-slash URL and a preview URL against production. Those four requests expose the failure modes with the highest consequences. Add the other rows when you can.

For performance work that sits alongside these fixes, see our Core Web Vitals and technical SEO audit pages. The glossary entries on headless CMS and ISR cover the terms for non-technical stakeholders, and our website development team works on these builds.

Filed underheadless CMS SEO Next.jsNext.js SEO problemsheadless CMS hospital websiteISR stale pages SEONext.js trailing slash redirect loop

About the author

Co-Founder & CTO · Gurugram, India

Arush builds the systems the rest of the company runs on — the patient-acquisition pipelines, the AI chatbots, the analytics that tie a single click to a booked appointment. If a campaign reports a number, it's because something his team built is tracking it.

Free guide · 17 pages

The Patient Acquisition Blueprint

A 90-day plan from first search to booked appointment.

The Pioneers Brief — one essay, three benchmarks, one teardown, every Thursday. Subscribe free →

Free seo audit

Your next chapter starts with a conversation.

Three quick questions. We come prepared with a plan for your specialty and city.

  • A 30-minute call with a healthcare specialist
  • Your top three growth opportunities, in writing
  • Honest advice — even if that means not hiring us
  • No obligation and no hard sell
You’ll speak with a senior strategist
Consultations are hosted by Arush Thapar’s team.
Step 1 of 3Takes 30 seconds

What do you want to improve first?

Details stay privateNo obligationReply within 1 working day

Client portfolio · SEO & search visibility

Work relevant to next js and headless cms for hospital sites the seo failure.

Explore client work →