# HP4003: HTML was rewritten between the server and the browser

> HP4003 (html-rewritten) means a CDN, proxy or edge function changed the HTML your server produced before the browser got it. Turn off that HTML rewriting.

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

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](https://hydration.jscrate.dev/docs/issues/hp1015) with the cause
[HTML rewritten by a CDN or proxy](https://hydration.jscrate.dev/docs/causes/cdn). 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](https://hydration.jscrate.dev/docs/causes/cdn) cause.

## How to fix it

Disable HTML rewriting (minification, email obfuscation, injection) for
server-rendered pages at the CDN or proxy.

1. Compare a page served through the CDN with the same page from the origin
   (for example `curl` on both URLs and a diff).
2. Turn off HTML minification. JavaScript and CSS minification are fine; the
   HTML React hydrates must stay as rendered.
3. Turn off email obfuscation and script injection for the routes React
   renders, or render email addresses in a way the feature skips.
4. 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:

```bash
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](https://hydration.jscrate.dev/docs/ignoring)).
`checks.externalChanges: false` turns off every HP4xxx check.

## Related

- [HP1015: whitespace differs between server and client](https://hydration.jscrate.dev/docs/issues/hp1015)
- [HTML rewritten by a CDN or proxy](https://hydration.jscrate.dev/docs/causes/cdn)
- [HP4001: the page was modified before React hydrated](https://hydration.jscrate.dev/docs/issues/hp4001)
- [HP4002: a browser extension changed the page](https://hydration.jscrate.dev/docs/issues/hp4002)
- [Errors that only happen in production](https://hydration.jscrate.dev/docs/guides/hydration-error-only-in-production)
