HP4003 (html-rewritten) means the HTML the browser received differs from what
your origin server produced: a CDN, a proxy or an edge function rewrote it on
the way. React then hydrates markup it did not render. Turn off HTML
rewriting (minification, email obfuscation, injection) for server-rendered
pages.
| Code | HP4003 |
|---|---|
| Name | html-rewritten |
| Default severity | Error |
| Group | Changes made outside React |
| What it means | The HTML the browser received differs from what the origin server produced (CDN minification, proxies, edge functions). |
What the HP4003 html rewritten finding means
React expects the DOM to be exactly the HTML it rendered on the server. Any layer between your server and the browser that edits the HTML breaks that:
- Minification removes whitespace or comments. Whitespace between elements is a text node React renders, and comments mark Suspense boundaries.
- Email obfuscation replaces email addresses in the text with a placeholder and a decoding script.
- Injection adds scripts, banners or analytics tags to the markup.
It is an error by default, because the whole page is affected, not one component.
When only whitespace changed, the difference is usually reported on the element
as HP1015 with the cause
HTML rewritten by a CDN or proxy. hydration-proof raises
its confidence when the response carries CDN headers such as cf-ray,
x-amz-cf-id, x-served-by, x-cache or via.
Likely causes
- A CDN feature that minifies HTML (for example "Auto Minify").
- Email address obfuscation turned on for the zone.
- A reverse proxy, edge function or middleware that rewrites the response body.
- A hosting feature that injects scripts into every page.
All of them are the CDN or proxy cause.
How to fix it
Disable HTML rewriting (minification, email obfuscation, injection) for server-rendered pages at the CDN or proxy.
- Compare a page served through the CDN with the same page from the origin
(for example
curlon both URLs and a diff). - Turn off HTML minification. JavaScript and CSS minification are fine; the HTML React hydrates must stay as rendered.
- Turn off email obfuscation and script injection for the routes React renders, or render email addresses in a way the feature skips.
- If an edge function must change the HTML, change the data the page renders instead, so React renders the final markup on both sides.
To reproduce the problem locally, test the app through the CDN URL:
npx hydration-proof test --url https://staging.example.com --route /When the rewrite is expected
If a proxy adds markup outside React's root on purpose, ignore it with
ignore.selectors or an ignore.issues rule with code: "HP4003" and a
reason (see ignoring findings).
checks.externalChanges: false turns off every HP4xxx check.