Imagine this…
A user is browsing your website. They go to your product page. Then to your pricing page. Then back to your product page as they forgot to check if you offer that specific feature. Finally, they navigate forward to your pricing page and finish their order.
As it turns out, it’s a pretty common scenario.
Chrome usage data shows that 1 in 10 (10%) navigations on desktop and 1 in 5 (20%) on mobile are either back or forward.
Truly spectacular numbers.
But…
The more important thing is - how can you guarantee that after navigating back and forward to your pages, they load immediately?
Enter back/forward cache (or bfcache).
In the following lines, you will learn everything about bfcache and how to implement it to improve speed and perceived performance.
Spoiler alert: it’s easier than you think.
Bfcache is a feature that allows browsers to create and store a snapshot of an already visited web page in their in-memory. So the next time a visitor navigates back or forward to it, the browser can display it immediately.
The whole behind-the-scene process looks like this…
When a visitor requests to load a specific page, the browser goes through the following process:
If the back/forward cache isn’t enabled for the specific page, it means that every time you leave it and then navigate back to it, the browser will have to go through the whole 5-step process.
And that takes time.
On the contrary, with bfcache enabled, the browser “freezes” the page with all of its resources, so the next time you re-visit it, the browser won’t need to waste time rebuilding and will be able to load it instantly.
The following Addy Osmani’s video illustrates best how fast a web page loads with and without bfcache:
As you can see from the video, the loading time is almost non-existent. On top of that, bfcache will reduce your visitors' data usage as they won’t have to re-download the same resources repeatedly.
And while all of these benefits sound incredible, a certain question might still bother you:
I already have an HTTP cache set up for my website. Do I need bfcache as well?
Here’s the answer…
Put simply, bfcache is a snapshot of the entire page stored in-memory (including the JavaScript heap), whereas the HTTP cache includes only the previously requested resources.
And as Google claims:
Not all resources are allowed to be cached in the HTTP Cache. For instance, some sites don’t cache the HTML document itself, but only the resources. As a result, every time a visitor loads a specific page, the browser needs to re-download the document.
Another reason back/forward cache can be faster is the difference between in-memory and disk cache.
It’s true that loading resources from the disk cache (HTTP cache) could be much faster than requesting them over the network. But there’s an extra boost from not even having to read them from disk and fetching the entire page directly from the browser’s in-memory.
All of them - Chrome, Safari, Firefox, Opera, and Edge:
The truth is back/forward cache isn’t a new concept. Safari added support for this feature back in 2009. Firefox has supported it since version 1.5.
Edge and Chrome were the latest to join the party, with the former introducing bfcache in 2020, while the latter did it a year later.
Now that you know that all major browsers support it let’s see how you can check if your page is served from the bfcache.
The best thing about back/forward cache is that it just works in the majority of cases because browsers automatically do all the work for you.
In some cases, however, your pages will not be restored by the bfcache.
The easiest way to check if everything works correctly is to run a PageSpeed Insights audit.
Since the release of Lighthouse v10, there’s been a new PSI audit called “Page prevented back/forward cache restoration.”
The audit will fail if the page you tested cannot be restored from bfcache for any reason. Clicking on the warning, a drop-down menu will open, and you’ll see a list with reasons and the frame(s) that caused the issue.
Failure reasons are separated into three categories:
Another option is to use Chrome’s Developer Tools, following these steps:
1. Open Chrome DevTools on the page you want to test:
2. Navigate to Application > Cache > Back/forward cache:
3. Click Test back/forward cache
If bfcache works on your page, you’ll see this message:
If not, you will see a list of issues:
Now that you know how to test it, let’s see how you can optimize your pages for bfcache and fix PSI’s warning.
Even if you don’t see the warning, meaning your page is eligible for bfcache, it’s good to know that it won’t stay there indefinitely.
That’s why it’s crucial to know how to optimize for back/forward cache.
Here are some best practices you can use to make it as likely as possible that browsers bfcache your pages:
The most surefire way to optimize for bfcache is to avoid using the unload event at all costs.
The unload event fires when the user navigates away from the page (by clicking on a link, submitting a form, closing the browser window, etc.).
On desktop, Chrome and Firefox consider a page ineligible for bfcache if it uses the unload event. Safari, on the other hand, will cache some pages that fire the unload event listener, but to reduce potential breakage, it will not run it when a user is navigating away.
On mobile, Chrome and Safari will cache a page that uses the event, but Firefox won’t.
In general, avoid using the unload event and instead go for the pagehide event. Otherwise, you’re risking slowing down your site, and your code won’t even run most of the time in Chrome and Safari.
Also, there’s an ongoing discussion between browsers to deprecate unload.
It’s ok to use beforeunload events in Chrome and Safari, but keep in mind that Firefox will flag your pages as ineligible for bfcache.
However, there are legitimate use cases for the beforeunload event, unlike the unload event. One example is when you must caution the user about losing unsaved changes if they exit the page. It's advisable to attach beforeunload event listeners only when there are unsaved changes and to remove them promptly after saving those changes.
If a page contains sensitive information and caching is inappropriate, then Cache-Control: no-store should be used to prevent it from being eligible for bfcache. On the other hand, if a page doesn't contain sensitive information and always requires up-to-date content, Cache-Control: no-cache or Cache-Control: max-age=0 can be used. These directives prompt the browser to revalidate the content before serving it and don't impact a page's eligibility for bfcache.
The bfcache isn’t supposed to work for pages that contain sensitive data. For instance, when a user signs out of a website on a public computer, the next user shouldn’t be able to sign back in just by hitting the back button.
To achieve that, it's a good practice to update the page after a pageshow event if event.persisted is true.
Here’s a code from web.dev you can use:
Whenever possible, use rel="noopener" instead of window.opener references. The opened window or the opener won't be eligible for bfcache if your site opens windows and controls them through window.postMessage().
Always close connections and disconnect observers during the pagehide and freeze event
When the page is stored in the bfcache, all JavaScript tasks are paused and resumed as soon as it is taken out of the cache.
If these tasks only access APIs isolated to the current page, there won’t be any problems.
However, if these tasks are connected to APIs that are also accessible from other pages in the same origin, then they may prevent code in other tabs from running properly.
If that’s the case, some browsers will not put a page in bfcache in the following scenarios:
The best thing you can do is to permanently close connections and remove or disconnect observers during pagehide or freeze events if your page uses any of these APIs. By doing this, the browser can cache the page without worrying about other open tabs being affected.
For something handled by browsers, we’ve covered a lot of information.
So here are the key takeaways from this article:
As always, don’t forget to test. Back/forward cache is a great feature, but remember that not every page should be eligible for it. Your visitors' experience should always be a first priority.
Niko has 5+ years of experience turning those “it’s too technical for me” topics into “I can’t believe I get it” content pieces. He specializes in dissecting nuanced topics like Core Web Vitals, web performance metrics, and site speed optimization techniques. When he’s taking a breather from researching his next content piece, you’ll find him deep into the latest performance news.