# Hydration Proof documentation > Detect React hydration errors in CI: hydration-proof compares real server HTML with the hydrated DOM in Next.js, Remix and Astro, then explains the cause. Two packages: `hydration-proof` (CLI and Node API; install with `npm install -D hydration-proof`) and `eslint-plugin-hydration-proof` (ESLint rules; install with `npm install -D eslint-plugin-hydration-proof`). Docs: https://hydration.jscrate.dev. Source: https://github.com/re-sohail/hydration-proof. This file contains every documentation page in order. The index with one line per page is https://hydration.jscrate.dev/llms.txt. --- # Quick start > Install hydration-proof, run it against your Next.js, Remix or Astro app, and read the report: every React hydration mismatch, its cause and the fix. Source: https://hydration.jscrate.dev/docs/quick-start Last updated: 2026-09-18 hydration-proof finds React hydration errors by loading every route of your server-rendered app in a real browser and comparing the server HTML with what React renders on the client. Install it, run `npx hydration-proof test`, and it tells you which element differs, both values, the likely cause and the fix. ## Install hydration-proof Add it as a dev dependency, then download the browser once: ```bash npm install -D hydration-proof npx hydration-proof install # downloads Chromium ``` It needs Node.js 22.18 or newer, and works with npm, pnpm, Yarn (including Plug'n'Play) and Bun. There are no install scripts: browsers are only downloaded by the `install` command, into Playwright's shared cache, so a project that already uses the same Playwright version does not download them again. To catch the same mistakes in your editor, add the [ESLint plugin](https://hydration.jscrate.dev/docs/eslint) as well: ```bash npm install -D eslint-plugin-hydration-proof ``` ## Run your first test ```bash npx hydration-proof init # creates hydration-proof.config.ts npx hydration-proof test ``` For Next.js, React Router, Remix and Astro apps that is all. hydration-proof: 1. discovers your routes from `app/`, `pages/` and the build output, 2. builds the app if there is no build yet, and starts it on a free port, 3. loads every route and compares the server HTML with the hydrated DOM, 4. exits with code `1` if it found a problem. Vite SSR and custom Node servers are detected too. Any other setup works with `--url` (see [adapters](https://hydration.jscrate.dev/docs/adapters)). ## Read the report Each finding in the terminal shows the issue code, the element, the value on each side, the source line and a fix: ```text Hydration Proof — 20 pages on http://localhost:3000 ✓ /pricing 684ms ✖ /dashboard 1.1s 1 error HP1001 Text differs between server and client (timezone difference, 95%) #last-login in LastLogin server: "Signed in at 5:00 AM" client: "Signed in at 10:00 AM" app/dashboard/LastLogin.tsx:14:10 → Pass an explicit timeZone to the formatter (the same on both sides), or format the date after mount. Report: .hydration-proof/report/report.html ``` - `HP1001` is a stable [issue code](https://hydration.jscrate.dev/docs/issues/hp1001) with its own page. - `timezone difference, 95%` is the [likely cause](https://hydration.jscrate.dev/docs/causes/timezone) and how sure hydration-proof is. Open `.hydration-proof/report/report.html` for everything at once: filters, the server and client values side by side, the code, screenshots with the element outlined, and a timeline of the page. [Reports](https://hydration.jscrate.dev/docs/reports) covers every output format. ## Test an app that is already running ```bash npx hydration-proof test --url http://localhost:3000 --route / --route /pricing ``` With `--url`, nothing is built or started, and only the routes you name are tested. Add `--sitemap` to test the pages in your sitemap, or `--crawl` to follow links from the tested pages. ## Test development and production builds Development builds give exact source lines. Production builds show what your users get, including attribute mismatches React 19 never reports in production. Test both in one run: ```bash npx hydration-proof test --mode both ``` ## Add it to CI ```yaml title=".github/workflows/hydration.yml" - run: npm ci - run: npx hydration-proof install --with-deps - run: npx hydration-proof test ``` Or let `npx hydration-proof init --ci github` write the workflow for you. [Detect hydration errors in CI](https://hydration.jscrate.dev/docs/ci) covers GitHub Actions, GitLab and CircleCI, sharding, baselines and budgets. ## Configure it The config file is optional for most apps. When you need it, it is TypeScript with completion: ```ts title="hydration-proof.config.ts" import { defineConfig } from "hydration-proof"; export default defineConfig({ routes: { // Example values for dynamic routes dynamic: { "/products/[id]": ["1", "42"] }, exclude: ["/api/**"], }, // The environments your users have scenarios: [ { name: "default" }, { name: "dark-mobile", colorScheme: "dark", viewport: "mobile" }, { name: "karachi", locale: "ur-PK", timezoneId: "Asia/Karachi" }, ], }); ``` See [configuration](https://hydration.jscrate.dev/docs/configuration) for every option, and [scenarios](https://hydration.jscrate.dev/docs/scenarios) for signed-in pages. ## Related - [How hydration-proof works](https://hydration.jscrate.dev/docs/how-it-works): the six snapshots it compares - [What is hydration in React?](https://hydration.jscrate.dev/docs/guides/what-is-hydration) - [All React hydration error messages](https://hydration.jscrate.dev/docs/errors), decoded - [Common causes of hydration errors](https://hydration.jscrate.dev/docs/causes) and their fixes - [The CLI](https://hydration.jscrate.dev/docs/cli): every command and flag --- # How it works > How hydration-proof detects mismatches: it captures each page at six stages in a real browser, compares them, and explains every finding with a likely cause. Source: https://hydration.jscrate.dev/docs/how-it-works Last updated: 2026-09-18 Here is how hydration-proof detects mismatches: it loads each page in a real browser, captures it at six stages, from the bytes the server sent to the settled page, and compares neighboring stages to find where a difference started. A small runtime, injected before any page script, connects to React the way React DevTools does. Your app is not changed. ## Connecting to React hydration-proof drives the browser with Playwright. Before any script of the page runs, it injects a runtime of about 29 KB that stays out of the app's way. React looks for `__REACT_DEVTOOLS_GLOBAL_HOOK__` when it loads, in development and in production builds. The runtime provides that hook, or wraps an existing one so React DevTools and Fast Refresh keep working, and React then tells it about every renderer and every commit. Inside a commit, React calls the hook before it reports recoverable errors. That lets the runtime capture those errors with their component stack, even when the app (or Next.js) installs its own error handler. ## How hydration-proof detects mismatches ### The six stages | Stage | How it is captured | | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 1. Server HTML | The body of the document response the browser received, read from the same navigation (never fetched twice) | | 2. Parsed HTML | The same bytes loaded again in a page where a Content Security Policy blocks scripts. This is the browser's own parser, so repairs, `