# 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.

Source: https://hydration.jscrate.dev/docs/issues/hp1014
Last updated: 2026-09-18

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.

| | |
| --- | --- |
| Code | `HP1014` |
| Name | `head-mismatch` |
| Default severity | Warning |
| Group | DOM mismatches |
| What it means | Metadata, 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:

| Change                                                                             | What the finding shows                        |
| ---------------------------------------------------------------------------------- | --------------------------------------------- |
| Hydration added a `<title>` with a new value                                       | The server title and the added one            |
| A `<meta>` tag (by `name`, `property`, `http-equiv` or `itemprop`) got new content | The server `content` and the new one          |
| A stylesheet `<link>` from the server HTML was removed                             | Its `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

- A title or description built from [browser storage](https://hydration.jscrate.dev/docs/causes/storage) or
  another [browser-only API](https://hydration.jscrate.dev/docs/causes/browser-api).
- A [locale](https://hydration.jscrate.dev/docs/causes/locale) or [time](https://hydration.jscrate.dev/docs/causes/time) formatted into
  the title.
- Data the client fetched again: [different data](https://hydration.jscrate.dev/docs/causes/data).

## 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:

```tsx title="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:

```tsx title="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](https://hydration.jscrate.dev/docs/ignoring).

## Example

```text
  ⚠ /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.
```

## Related

- [Do hydration errors hurt SEO?](https://hydration.jscrate.dev/docs/guides/hydration-errors-seo)
- [HP1001: text differs](https://hydration.jscrate.dev/docs/issues/hp1001)
- [HP1015: whitespace differs](https://hydration.jscrate.dev/docs/issues/hp1015)
- [Configuration: which checks run](https://hydration.jscrate.dev/docs/configuration)
