TOC
What is bfcache?
Back/forward cache (or bfcache) is a browser optimization that enables instant back and forward navigation.
– https://web.dev/bfcache/
There are two important concepts to know about bfcache right away:
- bfcache is not really a “cache”: where a browser cache or CDN cache might temporarily “store” a page’s assets to help them load faster in the future, bfcache is a literal snapshot of the entire, fully-rendered page, including all assets, the completed layout and the full JS heap.
- bfcache relates solely to pages that have already been visited by the user and therefore can be reached via the browser’s Back and Forward buttons.
To make bfcache work, the browser stores a fully rendered version of visited pages in its cache. Then, when the user clicks the Back or Forward button, simply displaying the cached page to the user, rather than initiating a complete page request again:
Here is a side-by-side example of loading a page, then hitting the Back, then the Forward, buttons:
The user experience is markedly improved, allowing for a near-instant Back and Forward page transitions, which allows for a much faster, more enjoyable browsing session.
And this not only makes the page load experience faster, but also:
- Saves the user’s data plan, because there is no bandwidth required to display the cached page;
- Saves the user’s battery life, because there is no fetching, parsing, rendering, etc. either;
- Reduces overall server and CDN requests, because no page assets need to be requested again, and
- Eliminates any KPI-related issues, because the page is already fully rendered (so, no CLS!).
Even things like an unresolved setTimeout
or a Promise
will be paused while the page is cached and resumed once the cached page is revisited. (Be aware, however, of possible network-related complications.)
As with all caches, however, there is a maximum cache size, meaning, as the cache fills, older pages will be removed (FIFO).
How do I add bfcache?
bfcache is available by default in all major browsers (Safari > 1.0, Firefox > 1.5 and Chrome > 96).
Unless you are doing something to break it…
How do I not break bfcache?
Again, bfcache is enabled by default in all modern browsers, so you don’t have to do anything to add it, but there are a number of blockers that will prevent a page from being cached.
To avoid blocking bfcache:
-
Never use an
unload
event handler- This handler has not been reliable for years, and continues to be problematic today, especially on mobile devices, and so will block a page from being cached.
- The preferred method is to use the
pagehide
event handler. This does not prevent bfcache from caching this page.
-
Limit use of the
Cache-Control: no-store
header- This literally tells the browser to not cache this page…
no-store
should be used only for pages that contain sensitive data, which should not be cached.- If the page contains time-sensitive data, something that should be updated or validated, you can use
Cache-Control: max-age=0
instead. max-age=0
does not prevent bfcache from caching this page, but you might need to use thepageshow
event to refresh the page’s content when the user returns to it.
-
Avoid creating
window.opener
references- If at all possible, do not use
window.open()
ortarget="_blank"
to open pages. - This creates a
window.opener
reference in the new page, which will block the page from being cached. - If you must use either
window.open()
ortarget="_blank"
, then also add arel="noopener"
to prevent thewindow.opener
reference. This does not prevent bfcache from caching this page.
- If at all possible, do not use
-
Pause all network activity
- If the page interacts with any network resource after the user navigates away, then the browser cannot know what state it should return to.
- And if the page interacts with any API, such as IndexedDB, freezing that could harm other pages that need to use it.
- Close, disconnect or pause any network or API connections when either the
pagehide
orfreeze
event fires. - This includes any IndexedDB connection, any in-progress
fetch()
orXMLHttpRequest
, or any open WebSocket or WebRTC connection. - These can all be resumed if the
pageshow
orresume
event fires.
How can I test & debug bfcache?
Event listeners
bfcache does have an API, which includes the pagehide
and pageshow
events. (Chrome also offers a Page Lifecycle API, but when this article was written, this is Chrome-only.)
These events can be monitored with something like these events:
/* Add these to a page, go to a new page, then hit your Back/Forward buttons to see the results in your console */ window.addEventListener('pagehide', (event) => { console.log('pagehide:', event); }); window.addEventListener('pageshow', (event) => { console.log('pageshow:', event); });
The event returned by both listeners above will contain, among other properties:
type
:pagehide
|pageshow
persisted
:true
|false
timeStamp
: when event happened
DevTools
You can easily test bfcache using DevTools:
- In Chrome, open the page you want to test.
- Open DevTools, go to the Application tab and, below Background Services, click Back/Forward cache, then click the Test back/forward cache button:
- If DevTools found any bfcache errors, it will tell you, but the supporting evidence is not exactly helpful:
- Knowing that
unload
handlers are blocking bfcache is helpful, but not giving any guidance as to where theunload
handler is added, is not… - This test is still under development, so hopefully it will continue to improve with time.
- For now, you would need to investigate and try to find the errors within your own code base.
Lighthouse
Lighthouse can also test bfcache:
- In Chrome, open the page you want to test.
-
Open DevTools, go to the Lighthouse tab, select the settings you want (definitely Navigation and Performance, as well as your choice of Mobile or Desktop), then click the Test back/forward cache button:
Lighthouse recommends using an Incognito window to prevent any other tabs or windows from interfering with IndexedDB. - If Lighthouse found any bfcache errors, they will be found under Diagnostics, inside of an expandable section titled Page prevented back/forward cache restoration, but, like the DevTools bfcache test above, the supporting evidence is not exactly helpful:
- Knowing that
unload
handlers are blocking bfcache is helpful, but not giving any guidance as to where theunload
handler is added, is not… - This test is still under development, so hopefully it will continue to improve with time.
- For now, you would need to investigate and try to find the errors within your own code base.
Notes
- Limitations/drawbacks of bfcache:
- Size: The size of the cache is limited by device memory. When the cache is full, the browser will remove pages that have not been visited recently.
- Persistence: When a browser closes, bfcache is cleared.
- Security: The cache is not secure. Sensitive information that is stored in bfcache can be accessed by anyone who has access to the device.
- Most browsers do not see a bfcache restore as a page view, and therefore most analytics do not see it as a page view.
- To record bfcache restores as a page view, you would need to manually trigger this. For GA, you could add something like this:
window.addEventListener('pageshow', (event) => { // Send another pageview if the page is restored from bfcache. if (event.persisted) { gtag('event', 'page_view'); } });
- To record bfcache restores as a page view, you would need to manually trigger this. For GA, you could add something like this:
- Performance metrics may actually get worse.
- This is because, as with page views, performance tools may also not record the new page view.
- And since even normal Back/Forward page navigation tend to be faster (because of browser and HTTP cache), if these are no longer being tracked, performance KPIs will lose some “faster” data, which will look like things got worse…
- One suggestion is to annotate page load metrics with their navigation type (
navigate
,reload
,back_forward
, orprerender
). - Then only
navigate
KPIs should be monitored to get a true data set for the user’s page load experience.
Resources
- Back/forward cache – Philip Walton, Barry Pollard, web.dev
- Test back/forward cache -Sofia Emelianova, Chrome Developers
- Back Forward cache : What you need to know – Murshid Muzamil, blog
- Performance Game Changer: Browser Back/Forward Cache – Barry Pollard, Smashing Magazine
- WebKit Page Cache I – The Basics – WebKit.org
- Using Firefox 1.5 caching – MDN Web Docs
- Lighthouse bfcache Audit – GitHub
- Back/forward cache: web-exposed behaviour – Google Doc
Happy caching,
Atg