Hydration Proof

Search documentation

Find a page or section

Fix the next/script hydration error

Anything that edits the page before React hydrates edits React's page.

A next/script hydration error can happen when a script changes the DOM before React hydrates it. Tag managers, experiments, and consent tools may rewrite text or add elements. Keep those changes outside React's tree, or run them only after the affected content has hydrated.

Symptoms

Hydration failed because the server rendered text didn't match the client.
Warning: Text content did not match. Server: "Hello world" Client: "Hola mundo"
Warning: Extra attributes from the server: data-experiment
Minified React error #418; visit https://react.dev/errors/418

The error may come and go because script and hydration timing varies.

hydration-proof reports a pre-hydration change as HP4001 and shows both values:

HP4001 The page was modified before React hydrated  ·  #greeting
  server "Hello world"  → client "Hola mundo"
  Possible cause: A script changed the page before hydration.  Fix: Load it after hydration or keep it outside React's tree.

Why the next/script hydration error happens

React hydrates the DOM as it exists at that moment. Scripts that run between HTML parsing and hydration can change it:

  • scripts in <head> without defer or async, and inline scripts
  • next/script with strategy="beforeInteractive", which Next.js injects into the <head> of the server HTML and fetches before any Next.js code
  • tag managers and experimentation tools that swap text or classes as early as they can, to avoid a flash
  • personalization, translation and consent tools that edit the page on load

next/script beforeInteractive hydration error

beforeInteractive scripts load early. If they edit React-owned DOM, they can race hydration. Use this strategy for scripts that must run early and do not change that DOM. See the Next.js issue for a reported case.

next/script nonce CSP hydration warning

With a Content Security Policy that uses a nonce, you may see:

Warning: Extra attributes from the server: nonce

Browsers hide a parsed script's nonce attribute from normal DOM reads, even though the nonce still controls whether it runs (React issue). Do not expose the nonce to client code just to silence a warning. Follow the Next.js CSP guide.

Vercel Speed Insights hydration error

A Vercel Speed Insights hydration error was reported in a Next.js issue. If you see a similar error, check your package versions, then test whether the DOM changed before hydration or the component itself rendered differently.

How to fix it

Load the script after hydration

afterInteractive runs after some hydration, not necessarily after every component hydrates. lazyOnload waits until browser idle time. Neither is a license to rewrite React-owned markup; use a later hook if the target must be hydrated first:

app/layout.tsx
import Script from "next/script";
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        {children}
        {/* Before: strategy="beforeInteractive" */}
        <Script
          src="https://example.com/experiments.js"
          strategy="afterInteractive"
        />
        <Script
          src="https://example.com/chat-widget.js"
          strategy="lazyOnload"
        />
      </body>
    </html>
  );
}

Use the latest loading strategy your script can tolerate, and test the route under slow-network conditions.

Give the script its own element

If a script must run early, give it a separate container outside the React root when possible. Avoid changing a placeholder React expects to hydrate.

Move experiments to the server

For an A/B test, choose the variant on the server and pass that decision to the browser. See server and client data.

Mark inline theme scripts

For a theme script that changes only <html>, use the focused pattern in the theme guide.

Catch it with ESLint

A linter cannot inspect what an external script does at runtime. Test the page in a browser.

Catch it in CI

hydration-proof compares parsed server HTML with the DOM before React hydrates. It reports script changes as HP4001 and recognized extension changes as HP4002. Use a scenario's initScripts to test a script before shipping it. See how it works.

npx hydration-proof test