Hydration Proof

Search documentation

Find a page or section

HP9009: The page never became quiet

HP9009 (ready-timeout) means the page kept changing, or your ready selector or function never passed, before the timeout. How to set the ready options.

HP9009 (ready-timeout) means the page hydrated, but its ready conditions were not met before the timeout: the DOM kept changing, or your ready selector or function never passed. The final snapshot was taken anyway and may be early. Set ready options that fit the page: a longer timeout, a shorter quiet period or a selector.

CodeHP9009
Nameready-timeout
Default severityWarning
GroupTest run problems
What it meansThe ready conditions (quiet DOM, selector, function) were not met before the timeout.

What the HP9009 ready timeout finding means

After hydration, hydration-proof waits for the page to settle before it takes the stable snapshot. hydration-proof never waits for "network idle". A page counts as settled when:

  1. the element in ready.selector exists, if you set one;
  2. the page function in ready.function returns a truthy value, if you set one;
  3. no DOM change or React commit happened for ready.quietMs (400 ms by default).

All three must happen within ready.timeout (30 seconds by default). If they do not, the snapshot is taken at the timeout and the page gets this warning:

The page kept changing until the timeout; the stable snapshot may be early.

Likely causes

  • Animations driven by JavaScript, carousels, tickers or a clock that updates the DOM more often than quietMs.
  • Polling or live data that re-renders the page every few hundred milliseconds.
  • A ready.selector that never appears, or a ready.function that never returns true, for example after a change to the page.
  • A slow page that settles, but after the timeout.

How to fix it

The issue code's advice is to increase the timeout or provide ready.selector for pages with continuous updates. In practice, pick by situation:

SituationFix
The page settles, but slowlyRaise ready.timeout, or pass --timeout
The page updates all the timeLower ready.quietMs for that route, below the interval of the updates
The content you care about arrives lateSet ready.selector or ready.function, so the snapshot waits for it
The selector or function never passesFix it, or remove it

A route object can set its own ready options, so the rest of the app keeps the defaults:

hydration-proof.config.ts
import { defineConfig } from "hydration-proof";
 
export default defineConfig({
  routes: {
    paths: [
      "/",
      {
        path: "/live-scores",
        ready: { quietMs: 150, selector: "#scoreboard" },
      },
    ],
  },
  ready: { timeout: 45_000 },
});

When the updates can be turned off for tests, a scenario can do it before any page script runs, for example with localStorage or initScripts (see scenarios). If none of this fits, ignore code: "HP9009" for the route with a reason (ignoring findings).