Why it matters
With Suspense on request-time routes, Next.js sends the shell first and the resolved content later in <div hidden id="S:n"> plus a script that moves it. Non-rendering crawlers get it out of reading order and inside a hidden element.
How to fix it
Add AI crawlers to htmlLimitedBots (they then get fully rendered, in-order HTML), prerender the route, or move primary content above the Suspense boundary.
Example
// next.config.ts — keep Next's default list; see seo/metadata-in-body for the full regex
const nextConfig: NextConfig = {
htmlLimitedBots: new RegExp(NEXT_DEFAULT_HTML_BOTS + '|Googlebot|GPTBot|OAI-SearchBot|ChatGPT-User|ClaudeBot|Claude-SearchBot|Claude-User|PerplexityBot|Perplexity-User', 'i'),
}References
More ai search rules
void geo reports 41 rules in this category. Generative-engine optimisation: whether AI crawlers that don't run JavaScript see the same content, valid and visible JSON-LD, an explicit AI robots policy, llms.txt, Markdown mirrors and answer-first writing.
js-dependencyMain content only appears after JavaScript runsai-bot-blockedAI crawler user agents get 401/403/429/503 or a challenge pageai-content-differsAI crawlers get materially different HTML than browsersjsonld-parse-errorJSON-LD block is not valid JSONjsonld-unsafeJSON-LD contains a literal </script or <!--jsonld-missingPage has no JSON-LDjsonld-not-in-rawJSON-LD is injected by JavaScripthome-entity-missingHome page lacks Organization + a single WebSite node