Debugging speculation rules

Speculation rules can be used to prefetch and prerender next page navigations as detailed in the previous post. This can allow for much quicker—or even instant—page loads, greatly improving Core Web Vitals for these additional page navigations.

Debugging speculation rules can be tricky. This is particularly true for prerendered pages, as these pages are rendered in a separate renderer—kind of like a hidden background tab that replaces the current tab when activated. Therefore, the usual DevTools options cannot always be used to debug issues.

The Chrome team has been working hard to enhance DevTools support for speculation rules debugging. In this post, you'll see all the various ways of using these tools to understand a page's speculation rules, why they may not be working, and when developers can use the more familiar DevTools options—and when not.

Explanation of "pre-" terms

There's a lot of "pre-" terms that are easily confused, so let's start with an explanation of these:

  • Prefetch: fetching a resource or document in advance to improve future performance. This post covers prefetching documents using the Speculation Rules API, rather than the similar, but older <link rel="prefetch"> option often used for prefetching subresources.
  • Prerender: this goes a step beyond prefetching and actually renders the whole page as if the user had navigated to it, but keeps it in a hidden background renderer process ready to be used if the user actually navigates there. Again, this document is concerned with the newer Speculation Rules API version of this, rather than the older <link rel="prerender"> option (which no longer does a full prerender).
  • Navigational speculations: the collective term for the new prefetch and prerender options triggered by speculation rules.
  • Preload: an overloaded term that can refer to a number of technologies and processes including <link rel="preload">, the preload scanner, and service worker navigation preloads. These items will not be covered here, but the term is included to clearly differentiate those from the "navigational speculations" term.

Speculation rules for prefetch

Speculation rules can be used to prefetch the next navigation's document. For example, when inserting the following JSON into a page, next.html and next2.html will be prefetched:

<script type="speculationrules">
  {
    "prefetch": [
      {
        "source": "list",
        "urls": ["next.html", "next2.html"]
      }
    ]
  }
</script>

Using speculation rules for navigation prefetches has some advantages over the older <link rel="prefetch"> syntax, such as a more expressive API and the results being stored in memory cache rather than the HTTP disk cache.

Debugging prefetch speculation rules

Prefetches triggered by speculation rules can be seen in the Network panel in the same way as other fetches:

Network panel in Chrome DevTools showing prefetched documents

The two requests highlighted in red are the prefetched resources, as can be seen by the Type column. These are fetched at Lowest priority as they are for future navigations and Chrome prioritizes the current page's resources.

Clicking on one of the rows also shows the Sec-Purpose: prefetch HTTP header, which is how these requests can be identified on the server side:

Chrome DevTools prefetch headers with Sec-Purpose set to prefetch

Debugging prefetch with the Speculative load tabs

A new Speculative loads section has been added in the Application panel of Chrome DevTools, under the Background services section, to help aid in debugging speculation rules:

Chrome DevTools Speculative load tabs showing prefetch rule

There are three tabs available in this section:

  • Speculative loads which lists the prerendered status of the current page.
  • Rules which lists all the rule sets found on the current page.
  • Speculations which lists all the prefetched and prerendered URLs from the rule sets.

The Speculations tab is shown in the previous screenshot, and we can see this example page has a single set of speculation rules for prefetching 3 pages. Two of those prefetches succeeded and one failed. The icon besides the Rule set can be clicked to take you to the source of the rule set in the Elements panel. Alternatively, the Status link can be clicked to take you to the Speculations tab filtered to that ruleset.

The Speculations tab lists all the target URLs, along with the action (prefetch or prerender), which rule set they came from (as there may be multiple on a page), and the status of each speculation:

Chrome DevTools Speculations tab showing prefetched URLs along with their status

Above the URLs, a drop down can be used to show URLs from all the rule sets, or only URLs from a particular rule set. Below that, all the URLs are listed. Clicking on a URL gives you more detailed information.

In this screenshot, we can see the failure reason for the next3.html page (which does not exist and therefore returns a 404, which is a non-2xx HTTP status code).

The summary tab, Speculative loads, shows a Speculative loading status for this page report to show whether a prefetch or prerender was used for this page or not.

For a prefetched page, you should see a successful message when that page is navigated to:

Chrome DevTools Speculative loads tab showing a successful prefetch

Unmatched speculations

When a navigation happens from a page with speculation rules that does not result in a prefetch or prerender being used, an additional section of the tab will show more details of why the URL did not match any of the speculation URLs. This is useful for spotting typos in your speculation rules.

Chrome DevTools Speculative loads tab, showing how the current URL did not match any of the URLs in the previous page's speculation rules

For example, here we navigated to next4.html, but only next.html, next2.html, or next3.html are prefetches, so we can see this doesn't quite match any of those three rules.

The Speculative loads tabs are very useful for debugging the speculation rules themselves, and finding any syntax errors in the JSON.

