Measuring the back/forward cache with Application Metrics
TL;DR — The
bfcacheMetricsIntegrationmodels 3 bfcache signals as app metrics. The integration is opt-in and launched in JavaScript SDKs v11.
There is a moment every web user knows by feel. You click a link, read the page, hit Back, and the previous screen is just there. No spinner, no flash of white, no jitter.
This is the bfcache (back/forward cache) in action, and for most teams it feels invisible. Your dashboards can be green, your Web Vitals healthy, your LCP the best it has ever been, but if the bfcache doesn’t deliver that instantaneous feel that allows users to navigate back and forth without waiting, your users feel it and you would never know.
That blind spot is exactly what we went after. Shipping application metrics meant we could finally turn any browser signal we could name into a number you can chart, so we started hunting for the signals that matter but never surfaced with other telemetry data types (e.g. spans). The bfcache was at the top of the list. The result is the new bfcacheMetricsIntegration. It turns a decision the browser makes almost silently, thousands of times a day into something you can measure, track, and fix.
How the bfcache impacts critical experiences
When you navigate away from a page, the browser normally tears it down. Scripts stop, memory is freed, the DOM is gone. If you come back later the page is rebuilt from scratch, listeners fire, fetch calls fan out, and spinners spin.
The bfcache short-circuits all of that. The browser freezes it in place, a complete in-memory snapshot of the DOM, the JavaScript heap, the scroll position, all of it.
On a back or forward navigation, it thaws that snapshot and hands it straight back. The transition is effectively instant, because there is nothing to load. The page was never really gone.
This is not a niche optimization. Back and forward navigations are one of the highest-frequency paths on the web, and they dominate the flows where perceived speed could convert into business value. Take for example ecommerce product-to-listing bouncing, search-result back and forth, documentations, media browsing, and marketplaces. The payoff is also biggest for users on slower networks or devices, who would otherwise pay the full cost of a reload every time they hit Back. For these journeys, “how fast is the Back button” should be a first-class performance question, and often a bigger one than fresh page load.
The difference is easiest to feel side by side. A miss means rebuilding the whole page from scratch, refetching, re-rendering, and losing where the user was.
It’s more about discovery
Every performance tool is built around the page-load lifecycle, including Sentry’s. To your usual tooling, a bfcache hit is indistinguishable from nothing happening at all, which is why back/forward navigations sometimes go unnoticed.
There’s a paradox here. The better your bfcache works, the less data your existing tools collect, because success is silence. You cannot track what you cannot see, and the healthiest case here is the one that leaves no trace (pun intended).
What makes it trickier still is that the browser decides whether a page is eligible for bfcache based on heuristics that shift and drift over time, which can disqualify your pages unexpectedly.
The disqualifiers can be mundane. An unload listener, a Cache-Control: no-store header, an open connection, or a blocker inside an embedded iframe have all kept pages out of the cache before. By the time you read this, some of them may no longer apply, and new ones could have taken their place. You or a third-party script can add any of them without noticing.
So eligibility can regress with simple code changes, or without any code changes at all. Fighting the regression via tests or code reviews isn’t viable. This is meant to be actively tracked and fixed.
Application metrics really lend themselves to discovery in a way spans or logs don’t. Whenever a miss spikes, you can break it down by route, then release, then browser, until the culprit is revealed. Every “what about x” is just another query away, with no need to redeploy or add new instrumentation.
How it works
The browser already tells you everything. Both the pageshow event and notRestoredReasons API describe exactly whether a page was ineligible for the bfcache, and why.
The bfcacheMetricsIntegration models these signals as three application metrics (subject to browser support) each carrying some attributes:
browser.bfcache.navigationis a counter, one per back/forward navigation, carrying:browser.bfcache.outcome:hitormiss.browser.bfcache.not_restored_reason_count: how many reasons the browser reported.
browser.bfcache.not_restored(Chromium only) is a counter, one per not-restored reason on a miss, carrying:browser.bfcache.reason: the browser’s raw reason string, for exampleunload-listener,websocket,idbversionchangeevent,response-cache-control-no-store.browser.bfcache.frame: where the blocker lived,topfor the main document orchildfor a subframe.
browser.bfcache.reload.durationis a distribution, in milliseconds, of how expensive the fallback reload was when a back/forward navigation missed. This is the impact metric. It does not claim to know how fast the restore would have been. Instead, it measures what the miss actually cost the user so you can prioritize by real pain rather than by raw blocker count.
We settled on these three because together they answer the whole arc of a back/forward navigation: Did it restore? Why not? What did the miss cost?
How to use it
You can enable the integration with a one liner:
import * as Sentry from "@sentry/browser";
Sentry.init({
integrations: [
// other integrations...
Sentry.bfcacheMetricsIntegration(),
],
});The integration emits application metrics, so rather than hand you a pre-packaged dashboard that answers some questions and needs constant tweaking, you get to build your own.
Using agentic dashboard creation, you can tell it exactly what you would like to see using those metrics. Here are a few examples:
- “Using bfcache metrics, I would like to see my overall bfcache hit rate, and whether it is trending up or down over the last month.”
- “Using bfcache metrics, I would like to see which routes are causing the most bfcache misses, so I can prioritize fixing them first.”
- “Using bfcache metrics, I would like to see the top reasons for bfcache misses, globally or for a given route.”
You can tweak the dashboards further by chatting with the wizard until you are satisfied.
For the full setup and the complete list of metrics and attributes, see the bfcacheMetricsIntegration docs.
Start tracking your back button
The integration is opt-in and launched in JavaScript SDKs v11. Hit and miss outcomes work across modern browsers, so you can measure your bfcache health today. The detailed not-restored reasons are currently a Chromium-only enhancement, and that coverage widens on its own as more engines ship the notRestoredReasons API.
We are also extending bfcache awareness to features that never counted these navigations, like Core Web Vitals. A restored page fires no pageload, so those vitals never recorded it. Wiring bfcache in fills that gap, and it is the kind of coverage we would rather build in than leave for you to notice.