Hydration Proof

Search documentation

Find a page or section

Fix the Cloudflare Auto Minify hydration error

Your server sent one page. The browser received another.

A Cloudflare Auto Minify hydration error can happen when a CDN changes your server's HTML before it reaches the browser. React then hydrates markup the server did not render. Turn off HTML rewriting for server-rendered pages and test through the CDN again.

Symptoms

The page works locally but fails behind the CDN. You may see:

Hydration failed because the server rendered text didn't match the client.
Text content does not match server-rendered HTML.
Minified React error #418; visit https://react.dev/errors/418

hydration-proof reports whitespace differences as HP1015 and other changed HTML as HP4003. A CDN response header can help identify where the change happened.

Why a Cloudflare Auto Minify hydration error happens

React may need whitespace between text and an element, as in Hello{" "}<strong>world</strong>. If a minifier removes that space, the browser receives different HTML. Removing React's HTML comments can also break adjacent text and Suspense boundaries.

Check these CDN features:

FeatureWhat it changesTurn it off
Auto Minify (HTML)Removes whitespace and commentsCloudflare deprecated Auto Minify on August 5, 2024. A zone that still has it on can turn it off through the API, as Cloudflare's Turn off Auto Minify page shows
Email Address ObfuscationReplaces visible email addresses with a link and adds a decode scriptSecurity, Settings, Client-side abuse, Email Address Obfuscation: Off. A configuration rule can turn it off for some paths only
Rocket LoaderDefers all JavaScript until after rendering, rewriting the page's scriptsSpeed, Settings, Content Optimization, Rocket Loader: Off. data-cfasync="false" before src excludes one script
Other proxies and edge functionsMinify, inject banners or analytics, rewrite linksCheck the proxy's HTML settings

See Cloudflare's docs for Email Address Obfuscation and Rocket Loader.

How to fix it

  1. Disable HTML minification for the affected routes.
  2. Disable Email Address Obfuscation or exclude those routes.
  3. Disable Rocket Loader if it changes your app's script loading.
  4. Purge the CDN cache, then test the public URL again.

Cached HTML can preserve the old problem, so do not skip the cache purge.

Fix an iOS format-detection hydration mismatch

On iOS, Safari can turn phone numbers in text into links. That changes the DOM before hydration. Disable automatic detection with a meta tag:

index.html
<meta name="format-detection" content="telephone=no" />

In the Next.js App Router, set it through the metadata API:

app/layout.tsx
import type { Metadata } from "next";
 
export const metadata: Metadata = {
  formatDetection: {
    telephone: false,
    email: false,
    address: false,
  },
};

If you want a phone number to be a link, render a tel: link yourself. Test this behavior on an iPhone; desktop browser checks may not reproduce it.

Catch it with ESLint

A CDN setting is not code, so no lint rule can catch it.

Catch it in CI

Test the same routes through the origin and public CDN URL:

npx hydration-proof test --url https://origin.example.com --route / --route /contact
npx hydration-proof test --url https://www.example.com --route / --route /contact

If only the public URL fails, inspect the CDN settings. See CI for checking a staging deployment.