![Barry Pollard](https://web.dev/images/authors/tunetheweb.jpg) Barry Pollard [X](https://twitter.com/tunetheweb) [GitHub](https://github.com/tunetheweb) [Mastodon](https://mastodon.social/@tunetheweb) [Bluesky](https://bsky.app/profile/tunetheweb.com) [Homepage](https://www.tunetheweb.com)

<br />

Speculation rules can be used to prefetch and prerender next page navigations as detailed in [the previous post](https://developer.chrome.com/docs/web-platform/prerender-pages.md.txt). This can allow for much quicker---or even instant---page loads, greatly improving [Core Web Vitals](https://web.dev/articles/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.

> [!NOTE]
> Prefer video to reading? Check out this [DevTools Tips video on debugging speculative navigations for faster page loads](https://youtu.be/BIpz9Hdjm_A) for a summary of what's in this document.
> [Video](https://www.youtube.com/watch?v=BIpz9Hdjm_A)

## Explanation of "pre-" terms

There's a lot of "pre-" terms that are confusing, so we'll 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](https://developer.chrome.com/blog/nostate-prefetch.md.txt)).
- **Speculative navigations**: 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](https://web.dev/articles/preload-scanner), and [service worker navigation preloads](https://web.dev/blog/navigation-preload). These items won't be covered here, but the term is included to clearly differentiate those from the "speculative navigations" term.

> [!NOTE]
> **Note:** For more details see the [preloading tech landscape document](https://docs.google.com/document/d/1FNLyXW0Q5Fi5-kEOtjfOdmtoDxRtUR_wX4dl5Fz9c7o/edit).

## 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:

```html
<script type="speculationrules">
  {
    "prefetch": [
      {
        "source": "list",
        "urls": ["next.html", "next2.html"],
        "tag": "rule-set-tag-1"
      }
    ]
  }
</script>
```

> [!IMPORTANT]
> **Key point:** Prefetch speculation rules only prefetch the document, not its subresources. This uses fewer resources than a full prerender of a potential next navigation, but also means the subresources need to be fetched and rendered upon navigation.

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.

### Debug `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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/network-panel-chrome-devtools-prefetch.png) 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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/chrome-devtools-prefetch-sec-purpose-header.png) Chrome DevTools prefetch headers with Sec-Purpose set to prefetch

### Debug `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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/speculations-rules-tab-prefetch.png) Chrome DevTools Speculative load tabs showing prefetch rule

> [!IMPORTANT]
> **Key point:** The **Speculative load** tabs are for working with speculation rules prefetching and prerendering (collectively known as "speculative navigations"). These tabs cannot be used to debug subresource *preloading* using `<link rel="preload">`, subresource *prefetching* using `<link rel="prefetch">`, nor the older `<link rel="prerender">` *no-state prefetching*.

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, designated as URLs or [rule tags](https://github.com/WICG/nav-speculation/blob/main/speculation-rules-tags.md), if any.
- **Speculations** which lists all the prefetched and prerendered URLs from the rule sets.

> [!IMPORTANT]
> **Important:** if you loaded the page before opening the **Speculative load** tabs in DevTools, you'll need to reload the page to populate these panels. This is because the panels use the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/) to monitor speculations in real time, and this is only enabled when the panels are used. We are looking to improve this [to allow some state to show even if opened after](https://issues.chromium.org/issues/341878626).

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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/speculations-prefetch-annotated.png) 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. Beneath 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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/successful-prefetch.png) 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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/unsuccessful-prefetch.png) Unmatched URLs are highlighted in DevTools

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.

> [!NOTE]
> **Note:** As this feedback is primarily intended for debugging speculation rules, this URL matching can look a little confusing when navigating to a completely different page that is not included in speculation rules, and is therefore not expected to be prefetched or prerendered: ![Chrome DevTools showing an unmatched URL in the Speculative loads tab](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/unrelated-unsuccessful-prefetch.png) Chrome DevTools showing an unmatched URL in the Speculative loads tab The Chrome team is [continuing to iterate on this feature](https://bugs.chromium.org/p/chromium/issues/detail?id=1473861) to improve the user interface in these cases.

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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/chrome-devtools-network-failed-prefetch.png) 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:

```html
<script type="speculationrules">
  {
    "prerender": [
      {
        "source": "list",
        "urls": ["next.html", "next2.html"],
        "tag": "rule-set-tag-1"
      }
    ]
  }
</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.

### Debug `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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/speculations-rules-tab-prerender.png) 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](https://developer.chrome.com/blog/new-in-chrome-121.md.txt#speculation-rules-api). This allows the browser to pick these up from same origin links on the page, rather than listing a specific set of URLs:

```html
<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 (on desktop), based on viewport (on mobile), or is clicked.

There are similar rules like this on [the speculative rules demo site](https://chrome.dev/speculative-loading/common-fruits.html), 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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/document-rules-not-triggered.png) 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 hold the pointer over the links, we see the status change as each URL is prerendered:
![Chrome DevTools Speculations tab with prerendered pages triggered](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/document-rules-triggered.png) Chrome DevTools Speculations tab with prerendered pages triggered

Chrome [has set limits on prerenders](https://developer.chrome.com/docs/web-platform/prerender-pages.md.txt#chrome-limits), 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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/replaced-prerender-shows-as-failure.png) Chrome DevTools Speculations tab with failed preloads showing

### Debug `prerender` with the other DevTools panels

Unlike prefetches, pages that have been prerendered won't 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, 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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/switch-renderers.png) Chrome DevTools now lets you 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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/network-with-different-renderer.png) 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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/sec-purpose-headers-prerender.png) 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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/prerender-elements-panel.png) 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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/prerender-console-panel.png) 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 couldn't 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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/success-failed-prerender.png) Chrome DevTools Speculative loads tab showing both a successful and failed prerendered page

Additionally---[as is the case for prefetches](https://developer.chrome.com/docs/devtools/application/debugging-speculation-rules.md.txt#unmatched-speculations)---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](https://developer.chrome.com/static/docs/devtools/application/debugging-speculation-rules/image/unsuccessful-prerender.png) Chrome DevTools showing the URL mismatches

## 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](https://developer.chrome.com/docs/devtools/application/debugging-speculation-rules/crbug.com/new) for any feature requests or bugs spotted.

## Acknowledgements

*Thumbail image by [Nubelson Fernandes](https://unsplash.com/@nublson) on [Unsplash](https://unsplash.com/photos/CO6r5hbt1jg).*