Why it matters
On request-time routes Next.js 16 streams metadata into <body> for any user agent not in htmlLimitedBots, and the default list excludes Googlebot and all AI crawlers. Google only accepts rel=canonical in <head> (it stays in <body> even after rendering), and non-rendering AI crawlers may miss the title.
How to fix it
Prerender the metadata (static params or 'use cache' in generateMetadata), or extend htmlLimitedBots with Googlebot and the AI crawlers. Setting htmlLimitedBots replaces Next's default list, so keep it.
Example
// next.config.ts — verified on Next 16.3.5: bots get <head> metadata and in-order HTML, browsers keep streaming
import type { NextConfig } from 'next'
// Copy of Next's default list (html-bots.ts); re-diff on upgrades.
const NEXT_DEFAULT_HTML_BOTS =
"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight"
const EXTRA_BOTS = [
'Googlebot', 'GPTBot', 'OAI-SearchBot', 'ChatGPT-User',
'ClaudeBot', 'Claude-SearchBot', 'Claude-User', 'Claude-Code',
'PerplexityBot', 'Perplexity-User', 'meta-externalagent', 'meta-externalfetcher',
'Amazonbot', 'DuckAssistBot', 'MistralAI-User', 'CCBot', 'Bytespider',
].join('|')
const nextConfig: NextConfig = {
htmlLimitedBots: new RegExp(NEXT_DEFAULT_HTML_BOTS + '|' + EXTRA_BOTS, 'i'),
}
export default nextConfigReferences
More seo rules
void seo reports 60 rules in this category. What search engines need from the raw response: status codes, titles and descriptions in <head>, self-referencing canonicals, one h1, crawlable links, Open Graph, icons, robots.txt and a sitemap with real dates.
title-missingNo single non-empty <title> in <head>title-lengthTitle length outside 10–60 characters, or keyword-stuffedmeta-description-missingNo meta description in <head>meta-description-lengthMeta description length outside 50–160 characterscanonical-missingNo single rel=canonical in <head>canonical-invalidCanonical URL is relative or contains a fragmentcanonical-brokenCanonical points to a URL that returns 4xx/5xxcanonical-conflictCanonical target redirects, is noindex, or canonicalises elsewhere