Hydration Proof

Search documentation

Find a page or section

HP1014: Document head differs between server and client

HP1014 (head mismatch): the title, meta tags or stylesheets in the head changed while the page hydrated, so crawlers and link previews see other values.

HP1014 (head-mismatch) means the <title>, a <meta> tag or a stylesheet in the document head changed while the page hydrated. Search engines, link previews and the first paint use the server's values, so they never see the final ones. Render the same head values on the server and the client, computed from data the server has.

CodeHP1014
Namehead-mismatch
Default severityWarning
GroupDOM mismatches
What it meansMetadata, stylesheets or scripts in <head> changed during hydration.

What HP1014 (head-mismatch) means

hydration-proof compares the <head> right before hydration with the page after the hydration commit's effects have run. It reports three things:

ChangeWhat the finding shows
Hydration added a <title> with a new valueThe server title and the added one
A <meta> tag (by name, property, http-equiv or itemprop) got new contentThe server content and the new one
A stylesheet <link> from the server HTML was removedIts href; the page can flash without styles

Values are compared as sets, because React 19 adds a new <title> or <meta> next to the server's instead of changing it. When that leaves two <title> elements, the browser shows the first one, which is the server's.

Since the comparison runs after effects, a title set from an effect (document.title = …) is reported as well.

Likely causes

How to fix it

  • Render the same <title> and <meta> tags on the server and the client, so search engines, link previews and the first paint show the final values.
  • Compute head values from data the server has (route params, cookies) instead of browser-only values.

A React 19 <title> that reads a name from storage:

welcome-title.tsx
"use client";
 
export function WelcomeTitle() {
  const name =
    typeof window === "undefined"
      ? "Guest"
      : (localStorage.getItem("name") ?? "Guest");
 
  return <title>{`Welcome, ${name}`}</title>;
}

Build the title on the server instead. In the Next.js App Router, that is generateMetadata, which can read cookies:

app/welcome/page.tsx
import { cookies } from "next/headers";
 
export async function generateMetadata() {
  const name = (await cookies()).get("name")?.value ?? "Guest";
  return { title: `Welcome, ${name}` };
}
 
export default function Page() {
  return <h1>Welcome</h1>;
}

When the difference is intentional

A title that changes on purpose after load, such as an unread count, is a legitimate update. Add an ignore.issues rule with code: "HP1014", the route and a reason; see ignoring findings.

Example

  ⚠ /welcome 890ms  1 warning
    HP1014 Document head differs between server and client
      head > title
      attribute: title
      server: "Welcome, Guest"
      client: "Welcome, Sohail"
      → Render the same <title> and <meta> tags on the server and the client, so search engines, link previews and the first paint show the final values.