Find which navigations were blocked from using the bfcache, and why.
The notRestoredReasons
property, added to the PerformanceNavigationTiming
class, reports information on whether frames present in the document were blocked from using the bfcache on navigation, and why. Developers can use this information to identify pages that need updates to make them bfcache-compatible, thereby improving site performance.
Current status
The notRestoredReasons
API has shipped from Chrome 123 and is being rolled out gradually.
Concepts and usage
Modern browsers provide an optimization feature for history navigation called the back/forward cache (bfcache). This enables an instant loading experience when users go back to a page they have already visited. Pages can be blocked from entering the bfcache or get evicted while in bfcache for different reasons, some required by a specification and some specific to browser implementations.
Previously, there was no way for developers to find out why their pages were blocked from using the bfcache in the field, though there was a test in Chrome dev tools. To enable monitoring in the field, the PerformanceNavigationTiming
class has been extended to include a notRestoredReasons
property. This returns an object containing related information on the top frame and all iframes present in the document:
- Reasons why they were blocked from using the bfcache.
Details such as frame
id
andname
, to help identify iframes in the HTML.This allows developers to take action to make those pages bfcache-compatible, thereby improving site performance.
Examples
A PerformanceNavigationTiming
instance can be obtained from features such as Performance.getEntriesByType()
and PerformanceObserver
.
For example, you could invoke the following function to return all PerformanceNavigationTiming
objects present in the performance timeline and log their notRestoredReasons
:
function returnNRR() {
const navEntries = performance.getEntriesByType("navigation");
for (let i = 0; i < navEntries.length; i++) {
console.log(`Navigation entry ${i}`);
let navEntry = navEntries[i];
console.log(navEntry.notRestoredReasons);
}
}
For history navigations, the PerformanceNavigationTiming.notRestoredReasons
property returns an object with the following structure, which represents the blocked state of the top-level frame:
{
children: [],
id: null,
name: null,
reasons: [
{"reason", "unload-listener"}
],
src: null,
url: "https://www.example.com/page/"
}
The properties are as follows:
children
- An array of objects representing the blocked state of any same-origin frames embedded in the top-level frame. Each object has the same structure as the parent object — this way, any number of levels of embedded frames can be represented inside the object recursively. If the frame has no children, the array will be empty.
id
- A string representing the
id
attribute value of the frame (for example<iframe id="foo" src="...">
). If the frame has noid
, the value will benull
. For the top-level page this isnull
. name
- A string representing the
name
attribute value of the frame (for example<iframe name="bar" src="...">
). If the frame has noname
, the value will be an empty string. For the top-level page this isnull
. reasons
- An array of strings each representing a reason why the navigated page was blocked from using the bfcache. There are many different reasons why blocking could occur. See the Blocking reasons section for more details.
src
- A string representing the path to the frame's source (for example
<iframe src="b.html">
). If the frame has nosrc
, the value will be an empty string. For the top-level page this isnull
. url
- A string representing the URL of the navigated page/iframe.
For PerformanceNavigationTiming
objects that don't represent history navigations, the notRestoredReasons
property will return null
.
Note that notRestoredReasons
also returns null
when there are no blocking reasons, so this being null
is not an indicator that the bfcache was or was not used. For that, you must use the event.persisted
property.
Report bfcache blocking in same-origin frames
When a page has same-origin frames embedded, the returned notRestoredReasons
value will contain an object inside the children
property representing the blocked state of each embedded frame.
For example:
{
children: [
{
children: [],
id: "iframe-id",
name: "iframe-name",
reasons: [],
src: "./index.html",
url: "https://www.example.com/"
},
{
children: [],
id: "iframe-id2",
name: "iframe-name2",
reasons: [
{"reason": "unload-listener"}
],
src: "./unload-examples.html",
url: "https://www.example.com/unload-examples.html"
},
],
id: null,
name: null,
reasons: [],
src: null,
url:"https://www.example.com"
}
Report bfcache blocking in cross-origin frames
When a page has cross-origin frames embedded, we limit the amount of information shared about them to avoid leaking cross-origin information. We only include information that the outer page already knows, and whether the cross-origin subtree blocked bfcache or not. We don't include any blocking reasons or information about lower levels of the subtree (even if some sub-levels are same-origin).
For example:
{
children: [
{
children: [],
id: "iframe-id",
name: "iframe-name",
reasons: [],
src: "./index.html",
url: "https://www.example2.com/"
}
],
id: null,
name: null,
reasons: [
{"reason": "masked"}
],
src: null,
url:"https://www.example.com"
}
For all the cross-origin iframes, we report null
for the reasons
value for the frame, and the top-level frame will shows a reason of "masked"
. Note that "masked"
may also be used for user agent-specific reasons so may not always indicate an issue in an iframe.
See the Security and privacy section in the explainer for more details about security and privacy considerations.
Blocking reasons
As we said earlier, there are many different reasons why blocking could occur:
The following are examples of some of the most common reasons the bfcache cannot be used:
unload-listener
: the page registers anunload
handler, which prevents bfcache usage in certain browsers. See Deprecating the unload event for more information.response-cache-control-no-store
: The page usesno-store
as acache-control
value.related-active-contents
: The page was opened from another page (either using "duplicate tab") which still has a reference to this page.
Feedback
The Chromium team wants to hear about your experiences with the bfcache notRestoredReasons
API.
Tell us about the API design
Is there something about the API that does not work like you expected? Or are there missing methods or properties that you need to implement your idea? Have a question or comment on the security model? File a spec issue on the corresponding GitHub repo, or add your thoughts to an existing issue.
Report a problem with the implementation
Did you find a bug with Chromium's implementation? Or is the implementation different from the spec?
File a bug on our issue tracker. Be sure to include as much detail as you can,
simple instructions for reproducing, and specify the component as UI > Browser > Navigation > BFCache
.
Glitch works great for sharing quick and easy repros.
Show support for the API
Are you planning to use the bfcache notRestoredReasons
API? Your public support helps the Chromium team
prioritize features and shows other browser vendors how critical it is to support them.
Send a tweet to @ChromiumDev using the hashtag
#NotRestoredReasons
and
let us know where and how you are using it.