The Back Button Problem: When bfcache Restores a Page Without Re-Checking Consent
A visitor accepts analytics, browses to a second page, goes back, and opens the privacy settings to withdraw consent. Then they press forward again, back to the page they came from. The page appears instantly, because the browser restored it from memory instead of reloading it. The analytics tag is still running, because the page was frozen in the state it had when the visitor left, with consent still granted. The withdrawal never reached it.
This is the back-forward cache, bfcache, and about one in ten Chrome navigations is a history navigation that can use it. The browser freezes the page's DOM and JavaScript heap when the visitor navigates away, and restores it exactly as it was when they come back. Nothing reloads. No load event fires. The consent platform never runs again, so it never sees the new choice.
What bfcache actually does
When a page enters bfcache, the browser suspends it whole: the DOM, the JavaScript heap, the timers, the open connections. The page is not running, but it is not gone either. When the visitor returns, the browser thaws it and the page continues from the exact point it stopped. From the visitor's perspective this is fast, and that is the point. From the consent platform's perspective, the page never left.
The key detail is what does not happen on restore. The load event does not fire. The scripts do not run again. The consent check that runs on a normal page load simply does not run, because there was no page load. A consent implementation that only checks on load is blind to every bfcache restore.
The one event that fires
One event does fire on restore: pageshow, with its persisted property set to true. That is the hook. A consent platform that listens for pageshow and re-reads the consent state when persisted is true will catch the change. A platform that does not listen will not. The fix is a few lines of code: on pageshow, if the event says the page came from bfcache, re-check the consent state and re-apply it to the tags.
The same hook handles the reverse case. A visitor who rejects, navigates away, and comes back should find the tags stopped. If the page was frozen with the tags running, the restore has to stop them. The pageshow handler has to do both directions, not just the one that adds tags.
The two things that break it
Two things keep a page out of bfcache entirely, and both are worth knowing. The first is an unload event listener. A page that listens for unload will not be cached, because the browser cannot guarantee the page will behave correctly on restore. The second is a Cache-Control header with no-store. Either one disables bfcache for the page, which solves the consent problem by removing the fast path, and costs the visitor the speed. Most sites should not disable bfcache to fix consent. They should handle the restore.
Test it directly. Open the site, accept consent, navigate to a second page, open the settings and withdraw, then press forward. Watch the network on the restored page. If a consent-dependent request fires after the withdrawal, the pageshow handler is missing or broken. The test takes a minute, and it is the only way to know, because the banner will never show the problem.
Keep reading: how consent state stays coherent across domains, and how consent state carries across subdomains cover the nearby cases in this series.
Frequently asked questions
What is bfcache and why does it affect consent?
The back-forward cache freezes a page when the visitor navigates away and restores it exactly as it was when they come back, without reloading. No load event fires, so a consent check that only runs on load never runs on restore, and the page keeps the old consent state.
How common are bfcache restores?
About one in ten Chrome navigations is a history navigation that can use bfcache. That is a large share of real browsing, and it is the share where a consent change made in another tab or page can go unnoticed on the restored page.
What event fires when a page comes back from bfcache?
The pageshow event, with its persisted property set to true. A consent platform should listen for pageshow and re-read the consent state when persisted is true, then re-apply it to the tags. The handler has to work in both directions, starting and stopping tags.
Does an unload listener stop bfcache from working?
Yes. A page with an unload event listener will not enter bfcache, and neither will a page served with Cache-Control no-store. Both disable the fast path, which fixes the consent problem at the cost of speed. Handling the pageshow event is the better fix.