🐛 International SEO meta tags are incorrectly rendered outside <head> into <body>
📝 Description
In the current production build, all critical SEO metadata (including <title>, <meta description>, <link rel="canonical">, and hreflang alternates) are incorrectly rendered inside or after the <body> element instead of the <head> block.
Furthermore, a client-side JavaScript snippet is being used as a temporary patch to dynamically append part of these elements back to <head>, which severely breaks server-side crawling for search engines and social media scrapers.
🔍 Proof of Evidences
- Invalid React Attribute Naming: The rendered HTML source shows hrefLang="..." (with a capital L) instead of the standard standard lowercase HTML attribute hreflang="...". This indicates a raw JSX string print leak.
- <html> Lang Mismatch: The root HTML tag is set to <html lang="fr">, while the sub-region SEO alternates targets hrefLang="fr-FR". They should be properly aligned.
- Emergency Patch Snippet Found:
document.querySelectorAll("body link[rel='icon'], body link[rel='apple-touch-icon']").forEach(el => document.head.appendChild(el))
🛠️ Suggested Fix
Refactor the SEO implementation in the Next.js storefront. Completely remove manual string/JSX node stitching for meta tags from the page render output. Instead, leverage the native Next.js Metadata API (export const metadata = { ... } or generateMetadata) to allow the framework to correctly hoist and validate all internationalization headers securely inside the standard structure.
Remove the JS Hack: Completely delete the client-side JavaScript patch mentioned. Once the Metadata API is adopted, Next.js will natively place all link and script tags in the head during SSR, rendering this workaround entirely obsolete and eliminating unnecessary client-side DOM manipulation.
⚠️ Critical Update: SSR vs. Hydration Mismatch affecting ALL SEO Meta Tags
After deeper investigation into the raw network payload, we found that this rendering bug affects all SEO-critical elements and introduces a major discrepancy between what is seen in DevTools and what is actually delivered by the server.
📍 Exactly Where to Look (How to Reproduce the Bug)
Do NOT use the standard Chrome Elements panel (F12) to inspect the code, as it masks the issue. Instead, developers can verify the bug using either of these two methods:
- Via Chrome Network Tab (Recommended):
- Open DevTools -> Go to the Network tab -> Reload the page.
- Click on the main document request (the initial page URL).
- Go to the Response sub-tab (or right-click the page and select "View Page Source").
- Search for
hreflang or canonical. You will see they are delivered inside the <body> structure, far below the closed </head> tag.
- Via Terminal (Instant Check):
- Run a simple curl command:
curl -s https://<your-stage-url> | grep hrefLang
- You will instantly see the raw HTML stream showing the misplaced tags with the incorrect React camelCase naming.
🔍 Why it was missed: The DevTools Illusion (Hydration)
- In Chrome Elements: The tags appear correctly inside the
<head> because React's client-side hydration process kicks in after the page loads and automatically hoists these DOM elements from the <body> back up into the <head>.
- In the Raw Server Response: As shown in the Network tab/Page Source, the server is emitting these tags inside the
<body> during SSR.
💥 The Full Scope: It is not just hreflang
This SSR leak breaks the entire SEO foundation of the page. The following critical tags are all trapped in the raw <body> response:
- The
<title> tag
- The
<meta name="description"> tag
- The
<link rel="canonical"> tag
- All
hreflang localized alternates
- All Open Graph (
og:) and Twitter Card social sharing tags
🚫 Impact on Search Engines & Scrapers
Search engine bots (like Googlebot) and social media crawlers (like Twitter, Facebook, Slack) primarily index and read the raw HTML server response before executing any client-side JavaScript. Because these tags are delivered outside the <head> in the initial byte stream, crawlers treat them as invalid syntax and completely ignore them, ruining our global search visibility and social preview cards.
🛠️ Reminder on the Fix
Please completely migrate all these tags away from manual string/JSX component assembly in the page body. Utilizing the native Next.js Metadata API (export const metadata or generateMetadata) will guarantee that the framework bundles and injects all these tags into the genuine <head> container during server-side generation.
🐛 International SEO meta tags are incorrectly rendered outside <head> into <body>
📝 Description
In the current production build, all critical SEO metadata (including <title>, <meta description>, <link rel="canonical">, and hreflang alternates) are incorrectly rendered inside or after the <body> element instead of the <head> block.
Furthermore, a client-side JavaScript snippet is being used as a temporary patch to dynamically append part of these elements back to <head>, which severely breaks server-side crawling for search engines and social media scrapers.
🔍 Proof of Evidences
document.querySelectorAll("body link[rel='icon'], body link[rel='apple-touch-icon']").forEach(el => document.head.appendChild(el))
🛠️ Suggested Fix
Refactor the SEO implementation in the Next.js storefront. Completely remove manual string/JSX node stitching for meta tags from the page render output. Instead, leverage the native Next.js Metadata API (export const metadata = { ... } or generateMetadata) to allow the framework to correctly hoist and validate all internationalization headers securely inside the standard structure.
Remove the JS Hack: Completely delete the client-side JavaScript patch mentioned. Once the Metadata API is adopted, Next.js will natively place all link and script tags in the head during SSR, rendering this workaround entirely obsolete and eliminating unnecessary client-side DOM manipulation.
After deeper investigation into the raw network payload, we found that this rendering bug affects all SEO-critical elements and introduces a major discrepancy between what is seen in DevTools and what is actually delivered by the server.
📍 Exactly Where to Look (How to Reproduce the Bug)
Do NOT use the standard Chrome Elements panel (F12) to inspect the code, as it masks the issue. Instead, developers can verify the bug using either of these two methods:
hreflangorcanonical. You will see they are delivered inside the<body>structure, far below the closed</head>tag.curl -s https://<your-stage-url> | grep hrefLang🔍 Why it was missed: The DevTools Illusion (Hydration)
<head>because React's client-side hydration process kicks in after the page loads and automatically hoists these DOM elements from the<body>back up into the<head>.<body>during SSR.💥 The Full Scope: It is not just
hreflangThis SSR leak breaks the entire SEO foundation of the page. The following critical tags are all trapped in the raw
<body>response:<title>tag<meta name="description">tag<link rel="canonical">taghreflanglocalized alternatesog:) and Twitter Card social sharing tags🚫 Impact on Search Engines & Scrapers
Search engine bots (like Googlebot) and social media crawlers (like Twitter, Facebook, Slack) primarily index and read the raw HTML server response before executing any client-side JavaScript. Because these tags are delivered outside the
<head>in the initial byte stream, crawlers treat them as invalid syntax and completely ignore them, ruining our global search visibility and social preview cards.🛠️ Reminder on the Fix
Please completely migrate all these tags away from manual string/JSX component assembly in the page body. Utilizing the native Next.js Metadata API (
export const metadataorgenerateMetadata) will guarantee that the framework bundles and injects all these tags into the genuine<head>container during server-side generation.