As for the prefetches themselves, the Network panel is likely a more familiar place. For the prefetch failure example, you can see the 404 for the prefetch here:

Chrome DevTools Network panel showing a failed prefetch

However, the Speculative loads tabs become much more useful for prerendering speculation rules, which are covered next.

Speculation rules for prerender

Prerender speculation rules follow the same syntax as prefetch speculation rules. For example:

<script type="speculationrules">
  {
    "prerender": [
      {
        "source": "list",
        "urls": ["next.html", "next2.html"]
      }
    ]
  }
</script>

This rule set triggers a full load and render of the specified pages (subject to certain restrictions). This can provide an instant loading experience—albeit with extra resource costs.

Unlike prefetches however, these are not available to be seen in the Network panel, as these are fetched and rendered in a separate rendering process in Chrome. This makes the Speculative loads tabs more important to debug prerender speculation rules.

Debugging prerender with the Speculative loads tabs

The same Speculative loads screens can be used for prerender speculation rules as demonstrated with a similar demo page that attempts to prerender, instead of prefetching the three pages:

Chrome DevTools Speculative loads tabs for a page with prerender speculation rules

Here we see again that one of the three URLs failed to prerender, and developers can get the details per URL in the Speculations tab by clicking on the 2 Ready, 1 Failure link.

In Chrome 121 we launched document rules support. This allows the browser to pick these up from same origin links on the page, rather than listing a specific set of URLs:

<script type="speculationrules">
{
  "prerender": [
    {
      "source": "document",
      "where": {
        "and": [
          {"href_matches": "/*"},
          {"not": { "href_matches": "/not-safe-to-prerender/*"}}
        ]
      },
      "eagerness": "moderate"
    }
  ]
}
</script>

This example selects all same origin links, except those beginning with /not-safe-to-prerender as prerender candidates.

It also sets the prerender eagerness to moderate which means the navigations are prerendered when the link is hovered, or clicked.

There are similar rules like this on this demo site, and using the new Speculative loads section on this site shows the usefulness of this new tab as all the eligible URLs the browser found on the page are listed:

Chrome DevTools Speculations tab with a number of Not triggered URLs

The Status is Not triggered as the prerender process for these has not started. However, as we hover over the links, we see the status change as each URL is prerendered:

Chrome DevTools Speculations tab with prerendered pages triggered

Chrome has set limits on prerenders, including a maximum of 2 prerenders for moderate eagerness, so after hovering over the 3rd link, we see the failure reason for that URL:

Chrome DevTools Speculations tab with failed preloads showing

Debugging prerender with the other DevTools panels

Unlike prefetches, pages that have been prerendered will not show up in the current rendering processes in DevTools panels like the Network panel, because they are rendered in their own behind-the-scenes renderer.

However, it is now possible to switch the renderer used by the DevTools panels with the drop down menu in the top right drop down, or by selecting a URL in the top part of the panel and selecting Inspect:

Chrome DevTools now allows you to switch renderers that information is displayed for

This drop down (and the value selected) is shared across all the other panels too, such as the Network panel, where you can see the page being requested is the prerendered one:

Chrome DevTools Network panel showing the network requests for the prerendered page

Looking at the HTTP headers for these resources we can see they will all be set with the Sec-Purpose: prefetch;prerender header:

Chrome DevTools Network panel showing Sec-Purpose header for a prerendered page

Or the Elements panel, where you can see the page contents, like in following screenshot where we see the <h1> element is for the prerendered page:

Chrome DevTools Elements panel for the prerendered page

Or the Console panel, where you can see console logs emitted by the prerendered page:

Chrome DevTools Console panel showing the console output from a prerendered page

Debug speculation rules on the prerendered page

The previous sections discuss how to debug prerendered pages on the page which initiates the prerendering. However, it's also possible for the prerendered pages themselves to provide debugging information, either by making analytics calls or logging to the console (which is viewable as described in the previous section).

Additionally, once a prerendered page is activated by the user navigating to it, the Speculative loads tab will show this status, and whether it was successfully prerendered or not. If it could not be prerendered an explanation as to why that was the case is provided:

Chrome DevTools Speculative loads tab showing both a successful and failed prerendered page

Additionally—as is the case for prefetches—navigating from a page with speculation rules that did not match the current page will attempt to show you why the URLs did not match those covered in the previous page's speculation rules in the Speculative loads tab:

Chrome DevTools Speculative loads tab showing the URL mismatch of the current URL and those covered by the previous page

Conclusion

In this post, we have shown the various ways developers can debug prefetch and prerender speculation rules. The team is continuing to work on tooling for speculation rules, and we would love to hear suggestions from the developers as to what other ways would be helpful for debugging this exciting new API. We encourage developers to raise an issue on the Chrome issue tracker for any feature requests or bugs spotted.

Acknowledgements

Thumbail image by Nubelson Fernandes on Unsplash.