ssrchecker
HomeFixNext.js not indexed

Next.js pages not indexed? The cause isn't what React devs expect.

Short answer
Next.js renders HTML on the server by default, so unindexed Next.js pages are rarely the empty-shell problem a plain React app has. The usual causes are data fetched in the browser inside client components, a rendering-mode misconfiguration such as static export with client fetching, or a directive problem like a stray noindex or bad canonical.

This matters because the standard advice — "migrate to a server-rendering framework" — is useless to you. You're already on one. The question on a Next.js site is narrower: which routes are leaking content to the client side, and is anything in your configuration telling Google to stay away.

Is this actually your problem?

Next.js indexing failures have a distinctive shape. The tell is unevenness — some routes fine, others invisible.

!Static marketing pages are indexed, but dynamic [slug] routes are not
!View source shows your header and footer but not the product data or article body
!Search Console shows the page with a loading skeleton or spinner in its screenshot
!Titles are right on some routes and generic on others
!Pages fetched with SWR or React Query fare worse than pages using server fetching
!The problem appeared after a Pages Router → App Router migration, or after adding “use client” broadly

If every page including static ones is unindexed, jump to when it isn't rendering — a site-wide failure on Next.js is almost always a directive or config problem, not a rendering one.

What's actually happening

Next.js produces real HTML on the server for every route. But "the route is server-rendered" and "the content is in the server-rendered HTML" are different claims. The framework renders whatever exists at render time. Data fetched in useEffect, SWR or React Query does not exist at render time — it arrives in the browser, afterwards.

So the server sends your layout, header, footer, and an empty state or skeleton where the data will go. A crawler captures exactly that. The page isn't an empty shell — it's a furnished room with the one thing that mattered missing. That's why Next.js sites get HYBRID verdicts where Create React App sites get CSR.

The trap combination
output: "export"plus client-side data fetching. Static export bakes the HTML once at build time — and if the data is fetched client-side, it bakes the skeleton. You've reproduced a single-page app's SEO profile inside a server-rendering framework, which is why the verdict surprises people. The framework isn't lying; the configuration opted out.

The "use client" misconception

The most common wrong diagnosis on App Router sites: "we added use client everywhere, so we lost SSR." Not quite. Client components are still pre-rendered to HTML on the server — "use client" does not switch a component to browser-only rendering.

What it changes is where your data code runs. A client component can't be async and can't fetch during the server render, so its data has to come from a hook — and hooks run in the browser. The directive doesn't remove your HTML; it quietly relocates your data fetching to after the HTML is sent. That's the mechanism behind almost every HYBRID verdict on a Next.js site, and it's why the fix is moving fetches up into a Server Component, not deleting the directive.

Confirm it in ten seconds

Check the exact route type Search Console is flagging — a dynamic product or article URL. On Next.js sites the homepage is nearly always the best-behaved page on the site and proves nothing.

Check what crawlers get from this route
https://

Reading the result

VerdictWhat it means on a Next.js site
HYBRIDThe expected failure mode. The shell rendered but data-dependent content is client-fetched. The missing-elements list tells you which components to trace — start with anything using useEffect, SWR or React Query.
CSRUnusual for Next.js and worth taking seriously. Either the route is fully client-rendered, static export is serving skeletons, or an error during server rendering made Next fall back to the client. Check the server logs for that route.
SSRThis route is fine — but Next.js renders per route, so check the actual URLs Search Console flags before concluding anything. If those are green too, your problem is directives or content, not rendering.
Image slot
Screenshot: HYBRID verdict on a Next.js dynamic route — highlight the rendered shell vs the missing data region.
The Next.js signature: the shell is there, the data isn't. HYBRID, not CSR.

How to fix it

Six steps. Steps three and four are the substantive ones — they move the data, then correct the mode.

01
Check a deep route, not the homepage
Next.js decides rendering per route, so one green result proves nothing about the rest. Check a product page, an article, a dynamic [slug] route — the pages Search Console is actually complaining about.
02
Identify where the missing content is fetched
If the verdict is HYBRID, the shell rendered but some content didn't. Search the components on that route for useEffect data fetching, SWR, or React Query without a server-side initial payload. That code runs after the HTML is sent — crawlers capture the version without it.
03
Move data fetching to the server layer
In the App Router, fetch in an async Server Component and pass the result down as props — client components can receive server-fetched data without losing interactivity. In the Pages Router, that means getServerSideProps or getStaticProps.
04
Fix the rendering mode per route
Stable pages should be static or ISR — they index fastest and cheapest. Frequently changing pages suit dynamic rendering. If you're using output: 'export' with client-fetched content, you've rebuilt a SPA with extra steps; that combination is the trap.
05
Move metadata to generateMetadata
Titles, descriptions and canonicals set with useEffect or document.title arrive after the first-pass capture. In the App Router they belong in the metadata export or generateMetadata; in the Pages Router, in next/head rendered with server-fetched props.
06
Verify, then request reindexing
Re-run the check on the routes you fixed and confirm the content ratio is near 100% with no missing links. Then use URL Inspection in Search Console on a few representative URLs to prompt a recrawl.

A practical note on step three: you don't have to convert interactive components to server components. The pattern is a thin async Server Component that fetches and passes props into your existing client component. Interactivity stays; the data moves. Most "we can't, our page is interactive" objections dissolve once the fetch and the interactivity are separated.

When it isn't rendering

If your flagged routes come back SSR, stop touching rendering. On Next.js sites these are the usual non-rendering culprits — several of them framework-specific:

A leftover noindex
Preview and staging deployments commonly send noindex headers — and the setting sometimes survives into production config. Check the response headers, not just the HTML.
Middleware in the way
Middleware that redirects by geography, locale or auth state can bounce crawlers before the page ever renders. Anything that redirects unauthenticated visitors will redirect Googlebot too.
Canonicals from a shared metadata export
A canonical defined in a layout or shared metadata object applies to every route under it. One hardcoded canonical in the root layout can point the whole site at a single URL.
robots.txt or robots.js too broad
A disallow rule written for /api or /admin that accidentally matches page paths. Test the specific flagged path against your rules.
Soft 404s from empty states
A dynamic route that renders “not found” content with a 200 status — instead of calling notFound() — teaches Google the template produces empty pages.

How long recovery takes

Same warning as every rendering fix: the most expensive mistake is deciding it didn't work and reverting before recrawling has had time to happen.

WhenWhat to expect
ImmediatelyFixed routes show green with a near-100% content ratio. Deploy-level confirmation — nothing in the index has changed yet.
Days 1–7URLs pushed through URL Inspection get picked up. Because Next.js problems are usually route-type-specific, inspect one URL per route template, not ten of the same kind.
Weeks 2–6Indexed counts climb per route template as recrawling reaches them. Watch templates separately — product pages may recover on a different curve than articles.
Weeks 6–12Impressions, then clicks. If one template lags the others past this window, re-check that template specifically.

Common questions

No. Client components are still pre-rendered to HTML on the server. What the directive changes is where data fetching can happen: a client component cannot fetch during the server render, so data loaded through hooks like useEffect or SWR arrives in the browser after the HTML is sent. The HTML exists, but the data-dependent content inside it does not.