intermediate 3 min answer

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.

bfcacheback-navigationthird-party-scriptsfield-metricscore-web-vitals
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 notRestoredReasons from 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. pagehide and visibilitychange give a vendor everything an exit survey needs and keep the page eligible.
  • Note that Cache-Control: no-store was 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-age does 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.