Back/Forward Cache (bfcache)
What the back/forward cache is — the browser feature that freezes a whole page in memory for instant Back/Forward navigation — how it differs from the HTTP cache, what blocks eligibility, how to test it, and its real (indirect) relationship to Core Web Vitals and SEO.
The back/forward cache (bfcache) is a browser optimization that freezes a whole page — DOM, JavaScript heap, running state — in memory when you navigate away, so pressing Back or Forward can restore it instantly with no reload, no re-render, and no network requests, as long as the browser hasn't evicted that frozen snapshot first. It's a browser feature, not a search ranking factor: Google's own Core Web Vitals ranking docs never mention it. Its SEO relevance is indirect and scoped — a bfcache-restored navigation posts near-instant LCP and effectively zero CLS for the users who get one, which can improve your aggregate field Core Web Vitals on any site with meaningful Back/Forward traffic (1 in 10 desktop and 1 in 5 mobile navigations), but it doesn't guarantee your restore rate, your overall CWV rating, rankings, or conversion. The single biggest blocker is the unload event handler; the historically largest was Cache-Control: no-store, though Chrome now allows bfcache for many no-store pages conditionally as of its 2025 rollout. Test with Chrome DevTools for one-off lab checks, or the Chrome-only notRestoredReasons API for field data. Don't confuse bfcache with the HTTP cache, the browser's in-memory resource cache, a service worker's Cache Storage, or the old retired 'cached page' search feature.
Evidence for this claim The back-forward cache stores a complete page snapshot for instant history navigation. Scope: Current official or standards documentation. Confidence: high · Verified: web.dev: Back/forward cache Evidence for this claim Browser eligibility rules and APIs such as unload handlers can prevent bfcache use. Scope: Current official or standards documentation. Confidence: high · Verified: web.dev: bfcache eligibilityTL;DR — The back/forward cache (bfcache) is a browser feature that freezes a whole page in memory when you leave it, so pressing Back or Forward can bring it back instantly — no reload — as long as the browser hasn’t evicted that frozen page first. It’s a browser thing, not a Google ranking factor. But because a restored page loads near-instantly, it quietly improves your Core Web Vitals numbers on the Back/Forward navigations that do get restored, which is why a performance audit might tell you to “fix bfcache eligibility.”
What bfcache is
When you click the browser’s Back button, one of two things happens. Either the browser rebuilds the previous page from scratch — re-downloading files, re-running JavaScript, re-laying-out the whole thing — or it restores the page instantly, exactly as you left it. That instant version is the back/forward cache, or bfcache.
Here’s the trick: instead of throwing the old page away when you navigate off it, the browser freezes the entire page in memory — everything, including the running JavaScript — and keeps it on ice. If you come back soon and the browser still has that frozen page available, it un-freezes and shows you the exact page again — no network requests, no waiting. It’s a possible restore, not a guarantee: the browser can evict a frozen page from memory before you hit Back (low memory, a timeout, certain activity), in which case you just get a normal reload instead.
Google’s own one-line description says it plainly: bfcache is “a browser optimization that enables instant back and forward navigation.”
Why it’s not “the cache” you already know
This is the part people mix up. When you hear “cache” you probably think of the browser cache or HTTP cache — the files (images, scripts, stylesheets) your browser saves so it doesn’t re-download them. Bfcache is not that. Those caches store files; bfcache stores the whole living page, JavaScript state and all, as a snapshot. Chrome’s own documentation spells it out: bfcache “differs from browser cache and HTTP cache.”
It’s also not two other things people sometimes lump in with it: the browser’s
in-memory resource cache (compiled scripts and decoded images it keeps around
for your current session) and a service worker’s Cache Storage (request/response
pairs a site explicitly manages with caches.open()). Both of those can be active
on the same page as bfcache — they’re just separate mechanisms, not bfcache itself.
It’s also not the old “cached page” or “cached snapshot” feature that Google and Bing used to offer in search results (the little dropdown that showed you the version of a page they had on file). That was a search feature and it’s been retired. Bfcache is a live browser feature with nothing to do with search results.
Does bfcache help my SEO?
Not directly. Bfcache is not a Google ranking factor — Google’s own Core Web Vitals ranking documentation never mentions it. What it does is make your Back/Forward navigations load near-instantly for the visitors who actually get a restore, and browsers measure that as an excellent “page load.” So if a lot of your visitors hit Back and Forward (shopping, browsing search results, reading article to article), bfcache can improve your site’s overall Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. field numbers — which is one of many things Google says lines up with what its ranking systems reward. Two steps removed from “bfcache boosts rankings,” and it doesn’t guarantee your restore rate, your overall Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. rating, or your rankings — but it’s real, and it’s measurable.
Want the full picture — exactly what blocks bfcache, how to test it, and the precise (not oversold) Core Web VitalsWeb Vitals is Google's initiative (launched May 2020) for unified page-experience quality signals. Core Web Vitals — LCP, INP, and CLS — are the subset used in ranking; the rest (TTFB, FCP, TBT, Speed Index) are diagnostic, not ranking factors. connection? Switch to the Advanced tab.
Evidence for this claim The back-forward cache stores a complete page snapshot for instant history navigation. Scope: Current official or standards documentation. Confidence: high · Verified: web.dev: Back/forward cache Evidence for this claim Browser eligibility rules and APIs such as unload handlers can prevent bfcache use. Scope: Current official or standards documentation. Confidence: high · Verified: web.dev: bfcache eligibilityTL;DR — Bfcache is a whole-page, in-memory snapshot (DOM + JS heap + running state), not a re-fetchable HTTP response, the browser’s in-memory resource cache, or a service worker’s Cache Storage — that’s the #1 conceptual distinction to nail. On navigating away the browser pauses JS and freezes the page; on Back/Forward, if that frozen snapshot is still available, it un-freezes and re-displays instantly with zero network requests — but eviction is always possible, so treat a restore as likely, not guaranteed. It is not a documented Google Search ranking factor (Search Central’s Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. docs never mention it); its relevance is indirect and scoped, through field CWV measurement (mainly LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. and CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good.) on the navigations that do get restored — it doesn’t guarantee your restore rate, aggregate CWV rating, rankings, or conversion. The biggest eligibility blocker is the
unloadhandler (~18 percentage points of hit rate on Chrome); the historically largest wasCache-Control: no-store(blocking ~17% of mobile / ~7% of desktop history navigations), though Chrome now allows bfcache for manyno-storepages conditionally (evicted on auth/cookie change, still blocked by the same open-connection APIs) after its 2025 rollout. Open connections, timers, and observers should be closed/paused atpagehide/freezeand re-established atpageshow/resume;window.opener, permissions policies, and frames can also block it — check the per-frame reason in DevTools ornotRestoredReasonsrather than assuming. Test one-off with Chrome DevTools; diagnose in the field with the Chrome-onlynotRestoredReasonsAPI (anullresult isn’t proof of a restore, and reason text isn’t stable). Each browser has its own eligibility rules, and SPAs’ soft navigations don’t get the same treatment.
What bfcache actually is (the accuracy spine)
The single most important thing to get right: bfcache is a whole-page, in-memory snapshot, not a cached HTTP response. When you navigate away from a page, rather than tearing it down, the browser pauses JavaScript execution and freezes the entire page — the DOM, the JS heap, in-flight timers, the lot — and holds it in memory. If you press Back or Forward while that frozen snapshot is still available, the browser un-freezes it and re-displays the exact page you left, with zero network requests and zero re-render. That’s a possible restore, not a guarantee — the browser can evict the snapshot before you navigate back (memory pressure, a timeout, certain events), or a browser-specific rule can force a fresh load, in which case it’s just an ordinary history navigation instead. Google’s canonical framing is that bfcache is “a browser optimization that enables instant back and forward navigation.”
This is why conflating it with the HTTP/browser cache is the recurring competitor
error. The HTTP cache stores responses to previous requests — files it can
re-serve. Bfcache stores the live, running page. Chrome’s DevTools documentation
draws the line explicitly: bfcache “differs from browser cache and HTTP cache.”
You don’t “turn on” bfcache with cachingCaching stores a copy of a page or resource — in a browser, a CDN edge node, or a search crawler's own cache — so it can be served again without regenerating or re-downloading it. It isn't a direct ranking factor, but it feeds page speed and crawl efficiency. headers the way you configure HTTP
caching — the only place headers enter the picture is that Cache-Control: no-store used to disqualify a page (more on that below).
The same distinction holds against two other caches people sometimes conflate
with bfcache: the browser’s in-memory resource cache (compiled scripts and
decoded images kept around for the current session) and a service worker’s
Cache Storage (explicit request/response pairs a site manages itself via
caches.open()). Both can be active on the same page at the same time as
bfcache — neither one is bfcache, which is specifically the frozen page
instance, not cached assets or intercepted responses.
One more disambiguation worth stating because it still causes confusion: bfcache has nothing to do with the old “cached page” search feature that Google (and Bing) once exposed in results. That was a stored snapshot of a page in the search indexStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed., and it’s been retired. Bfcache is a client-side, renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM.-engine feature.
How common are Back/Forward navigations, really?
This is not a niche edge case. Per web.dev, “1 in 10 navigations on desktop and 1 in 5 on mobile are either back or forward.” On any site with repeat/back-forward flows — e-commerce category-to-product-and-back, search results, paginated contentPagination splits a large set of content — product listings, blog archives, search results — across multiple sequentially numbered URLs. For SEO, each paginated page should be crawlable, indexable, and self-canonical; Google no longer uses rel=prev/next, but Bing still does., article-to-article reading — that’s a large slice of real navigations you can make near-instant.
Browser support
“All major browsers include a bfcache, including Chrome since version 96, Firefox and Safari.” Firefox and Safari have had their own, longer-running bfcache implementations; all Chromium-based browsers (Edge, Brave, Opera, Arc) inherit Chrome’s. Microsoft’s Edge policy documentation describes the same feature: when navigating away from a page, its current state (document tree, script, and so on) may be preserved in the back-forward cache, and if the browser navigates back the page may be restored from it and displayed in the state it was in before being cached. It’s enabled by default in Edge; the only off switch is an enterprise policy an IT admin controls, not a site owner.
The important caveat: each browser’s bfcache applies its own eligibility rules. A page that passes Chrome DevTools’ “Test back/forward cache” is not guaranteed to be eligible in Firefox or Safari. Treat a Chrome pass as necessary, not sufficient.
What blocks bfcache eligibility
The unload event — the single biggest blocker
If you take one thing from this article: stop using the unload event. web.dev
puts it with rare emphasis for a Google doc: “Never use the unload event.
Ever!” On Chrome, unload handlers cost roughly an 18-percentage-point
reduction in bfcache hit rate — by far the largest self-inflicted disqualifier.
There are two reasons Chrome is actively deprecating it. First, it’s the biggest
bfcache blocker. Second, unload is extremely unreliable to begin with: on mobile
it frequently doesn’t fire at all, because tabs get backgrounded and killed and the
browser prioritizes bfcache over firing unload. So the event you’re relying on
for “cleanup” often never runs and it’s blocking a real performance win.
The fixes:
- Replace
unloadwithpagehide. Thepagehideevent fires in every caseunloaddoes, plus when a page enters the bfcache — so it’s a strict upgrade. Usevisibilitychangefor reliable “user is leaving” cleanup. - Detect a bfcache restore with
pageshow. Listen forpageshowand checkevent.persisted— if it’strue, the page was restored from bfcache, which is your cue to refresh stale data or re-count a pageview. - Proactively block unload listeners with the
Permissions-Policy: unload=()response header, which prevents anyunloadhandlers from being registered at all. Chrome is gradually migrating the default policy toward deny (aPermissions-Policyfor unload shipped from Chrome 115).
Cache-Control: no-store — historically the largest, now nuanced
This is the freshness point most competitor content gets wrong. Historically,
Cache-Control: no-store was the largest single reason pages were excluded
from bfcache — Chrome’s own figures put it at roughly 17% of history navigations
on mobile and 7% on desktop. Many sites set no-store defensively to avoid
serving a stale page, but Google’s argument is that this rationale weakens under
bfcache: a bfcache restore isn’t loading a stale cached response, it’s
re-displaying the exact live page almost as if the tab had been left open.
So Chrome changed the behavior — but conditionally, not universally. Experiments
began in Chrome 116, with the final rollout to 100% of users over March and
April 2025: Chrome now allows bfcache for many no-store pages, subject to
specific safety conditions rather than a blanket exception. Per Chrome’s own
docs, this comes with real constraints — the page is evicted from bfcache if
authentication state or cookies change while it’s frozen (so a signed-out or
cookie-cleared visitor won’t see a stale signed-in snapshot), and a fixed list of
APIs — the same open-connection APIs covered below (IndexedDB, WebSocket, WebRTC,
and the rest) — still exclude a no-store page from bfcache the same way they
would any other page. This is Chrome-specific behavior on a specific version
range, not a rule you can assume other browsers, or older Chrome versions, follow
— pull the current DevTools/notRestoredReasons report for the browser and
version you’re actually testing rather than trusting a fixed rule of thumb.
The practical takeaway: any guide (including older versions of this one) that
lists no-store as an unconditional, permanent bfcache blocker is stale — and so
is treating it as fully solved. If freshness genuinely matters for a page,
Chrome’s docs suggest no-cache or a short max-age (e.g. max-age=60) rather
than no-store.
Open connections, observers, and other blockers
At the moment of navigation, certain open resources can still block eligibility — and exactly which ones, and whether they block outright or just get closed-and-reconnectable, is browser- and version-specific. Treat the list below as examples of a pattern, not a fixed, permanent blocker list:
- In-progress
fetch()/XMLHttpRequestrequests. - Open
IndexedDBtransactions. - Open
WebSocket/WebRTCconnections, timers, and observers (MutationObserver,IntersectionObserver, and similar). This is an actively improving area — recent Microsoft Edge release notes show an open WebSocket now being closed when a page enters bfcache (rather than blocking caching outright), with reconnection recommended via thepageshowevent’sevent.persistedcheck. That mirrors Chrome’s broader trend of reducing blockers rather than just excluding pages.
The general pattern to build to, rather than memorizing a fixed list: close or
pause open connections, timers, and observers in your pagehide/freeze
handling, and re-establish them in your pageshow/resume handling when
event.persisted is true. That pattern survives a browser changing exactly which
APIs block eligibility outright versus which ones it now just suspends and lets
you reconnect.
window.opener, permissions policies, and frames. A window.opener
reference, certain permissions policies, and embedded (same- or cross-origin)
iframesHTML element that displays one webpage inside another — how embeds work. can also affect eligibility — this is on the checklist I distilled in
Ahrefs’ CLS guide and in
Chrome’s docs. But don’t assume which one is the actual cause from a generic
checklist: Chrome’s DevTools panel and the notRestoredReasons API both report
blocking reasons per frame — the top frame and each iframe separately —
because the frame actually responsible for a block isn’t always the top-level
page. Pull the real reason from that frame-level report for the browser you’re
testing rather than guessing from a general list.
Getting the lifecycle event/state sequence right
Mixing up what each lifecycle event actually proves versus merely suggests is the second most common correctness bug here, after the eligibility mistakes above:
| Event / state | Signal | What it actually means | What to do |
|---|---|---|---|
pagehide (event.persisted === true) | Intent to cache | The browser is attempting to freeze the page for bfcache — not a confirmed cache entry | Close/pause connections, timers, and observers here; don’t assume the page will actually be restored |
freeze | Paused | JS execution is paused; the page can still be evicted before any restore | No action beyond what you already did at pagehide |
| (no event) possible eviction | — | The browser can drop a frozen page from memory at any point — memory pressure, a timeout, a browser rule — and there’s no event that fires for this | Don’t rely on cleanup code running later; do it unconditionally at pagehide/freeze |
pageshow (event.persisted === true) | Confirmed restore | The only reliable signal that a bfcache restore actually happened | Refresh time-sensitive/sensitive state, reconnect closed connections, count exactly one analytics view |
resume | Resumed | JS execution is unpaused after a confirmed restore | Reconnect anything paused at freeze |
The practical rule: treat pagehide.persisted as intent, not proof — the page
might still get evicted before you’d ever see a restore. Only
pageshow.persisted === true is evidence a restore happened. Do your cleanup
unconditionally at pagehide/freeze (it’s cheap and safe even on an ordinary
navigation), and do your restore-specific work only at pageshow/resume, gated
on event.persisted, so you don’t refresh data or double-count an analytics view
on a plain fresh load.
How to test and diagnose bfcache
Lab / one-off: Chrome DevTools
Open DevTools → Application → Background services → Back/forward cache, then
click “Test back/forward cache.” Chrome auto-navigates to chrome://terms/ and
back, then reports either success or a specific list of blocking reasons. Good for
checking one URL at a time.
Field / production: the notRestoredReasons API
Previously the only way to check eligibility was that manual, one-URL-at-a-time
DevTools test — there was no way to see why real users’ navigations were blocked.
The notRestoredReasons property on PerformanceNavigationTiming (shipped in
Chrome 123+) closes that gap: it reports the specific blocking reason(s) for the top
frame and same-origin iframes in real field dataPerformance metrics captured from real users, not lab tests..
const nav = performance.getEntriesByType('navigation')[0];
console.log(nav.notRestoredReasons);A few things to get right when you use it, straight from Chrome’s own API guidance:
- It’s Chrome-only (123+). Firefox and Safari don’t expose an equivalent field API, so you still need manual spot-checks in those browsers to know your restore rate there.
- A
nullresult is ambiguous, not a green light. It can mean the page was restored, or it can mean the browser simply didn’t collect a reason — Chrome’s own docs say not to treatnullas proof of a successful restore. - Reason text isn’t a stable contract. Don’t hard-code string matches against it; group and trend by reason instead, since the exact wording can change across Chrome versions.
Practically: pull notRestoredReasons alongside pageshow.persisted restore
rates before and after a fix ships, compare the trend rather than a single
snapshot, and pair it with a manual DevTools/lab pass in Firefox and Safari for
the browsers the API can’t reach. This is the tool to reach for when diagnosing
bfcache at scale in RUM/production, rather than checking URLs one by one — just
don’t treat it as the whole picture.
Bfcache and Core Web Vitals — the precise relationship
Here’s the nuance most competitor content blurs, and the angle worth owning.
How a bfcache restore is measured. Browsers (and therefore CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. field data) count a bfcache-restored navigation as an extremely fast “page load” — near-instant LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. and, when the page is implemented correctly (nothing has to re-lay-out), effectively zero additional CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good., because there’s no re-render. In DebugBear’s real-world comparison, a bfcache-restored page hit LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. around 100ms versus ~427ms for an uncached load. This is exactly why bfcache shows up as a lever on CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. and LCP in my own Ahrefs CLS checklist, where I put it simply: “Make sure your pages are eligible for bfcache. The back/forward cache keeps pages in the browser cache. It allows for instant loading of a page that was already loaded, meaning no layout shifts will happen.”
Two scope caveats worth being precise about, since this is where competitor
content tends to overclaim. First, this only affects navigations CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. classifies
as back/forward (its navigation-type dimension) — it says nothing about your
first-visit or reload navigations, which are the majority of traffic on most
sites. Second, a restore improving the measured experience for the users who
get one is not the same as a guarantee: a user who’s evicted from bfcache (see
the lifecycle table above) still gets a normal, unimproved load, so bfcache
eligibility work moves your restore rate among Back/Forward navigations, not
a fixed share of your total traffic — and it doesn’t guarantee your aggregate
field Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. rating, your rankings, or your conversion rate. It’s a
real, measurable lever with a specific, bounded scope, not a general performance
or SEO fix.
Is bfcache a ranking factor? No. This is the defensible, differentiated claim. Google’s own Core Web Vitals ranking documentation does not mention bfcache at all. The honest chain of influence is: bfcache eligibility → better field CWV numbers (mainly LCP/CLS) on back/forward navigations → Core Web VitalsWeb Vitals is Google's initiative (launched May 2020) for unified page-experience quality signals. Core Web Vitals — LCP, INP, and CLS — are the subset used in ranking; the rest (TTFB, FCP, TBT, Speed Index) are diagnostic, not ranking factors. is one input among many “page experience” signals Google says align with what its ranking systems already reward. That’s a materially weaker, more precise claim than “bfcache boosts rankings” — and it’s the claim competitor content should be making but usually isn’t careful about. Bfcache is also, correctly, a renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM.-engine feature, not a crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. feature — it has nothing to do with how GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. or BingbotBingbot is Microsoft Bing's primary web crawler — the bot that discovers, fetches, and renders pages to build the Bing index. That index also powers Yahoo, DuckDuckGo, Ecosia, and Microsoft Copilot, so Bingbot's reach is far wider than Bing's own search-market share. crawl your pages, which is why there’s no “Bing’s take on bfcache for SEO” the way there is for robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere. or sitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing..
SPAs and soft navigations. Bfcache operates on real browser navigation and history events. A single-page app’s client-side “soft” route change (a JS-driven view swap that doesn’t trigger an actual browser navigation) is not a bfcache event and doesn’t get the same treatment. Some RUM tools’ attempts to attribute Core Web Vitals to soft navigations can create CrUX-vs-RUM measurement mismatches — worth a callout if you’re auditing a JS-framework site.
How common are bfcache blockers in the wild?
The HTTP Archive Web Almanac
tracks this, and it’s a live, moving area — not settled old news. Back in the 2022
edition, at least ~22% of mobile pages were ineligible for bfcache on the unload and
no-store criteria alone. Since then, unload handler usage has been declining
across site tiers and devices — but Cache-Control: no-store usage has risen
(the 2025 chapter puts it around 23% of sites, up from ~21% in 2024, attributed
partly to more authenticated/personalized experiences and stricter compliance
requirements).
The counter-intuitive finding worth citing: larger, higher-traffic sites are
disproportionately more likely to block their own bfcache. On the top 1,000 sites,
around 28% of desktop pages and 20% of mobile pages still use unload handlers,
versus only ~11% desktop / ~10% mobile across all sites — often because bigger
sites carry more legacy analytics and unload-dependent code. The sites with the most
back/forward traffic to lose are frequently the ones still getting in their own way.
Where this sits
Bfcache is one performance lever among several in this cluster. Its payoff shows up
in Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. field data —
specifically in Cumulative Layout ShiftCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good.
and Largest Contentful PaintLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good.,
since a restored page re-displays instantly with no re-layout. It’s distinct from
cachingCaching stores a copy of a page or resource — in a browser, a CDN edge node, or a search crawler's own cache — so it can be served again without regenerating or re-downloading it. It isn't a direct ranking factor, but it feeds page speed and crawl efficiency., which stores files rather than
a live page snapshot, even though the two share the Cache-Control header as a
touchpoint. There’s no direct tie to
Interaction to Next PaintInteraction to Next Paint — the input-to-paint latency at the 75th percentile of a page's interactions. ≤200 ms is good.,
so I won’t force one.
AI summary
A condensed take on the Advanced version:
- Bfcache = a whole-page, in-memory snapshot (DOM + JS heap + running state), not a re-fetchable HTTP response, the browser’s in-memory resource cache, or a service worker’s Cache Storage. On navigating away the browser pauses JS and freezes the page; on Back/Forward, if that frozen snapshot is still available, it un-freezes and re-displays instantly with zero network requests — eviction is always possible, so a restore is likely, not guaranteed. Chrome’s docs: it “differs from browser cache and HTTP cache.” It is also not the old retired “cached page” search feature.
- Not a ranking factor, and scoped. Google’s own Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. ranking docs never mention bfcache. The real chain is indirect: bfcache eligibility → better field CWV numbers (mainly LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good./CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good.) on the Back/Forward navigations that get restored → CWV is one page-experience input Google says aligns with its ranking systems. It doesn’t guarantee restore rate, aggregate CWV, rankings, or conversion — and it only touches navigations CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program. classifies as back/forward.
- Scale: “1 in 10 navigations on desktop and 1 in 5 on mobile are either back or forward.” Support: Chrome since v96, plus Firefox and Safari — but each browser has its own eligibility rules.
- Biggest blocker: the
unloadevent (“Never use theunloadevent. Ever!”) — ~18 percentage points of Chrome’s hit rate. Replace withpagehide+visibilitychange; detect restores withpageshow/event.persisted; block unload viaPermissions-Policy: unload=(). Cache-Control: no-storewas the historically largest blocker (~17% mobile / ~7% desktop history navigations). Chrome now allows bfcache for manyno-storepages conditionally after its March–April 2025 rollout — evicted if auth/cookies change, still blocked by the same open-connection APIs — and only on Chrome; older guides callingno-storean absolute blocker are stale, and so is treating it as fully solved.- Other blockers: in-progress fetch/XHR, timers, observers, open IndexedDB,
WebSocket/WebRTC (close/pause at
pagehide/freeze, reconnect atpageshow/resume),window.opener, permissions policies, and frames — pull the per-frame reason from DevTools/notRestoredReasonsrather than assuming. - Lifecycle correctness:
pagehide.persistedis intent, not proof; onlypageshow.persisted === trueconfirms a restore. Do cleanup unconditionally atpagehide/freeze; do restore-specific work (refresh sensitive data, reconnect, count one analytics view) only atpageshow/resume. - Testing: Chrome DevTools “Test back/forward cache” (one-off lab); the
Chrome-only
notRestoredReasonsAPI (Chrome 123+) for field dataPerformance metrics captured from real users, not lab tests. —nullisn’t proof of a restore, reason text isn’t stable, and Firefox/Safari need manual spot-checks. ComparenotRestoredReasonsandpageshow.persistedrates before/after a fix. - SPAs: soft client-side navigations aren’t bfcache events and don’t get the same treatment (a source of CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program.-vs-RUM mismatch).
- Adoption (Web Almanac):
no-storeusage rising (~21%→23%),unloadusage higher on the largest sites (~28% desktop on top 1,000) — big sites often block their own bfcache.
Official documentation
Primary-source documentation on bfcache. Note the source split: bfcache lives in the Chrome / renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM.-engine docs (Google’s institutional voice on it), not in Google Search Central — that separation is itself the point.
Google / Chrome
- Back/forward cache — the canonical doc: definition, mechanism, the 1-in-10 / 1-in-5 stat, and the
unloadguidance. - Test back/forward cache — DevTools testing steps, top blockers, and the explicit “differs from browser cache and HTTP cache” line.
- Enabling bfcache for Cache-Control: no-store — the 2025 policy change, the 17% / 7% figures, and the rollout timeline.
- Deprecating the unload event — why
unloadis being phased out and thePermissions-Policymigration. - Back/forward cache notRestoredReasons API — field diagnosis on
PerformanceNavigationTiming(Chrome 123+). - Understanding Core Web Vitals and Google Search results — Google Search Central’s ranking doc; cited here as evidence that it never mentions bfcache.
Microsoft / Edge
- Microsoft Edge policy: BackForwardCacheEnabled — Edge’s definition, the same
unloadcaveat, and the enterprise-policy off switch.
MDN / web standards
- bfcache — MDN Glossary — general web-dev definition and the HTTP-cache distinction.
- Monitoring bfcache blocking reasons — MDN — using
notRestoredReasonsin practice.
Quotes from the source
On-the-record statements from the source documentation. Each link is a deep link that jumps to the quoted passage on the source page.
Google / Chrome — what bfcache is and why it matters
- “Back/forward cache (or bfcache) is a browser optimization that enables instant back and forward navigation.” — web.dev. Jump to quote
- “1 in 10 navigations on desktop and 1 in 5 on mobile are either back or forward. With bfcache enabled, browsers could eliminate the data transfer and time spent loading for billions of web pages every single day!” Jump to quote
- “All major browsers include a bfcache, including Chrome since version 96, Firefox and Safari.” Jump to quote
Google / Chrome — the #1 optimization rule
- “Never use the
unloadevent. Ever!” — web.dev. Jump to quote
Chrome DevTools — bfcache is not the HTTP cache
- “Back/forward cache differs from browser cache and HTTP cache.” — Chrome DevTools docs. Jump to quote
Microsoft Edge — the same feature, the same caveat
- “When navigating away from a page, its current state (document tree, script, and so on) may be preserved in the back-forward cache. If the browser navigates back to the page, the page may be restored from the back-forward cache and displayed in the state it was in before being cached.” — Microsoft Edge policy documentation. Jump to quote
Patrick Stox (me) — bfcache as a CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. lever
- “Make sure your pages are eligible for bfcache. The back/forward cache keeps pages in the browser cache. It allows for instant loading of a page that was already loaded, meaning no layout shifts will happen.” — my Ahrefs CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. guide. Read it
unload event. Ever!” line were
matched as exact substrings against the live page. The Chrome DevTools
“differs from browser cache and HTTP cache” line and the Microsoft Edge policy
wording are quoted from those docs. Chrome’s Cache-Control: no-store figures
(~17% mobile / ~7% desktop) and the ~18-percentage-point unload hit-rate cost are
reported as documented facts in the article body rather than as verbatim quotations,
since they weren’t independently re-verified as exact substrings this pass. There is
no on-the-record statement from a Google or Bing Search-team representative about
bfcache — the correct attribution for any Google-side statement is the Chrome/web.dev
engineering docs, not a Search liaison. Bfcache eligibility checklist
A pass to confirm your pages can enter the back/forward cache:
- No
unloadevent listeners anywhere on the page (yours or third-party scripts). This is the single biggest blocker. - Cleanup/analytics code moved from
unloadtopagehideandvisibilitychange. - A
pageshowlistener checksevent.persistedto refresh stale data and correctly re-count pageviews after a bfcache restore. - Consider the
Permissions-Policy: unload=()response header to block anyunloadlisteners from being registered. - Review
Cache-Control: no-store— if you set it defensively, confirm you still need it (Chrome 2025+ allows bfcache for manyno-storepages conditionally — evicted on auth/cookie change, still blocked by the same open-connection APIs; don’t assume other browsers or versions match); if freshness matters, preferno-cacheor a shortmax-age. - No open connections, timers, or observers left hanging at navigation
time — in-progress fetch/XHR, open IndexedDB transactions, WebSocket/WebRTC,
MutationObserver/IntersectionObserver(close/pause atpagehide/freeze, re-establish atpageshow/resumewhenevent.persistedis true). - No
window.openerreferences, restrictive permissions policies, or blocked frames keeping the page ineligible — check the per-frame reason in DevTools/notRestoredReasonsrather than assuming which one applies. - Lab test the page in Chrome DevTools → Application → Back/forward cache → “Test back/forward cache.”
- Field-diagnose at scale with
notRestoredReasonsin your RUM (Chrome-only; anullresult isn’t proof of a restore, and reason text isn’t a stable contract — trend by reason, don’t hard-code strings). - Don’t assume a Chrome pass = eligible everywhere — spot-check Firefox and Safari, which apply their own rules.
Bfcache cheat sheet
What blocks it — and the fix
| Blocker | Why | Fix |
|---|---|---|
unload event handler | #1 blocker (~18pt hit-rate cost); unreliable anyway | Use pagehide + visibilitychange; Permissions-Policy: unload=() |
Cache-Control: no-store | Historically the largest (~17% mobile / ~7% desktop) | Chrome (2025+) allows many no-store pages conditionally — evicted on auth/cookie change, still blocked by the same open-connection APIs; other browsers/versions may still block outright |
In-progress fetch/XHR, timers, observers | Open work at navigation, browser/version-specific | Close/pause at pagehide/freeze; re-establish at pageshow/resume |
| Open IndexedDB transaction | Open connection at navigation | Close/commit before navigation |
| Open WebSocket / WebRTC | Open connection | Close on pagehide; reconnect on pageshow |
window.opener, permissions policy, frames | Page tied to opener or a blocked frame | Avoid / rel="noopener"; check the per-frame reason, don’t assume |
Events to know
| Event | When it fires | Use it for |
|---|---|---|
pagehide (persisted) | Every case unload does, plus on bfcache entry | Intent signal — cleanup, the unload replacement (not proof of a restore) |
freeze | On entering bfcache | No action beyond pagehide cleanup |
pageshow (persisted) | On load and on bfcache restore | The only confirmed-restore signal — refresh state, reconnect, count one view |
resume | On a confirmed restore | Reconnect anything paused at freeze |
visibilitychange | Tab hidden/shown | Reliable “user is leaving” work |
Test it
| Scope | Tool |
|---|---|
| One URL, lab | DevTools → Application → Back/forward cache → “Test back/forward cache” |
| Real users, field | notRestoredReasons on PerformanceNavigationTiming — Chrome-only (123+); null isn’t proof of a restore |
| Firefox / Safari | No field API — spot-check manually |
Fast facts
- Bfcache = whole live page in memory, not files, not the resource cache, not service worker Cache Storage. Chrome: it “differs from browser cache and HTTP cache.”
- Not a Google ranking factor — Search Central’s CWVGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. docs never mention it. A restore improves measured LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good./CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. for the users who get one; it doesn’t guarantee restore rate, aggregate CWV, rankings, or conversion.
- Support: Chrome 96+, Firefox, Safari — each with its own rules.
- 1 in 10 desktop / 1 in 5 mobile navigations are Back/Forward.
Bfcache anti-patterns (and the myths behind them)
“Bfcache is just my HTTP/browser cache — I configure it with Cache-Control.”
No. Bfcache is a distinct, whole-page in-memory snapshot; Chrome’s docs say it
“differs from browser cache and HTTP cache.” CachingCaching stores a copy of a page or resource — in a browser, a CDN edge node, or a search crawler's own cache — so it can be served again without regenerating or re-downloading it. It isn't a direct ranking factor, but it feeds page speed and crawl efficiency. headers only matter insofar as
no-store used to disqualify a page. You don’t “turn bfcache on” with cache headers.
“Bfcache is a Google ranking factor, so fixing it boosts rankings.” Not established by any official Google Search source. Its Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. ranking doc doesn’t mention bfcache. The real relationship is indirect (better field LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good./CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. on Back/Forward navigations), which is a weaker, more precise claim.
“Cache-Control: no-store always blocks bfcache, permanently.” True
historically — and still the biggest historical cause — but no longer
categorically true after Chrome’s full 2025 rollout of no-store-safe bfcache.
Guides that predate the change are stale on this exact point — but so is treating
it as fully solved: Chrome’s exception is conditional (evicted on auth/cookie
changes, still blocked by the same open-connection APIs) and Chrome-specific, not
a universal green light.
“A page that fires pagehide with persisted: true was definitely cached.”
No — that’s intent, not proof. The browser can still evict the page before you’d
ever see a restore. Only pageshow.persisted === true confirms a restore
actually happened.
“If it passes the Chrome DevTools bfcache test, it’s eligible everywhere.” False. Chrome, Firefox, and Safari each apply their own restrictions; a pass in one doesn’t guarantee eligibility in another.
“unload is a fine way to run exit/cleanup code, so I’ll keep it.” No — Chrome
calls it extremely unreliable (it often doesn’t fire on mobile at all) and is
actively deprecating it via a Permissions-Policy, precisely because it’s the single
biggest bfcache blocker. Use pagehide + visibilitychange.
“Bfcache helps my SPA the same way it helps a multi-page site.” Not without qualification. Bfcache is tied to real browser navigations; a client-side “soft” route change isn’t the same event and doesn’t get the same treatment — which also causes CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program.-vs-RUM mismatches on SPA-heavy sites.
“Bfcache is solved / old news, not worth auditing.” Contradicted by the Web
Almanac’s own data: no-store usage is rising, and unload usage remains
markedly higher on the largest, highest-traffic sites — the ones with the most
Back/Forward traffic to lose.
Patrick's relevant free tools
- Hosting Checker — Find a domain's public IP network, CDN or edge platform, DNS and mail-host evidence, and response transfer facts without pretending a proxy reveals the origin.
- Page Speed Test & Core Web Vitals Checker — One sentence tells you whether a page passes Core Web Vitals and what to fix first — real Chrome user data (CrUX) with a Lighthouse lab fallback, mobile and desktop side by side, loudly-labeled data sources, and prioritized diagnostic fixes. Plus a bulk origin scorecard with CSV export.
- Core Web Vitals History & Competitor Comparison — Chart 40 weeks of real-Chrome-user Core Web Vitals — p75 LCP, INP, CLS, FCP, and TTFB from the Chrome UX Report — and compare up to 5 origins or URLs on one chart. Plus a competitor Leaderboard that ranks curated groups of SEO and page-speed tools on each metric. Pass/fail scorecards, mobile vs desktop, shareable links, CSV export.
Tools for testing and diagnosing bfcache
- Chrome DevTools — Back/forward cache panel. Application → Background services →
Back/forward cache → “Test back/forward cache.” Auto-navigates to
chrome://terms/and back, then reports success or the exact blocking reasons. Best for a one-off, single-URL lab check. - The
notRestoredReasonsAPI (Chrome 123+). Readperformance.getEntriesByType('navigation')[0].notRestoredReasonsin your RUM to see real users’ blocking reasons — including for same-origin iframesHTML element that displays one webpage inside another — how embeds work. — at scale, not just in a manual lab test. - PageSpeed InsightsPageSpeed Insights (PSI) is a free Google tool at pagespeed.web.dev that reports two kinds of data for a URL: real-user field data from the Chrome UX Report and a single Lighthouse lab run with the 0–100 Performance score. Only the field Core Web Vitals are what Google uses for ranking. / LighthouseLighthouse is Google's free, open-source tool that audits a page under simulated lab conditions and scores it 0–100 across Performance, Accessibility, Best Practices, and SEO. It's lab data — useful for debugging, not a ranking signal. / CrUXChrome User Experience Report — Google's public dataset of real-world (field) performance data from eligible Chrome users. It's the official field-data source behind the Core Web Vitals program.. Where a “back/forward cache” recommendation or flag usually surfaces first in an audit, and where the field CWVGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. benefit of a bfcache-eligible site shows up.
Permissions-Policy: unload=()header. Not a test tool but the enforcement lever: set it to actively prevent anyunloadlisteners (including third-party ones) from being registered.- Web Almanac (HTTP Archive) Performance chapter. For benchmarking how common bfcache blockers are across the web by device and site-rank tier.
DevTools says an unload handler blocked restoration
Symptom: the Back/forward cache test names unload. Likely cause: first- or
third-party code registered an unload listener. Fix: replace cleanup with
pagehide/visibilitychange, add Permissions-Policy: unload=() where appropriate,
and rerun the test after every affected script changes.
A restored page shows stale user data
Symptom: Back returns instantly but account state, inventory, or another dynamic
value is stale. Likely cause: the page resumed its frozen state without refreshing
time-sensitive data. Fix: listen for pageshow, check event.persisted, and
refresh only the required data. Confirm both ordinary loads and restores behave.
Analytics misses or doubles Back/Forward views
Symptom: pageviews differ from actual history navigations. Likely cause:
analytics runs only on the original load or runs twice without distinguishing a
restore. Fix: handle pageshow explicitly and use event.persisted to count the
restored navigation once.
Lab passes but field restoration stays low
Symptom: a sampled URL passes DevTools while RUM reports many non-restores.
Likely cause: other templates, browsers, real-user states, or intermittent open
connections add blockers. Fix: collect notRestoredReasons, group by reason and
template, and reproduce the dominant field case rather than extrapolating one pass.
Prove a bfcache fix landed
Eligibility test
Test to run: DevTools → Application → Back/forward cache → Test back/forward cache. Expected result: the page restores successfully with no blocking reason. Failure interpretation: at least one eligibility blocker remains. Monitoring window: immediate for Chrome on the tested state. Rollback trigger: the fix breaks cleanup, security, or required application behavior.
Restore-behavior test
Test to run: navigate away and Back, then verify pageshow receives
event.persisted === true and time-sensitive data refreshes. Expected result: one
instant restore, correct data, and one analytics view. Failure interpretation: the
page either was not cached or restore handling is incomplete. Monitoring window:
immediate across representative signed-in/out states. Rollback trigger: stale
sensitive data or duplicated actions after restore.
Field-reason test
Test to run: monitor PerformanceNavigationTiming.notRestoredReasons in RUM.
Expected result: the targeted blocker declines for affected templates without a
new dominant blocker replacing it. Failure interpretation: the lab sample did not
represent production or another dependency owns the issue. Monitoring window:
enough real Back/Forward traffic to compare the same template mix. Rollback trigger:
a material application or data-integrity regression tied to the change.
Bfcache metrics worth keeping
Restore hit rate
Metric: eligible Back/Forward navigations restored from bfcache. What it tells
you: how often users receive the instant-navigation benefit. How to pull it: RUM
navigation entries and pageshow.persisted, segmented by browser and template.
Benchmark / realistic range: establish your own baseline because browser rules,
page state, and navigation mix differ. Cadence: weekly and after lifecycle changes.
Non-restore reasons
Metric: history navigations grouped by notRestoredReasons. What it tells you:
which blockers cost the most real restores. How to pull it: the
PerformanceNavigationTiming API in supporting browsers. Benchmark / realistic
range: target zero for blockers your own code controls, while labeling browser/API
coverage. Cadence: weekly triage.
Restored-navigation correctness
Metric: errors, stale-data incidents, and duplicate analytics/actions after a
restore. What it tells you: whether higher eligibility preserves application
correctness. How to pull it: RUM error events, application monitoring, and
analytics QA keyed to pageshow.persisted. Benchmark / realistic range: zero
known correctness or privacy failures. Cadence: continuous alerting and release QA.
Resources worth your time
My related writing
- What Is Cumulative Layout Shift (CLS) & How To Improve It — where I list bfcache eligibility as a CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good.-improvement tactic, with the short blocker checklist.
- What Are Core Web Vitals (CWVs) & How To Improve Them — the parent metrics, with bfcache as one CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. lever among many.
- The Beginner’s Guide to Technical SEO — where web performance fits in the bigger picture.
My speaking
- How Search Works (SlideShare) — my walkthrough of crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor., renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed., and ranking, for context on why a renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM.-engine feature like bfcache sits outside Search’s ranking signals. (My standing disclaimer applies: “This is my understanding of systems… not going to be 100% complete or accurate.”)
Official
- Back/forward cache (web.dev) — the canonical doc.
- Enabling bfcache for Cache-Control: no-store and Deprecating the unload event (Chrome for Developers) — the two changes that make older guides stale.
- Understanding Core Web Vitals and Google Search results (Google Search Central) — the ranking doc that, tellingly, never mentions bfcache.
From around the industry
- bfcache — MDN Glossary — accurate, engine-neutral definition and the HTTP-cache distinction.
- What Does The Back/Forward Cache Mean For Site Speed? (DebugBear) — the most data-driven piece in this space, with a real-site log and a concrete LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. comparison (~100ms cached vs ~427ms uncached).
- Back Forward Cache Explained (SpeedVitals) — mechanics, eligibility, testing, and CWVGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. impact.
- Back/Forward Cache: What It Is and How to Implement It (NitroPack) — implementation-focused, for a CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms./hosting audience.
- Performance Game Changer: Browser Back/Forward Cache (Smashing Magazine) — a solid technical deep-dive, but note it predates the 2025
no-storechange. - Web Almanac — Performance chapter (2025) (HTTP Archive) — the real-world adoption data on
unloadandno-storeprevalence by device and site-rank tier.
Stats worth citing
- Back/Forward navigations are common: “1 in 10 navigations on desktop and 1 in 5 on mobile are either back or forward” — the scale of the opportunity, not a niche case. Source
unloadcosts ~18 percentage points of bfcache hit rate on Chrome — which is why it’s the #1 blocker and being deprecated. SourceCache-Control: no-storewas the largest historical blocker — roughly 17% of history navigations on mobile and 7% on desktop — before Chrome’s March–April 2025 rollout allowed bfcache for manyno-storepages. Source- A bfcache restore is near-instant: DebugBear measured LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. around 100ms for a restored page versus ~427ms for an uncached load. Source
- Big sites block themselves the most: on the top 1,000 sites, ~28% of desktop
and ~20% of mobile pages still use
unloadhandlers, versus ~11% / ~10% across all sites — andno-storeusage is rising (~21%→23%). Source
Test yourself: Back/Forward Cache (bfcache)
Five quick questions on what bfcache is, what blocks it, and how it relates to SEO. Pick an answer for each, then check.
Back/Forward Cache (bfcache)
The back/forward cache (bfcache) is a browser feature that freezes a whole page in memory when you navigate away, so pressing Back or Forward can restore it instantly — no reload, no re-render, no network requests — as long as the browser hasn't evicted that frozen page first. It's a browser optimization, not a search ranking factor.
Related: Core Web Vitals, CLS, Caching for SEO
Back/Forward Cache (bfcache)
The back/forward cache — bfcache — is a browser-level performance optimization that makes clicking the browser’s Back or Forward button feel instant. Instead of destroying a page’s JavaScript state and re-requesting everything when you navigate away, the browser freezes the entire page — DOM, JS heap, in-flight timers — as a snapshot in memory. If you return while that frozen snapshot is still available, the browser un-freezes and re-displays the exact page as it was, with no network requests and no re-render, rather than reloading it from scratch. That’s a possible restore, not a guarantee — the browser can evict a frozen page from memory (low memory, a timeout, certain activity) before you navigate back, in which case you get a normal reload instead. Google’s one-line framing: bfcache is a browser optimization that enables instant back and forward navigation.
The distinction to get right: bfcache is not the same as the HTTP cache or browser disk cache — and it’s also distinct from two other caches people sometimes lump in with it: the browser’s in-memory resource cache (compiled scripts and decoded images kept for the session) and a service worker’s Cache Storage (request/response pairs a site manages itself). The HTTP cache stores responses to previous requests (files); bfcache stores the entire live, in-memory page — including running JavaScript state — and can coexist with the other two. Chrome’s own documentation states directly that bfcache differs from browser cache and HTTP cache. It’s also unrelated to the old “cached page” search feature Google and Bing once offered — that was a user-facing snapshot of a page in the indexStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed., now retired, and has nothing to do with bfcache.
For SEO, the relationship is indirect and scoped. Bfcache is not a documented Google Search ranking factor — Google’s own Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. ranking documentation never mentions it. What it does is make a back/forward navigation post near-instant LCPLargest Contentful Paint — render time of the largest visible image or text block, relative to when the page started loading. ≤2.5 s (at the 75th percentile) is good. and effectively zero CLSCumulative Layout Shift — a unitless score for unexpected visual movement, taken from the largest burst (session window) of layout shifts, not the lifetime sum. ≤0.1 is good. for the navigations that actually get restored, which can improve your site’s aggregate field Core Web VitalsGoogle's three real-user UX metrics — LCP (loading), INP (responsiveness), and CLS (visual stability) — used by Google's ranking systems, with no official weight attached, measured on field data. numbers on any site with meaningful back/forward traffic — but it doesn’t guarantee your restore rate, aggregate CWV rating, rankings, or conversion. The biggest thing that blocks a page from being bfcache-eligible is the unload event handler; the historically largest was the Cache-Control: no-store header, though Chrome now allows bfcache for many no-store pages conditionally (evicted on auth/cookie change, still blocked by the same open-connection APIs) as of its 2025 rollout.
Related: Core Web Vitals, CLS, Caching for SEO
Build-time retrieval analysis plus live signals for this exact article. The automatic chunk report includes a deterministic readiness score and is ready without a model download.
Search Console
sampleGA4 traffic (28d)
sampleCloudflare traffic (7d)
sampledCrUX field data (28d, phone)
sampleGoogle NLP entities
localChangelog
Revision history
Compare the published article with an archived editorial snapshot. Added and removed words are shown only after you open a comparison.
Updated Jul 17, 2026.
Editorial summary and recorded change details.Summary
Tightened restore-guarantee language, distinguished bfcache from the browser resource cache and service worker Cache Storage, scoped Chrome's 2025 no-store exception to its actual conditions, generalized the open-connections/observers blocker list into a close-at-pagehide/reconnect-at-pageshow pattern, added a pagehide-vs-pageshow lifecycle event/state matrix, added per-frame diagnostics for opener/permissions/frame blockers, and bounded the Core Web Vitals/CrUX claims to the navigations that actually get restored.
Change details
-
Added a lifecycle event/state matrix (pagehide = intent, pageshow.persisted = confirmed restore) so cleanup and restore-specific code aren't triggered on the wrong signal.
-
Scoped Chrome's 2025 Cache-Control: no-store exception to its actual conditions (auth/cookie eviction, explicit API exclusions) instead of describing it as fully resolved.
-
Bounded the Core Web Vitals/SEO section to say a bfcache restore improves measured LCP/CLS for restored navigations only, without guaranteeing restore rate, aggregate CWV, rankings, or conversion.