A content site adds a vendor exit-survey tag that registers an unload listener. Nothing breaks in testing. Over the following week, the share of back navigations that complete instantly collapses, origin requests rise about 15%, and the site's field largest contentful paint at the 75th percentile gets worse without any page becoming slower. Walk through what happened.
Show the full answer Hide the answer
What happens, step by step
The browser's back/forward cache freezes a whole page when the user navigates away — DOM, JavaScript heap, scroll position, in-flight component state — and restores it from memory on a back navigation. A restore skips the network, the parse, the framework boot and the data fetch entirely.
An unload listener makes a page ineligible to be frozen, because the listener's contract is that it runs when
the document goes away, and a frozen document has not gone away. Chrome reports this directly: the reason code
unload-listener appears in the notRestoredReasons field of PerformanceNavigationTiming, shipped from
Chrome 123 in 2024.
So from the moment the tag goes live, every back navigation becomes a full navigation: request, HTML, parse, hydrate, refetch.
Where it amplifies
On a content site the dominant movement is article → index → article, so back navigations are a large share of all navigations. Those were the cheapest ones in the system — served from the user's own memory — and they all land on the origin at once. A 15% rise in origin requests is consistent with that, and it concentrates on index and section pages, which are the most expensive to assemble.
The second amplifier is the data layer. A restored page keeps its fetched state. A reloaded page refetches, so the API tier sees the same multiple.
What the user sees
The index re-renders from the top. Scroll restoration becomes approximate rather than exact. An infinite-scroll feed loses the eight pages that had been loaded, so going back and continuing to read is no longer possible. Any in-page state — a chosen filter, a partially filled form, an expanded comment thread — is gone. None of this appears as an error, which is why testing passed.
Why the metric moved without any page getting slower
A restore from the back/forward cache counts as a navigation in field reporting, and it reports a near-zero largest contentful paint. Those values were pulling the distribution down. Removing them raises the 75th percentile while every individual page renders exactly as fast as before.
A field percentile is a property of a population, not of a page. The same illusion appears whenever a fast cohort leaves the sample, and it is the reason a regression investigation should start by asking what changed about who is being measured.
What stops it
- Measure the reason, not the symptom. Report
notRestoredReasonsfrom real-user monitoring and alert when any single reason appears in more than roughly 1% of navigations. Without this the cause is invisible. - Make third-party tags load through a wrapper that refuses to register
unload, and make that wrapper the only supported way to add a tag. A review gate catches the first tag and not the fourth. - Use the supported events.
pagehideandvisibilitychangegive a vendor everything an exit survey needs and keep the page eligible. - Note that
Cache-Control: no-storewas once a blanket disqualifier and Chrome has since narrowed that, allowing the cache for many no-store pages with a shorter lifetime and eviction on cookie or authorisation change (Chrome documentation, 2025). Chrome is also deprecating the unload event through a staged 2025 rollout. Both change, so verify against the browser's own docs rather than a blog post — including this one.
Common weak answers
- "Add a cache header." HTTP caching and the back/forward cache are different mechanisms; a
max-agedoes not restore a frozen heap. - "Preload the index page." Prefetching makes the reload faster and still costs a full boot and a refetch, and it adds load rather than removing it.
- "Ask the vendor for a faster script." Script speed is irrelevant. The listener's existence is the defect.
- "Roll back the tag and move on." Correct and insufficient: without the reason-code alert the next tag does the same thing.