Skip to main content

Blazing Fast Websites with Speculation Rules

· Updated on · 18 min read

This post introduces speculation rules, a new web platform feature that allows developers to deliver instant page navigations after the initial page load.

By the end of this post, you will:

  • Understand how speculation rules can be used to prerender or prefetch pages.
  • Have practical code examples that you can start using today.
  • Learn how to debug and monitor speculation rules in DevTools.

There's also a live demo that you can experiment with to see speculation rules in action.

An Introduction to speculation rules

Typically, when you navigate through a website in your web browser, the browser downloads pages on-demand. This is the web we're all used to.

Speculation rules is a new browser feature that allows developers to hint to the browser which pages to proactively download in the background. If a page has been downloaded in the background, it can be instantly displayed to the user when they navigate to it.

Speculation rules work by specifying the pages, or hyperlinks, that the browser should consider for downloading in the background.

<script type="speculationrules">
{
"prerender": [
{
"urls": ["/shop", "/contact"]
}
]
}
</script>

In the previous code example, two URLs are specified for downloading: /shop and /contact.

Speculation rules offer two types of speculations: prerendering and prefetching.

  • Prerendering: Downloads the resources for a page and renders the page in the background. When the user navigates to the page, it's instantly displayed.
  • Prefetching: Downloads key resources for a page, but doesn't render the page. When the user navigates to the page, the page still needs to be rendered.

Why use speculation rules to prerender pages?

When you use speculation rules to prerender or prefetch pages, you can provide users with instant page navigation.



Scenario:

Consider you have two pages on your ecommerce website:

  • example.com
  • example.com/shop

If a user lands on your main home page example.com, you might know that almost all users navigate from the homepage to the example.com/shop page. To improve this experience, you can use speculation rules to prerender the example.com/shop page when the user lands on the homepage.

When the shop page is prerendered, the browser downloads the resources for the page in the background, and also renders the page - for example running JavaScript and CSS.

Once the user clicks on the link to navigate to the shop page, the browser instantly shows the prerendered page, providing the user with a near-instant navigation experience.

Who benefits from prerendered pages?

Speculation rules can help your end-users as they experience a faster website. But your development team also benefits:

  • You don't need to use a heavy JavaScript framework or a single page app to achieve instant navigation.

    Many content-based websites use single page apps, and in turn, heavy JavaScript frameworks, to achieve instant navigation.

  • You don't need to figure out complex prerendering logic.

    Some websites come up with clunky logic to determine which pages to prerender. With speculation rules, much of this logic is now handled by the browser.

  • You don't need to determine for yourself whether the user is in a constrained environment, such as on a mobile device with limited memory.

    Browsers won't speculate when certain conditions are met, such as when the user is on energy saver mode, due to a low battery. Note however, it's still possible to waste bandwidth and CPU resources if you over-speculate as prerendering uses a lot of resources.

Try out speculation rules

warning

If speculation rules aren't working as expected this may be related to your browser settings. Head to the next section to learn more.

Check out this live demo to see speculation rules in action.

To understand this demo, note that the /shop, /about, and /contact pages have lots of slow loading resources. Prerendering these pages can download those resources in the background, so when the user navigates to these pages, they load instantly.

Speculation rules live demo

To experience this demo:

  1. Navigate to the live demo in a supported browser.
  2. Wait a few seconds while pages are prerendered in the background.
  3. Click on the navigation links to see the instant navigation experience.
  4. Navigate to the version of the demo that does not use speculation rules to see the difference in navigation speed as you click on the links.

Why are speculation rules not working for me?

info

Browser support information is correct as of June 2024.

Speculation rules are supported by default in Chrome and Edge. You can start using speculation rules today to give your users a faster navigation experience.

It's possible that you, or your installed browser extensions, have changed certain settings that disable speculation rules. We recommend you go through the following steps to verify:

  1. To try out this feature, use a supported browser like Chrome or Edge.

  2. Navigate to your browser settings to enable web page preloading. In Chrome, you can configure this in chrome://settings/performance/.

    Ensure the Preload pages for faster navigation and searching setting is enabled.

    Enable Preload pages setting in Chrome

    info

    Note that some Chrome extensions, like uBlock Origin, can disable browser preloading. If this has happened, the Speed section on chrome://settings/performance/ informs you of this fact as you hover over the jigsaw piece icon.

    Chrome extension disabling preloading

    If you are using uBlock Origin, you can address this by navigating to the extension settings page and unchecking the setting: "Disable pre-fetching (to prevent any connection for blocked network requests)".

Are prerendering and speculation rules the same?

This post uses the terms prerendering and speculation rules interchangeably, however it's useful to be clear on the distinction:

Speculation Rules is an API that supports two types of speculations: prerendering and prefetching.

Speculation rules and page prerendering is not the same as link preloads:

Link preloads: Use the <link rel="preload"> tag to download resources in the background. This is useful for resources like fonts, images, and scripts that are needed for the current page. Speculation rules are used for subsequent pages that the user is likely to navigate to, whereas link preloads are used for resources needed on the current page.

Difference between Document Rules and URL List Rules

To specify the pages you want prerendered, you can use two types of rules:

  • URL List Rules: Use a list of URL strings to specify which pages to prerender.
  • Document Rules: Use conditions to determine when a page should be prerendered.

Use a URL List to prerender specific pages

Using a list of URL strings, you can specify which pages to prerender.

Before:

When the user clicks on and navigates to the page-1.html or page-2.html link, the page is slow to load.

<!-- These pages are slow to load -->
<a href="page-1.html">Page 1</a>

<a href="page-2.html">Page 2</a>

After:

When the user clicks on and navigates to the page-1.html or page-2.html link, the page loads immediately.

<script type="speculationrules">
{
"prerender": [
{
"urls": ["page-1.html", "page-2.html"]
}
]
}
</script>

<!-- These pages are now prerendered -->
<a href="page-1.html">Page 1</a>

<a href="page-2.html">Page 2</a>

Use Document Rules to prerender pages based on conditions

When you use Document Rules with the speculation rules API, you can specify conditions that determine when a page should be prerendered.

Before:

In this example, no pages are prerendered.

<a href="/shop">Shop</a>

<a href="/about">About</a>

<a href="/logout">Logout</a>

After:

In this example, the /shop and /about URLs are prerendered, but the logout URL is not. Have a look at the following code snippet, and then continue reading to understand how it works.

<script type="speculationrules">
{
"prerender": [
{
"where": {
"and": [
{ "href_matches": "/*" },
{ "not": { "href_matches": "/logout" } }
]
}
}
]
}
</script>

<!-- ✅ Prendered -->
<a href="/shop">Shop</a>

<!-- ✅ Prendered -->
<a href="/about">About</a>

<!-- ❌ Not prerendered -->
<a href="/logout">Logout</a>

In the previous code snippet, the where key is used to specify conditions for prerendering. The and key is used to combine multiple conditions. You can reason about the code snippet as follows:

"Prerender all pages except the /logout page."

The "all pages" condition is specified using the href_matches key with the value /* - this value is a URL Pattern that uses a wildcard (*) to match all hyperlinks found on the website.

tip

While out of scope for this article, it's important to think about pages which should not be prerendered. If the prerendering of a page introduces unwanted side effects, you should evaluate whether the page should be prerendered. For example, a page that logs the user out should not be prerendered. Image the scenario:

  1. A logged in user of your website is on their /dashboard page. This current page has a logout hyperlink, amongst other hyperlinks.
  2. Document rules, as part of the speculation rules API, are used to prerender the matching hyperlinks found on the page.
  3. The browser prerenders the /logout page. Through the prerendering process, and your website's backend logic, the user is logged out.
  4. The user navigates to the /shop page only to discover they are logged out.

The speculation rules API allows you to specify an eagerness setting to control when a page is prerendered.

  • immediate: The page is prerendered or prefetched immediately.
  • moderate: The page is prerendered or prefetched when the user hovers over a link for 200 milliseconds.
  • conservative: The page is prerendered or prefetched when the user initiates a click on the link.

You might be wondering what the point of the conservative setting is, since clicking on a link will open the following page anyway. The key here is that with the speculation rule the next page will start loading in the background as soon as the mouse button goes down or as soon as the tap interaction starts on a mobile device. In contrast, a click is only recorded once the mouse button goes up again.

tip

There's also an eager setting however it's currently identical to immediate.

<script type="speculationrules">
{
"prerender": [
{
"where": {
"href_matches": "/*"
},
"eagerness": "moderate"
}
]
}
</script>

<!--
The user has to hover over the link for
200 milliseconds for the page to be prerendered
-->
<a href="/shop">Shop</a>

Document rules and URL list rules have different default eagerness settings:

  • Document Rules: The default eagerness setting is conservative.
  • URL List Rules: The default eagerness setting is immediate.

Prefetch pages instead of prerendering

You can think of prefetching as a lighter version of prerendering.

Prefetching downloads the main document resource of the speculated page, but doesn't render the page and doesn't download its subresources. The lack of prerendering is a key difference between prefetching and prerendering.

To use the prefetching mechanism rather than prerendering, use the prefetch key in the speculation rules.

<script type="speculationrules">
{
"prefetch": [
{
"urls": ["/shop", "/about"]
}
]
}
</script>

<!--
The /shop and /about pages are prefetched
-->
<a href="/shop">Shop</a>
<a href="/about">About</a>

Compared to prerendering, prefetching is less resource-intensive. It's a good option when you want to download resources for a page, but don't want to render the page until the user navigates to it.

Add or remove speculation rules via JavaScript

Instead of adding speculation rules directly in the HTML, you can also add them via JavaScript. This is helpful when you need to dynamically add or remove speculation rules based on user interactions or client-side data.

const scriptEl = document.createElement("script");
scriptEl.type = "speculationrules";
const specRules = {
prerender: [
{
urls: ["shop.html", "about.html", "contact.html"],
},
],
};
scriptEl.textContent = JSON.stringify(specRules);
document.body.append(scriptEl);

Prerender using href_matches

In some previous code examples, you saw how to use href_matches to specify which pages to prerender. This uses the URL Pattern API to match URLs, and unlocks a powerful way to specify which pages to prerender.

<script type="speculationrules">
{
"prerender": [
{
"where": {
"href_matches": "/*"
}
}
]
}
</script>

Prerender based on CSS selectors

You can use the selector_matches key to specify which pages to prerender based on CSS selectors. Depending on your use case, this can lead to declarative code like this:

<script type="speculationrules">
{
"prerender": [
{
"where": {
"and": [
{ "href_matches": "/*" },
{
"not": {
"selector_matches": ".no-prerender"
}
}
]
}
}
]
}
</script>

In the previous example, document rules are used to prerender all pages, unless the hyperlink to the page has the .no-prerender class.

Chrome DevTools and Debugging

Prerendering and prefetching activity can be monitored in Chrome DevTools.

warning

As of June 2024, when using Chrome DevTools to debug speculation rules, you should follow this guidance:

Open Application > Background Services > Speculative Loads > Speculations before loading the page that has the speculation rules you want to inspect. This helps ensure that speculations are correctly captured within DevTools.

If a page uses speculation rules to prerender or prefetch pages, you can inspect the speculations in: Application > Background Services > Speculative Loads > Speculations.

Inspecting speculations in the Application panel

You can click to view the speculations and see individual URLs that are being prerendered or prefetched.

Viewing URLs that are being prerendered or prefetched

When a page is being prerendered, DevTools lets you change the context of DevTools to inspect the prerendered page - so you can inspect the prerendered page as if it were a regular page.

Inspecting a prerendered page in DevTools

Without having to switch the DevTools context to a prerendered page, the Network track in the Performance Panel shows you network activity relating to the prerendered resources.

Performance panel network track showing prerendering

When you navigate to a prerendered page, the Application panel confirms the Speculative loading status for the current page.

Speculative loading status in the Application panel

This confirms whether or not the page is prerendered or prefetched.

Prerendering Behavior and Limitations

If you use prerendering, you should be aware of certain behavior and limitations (applicable to Chrome as of June 2024).

If you use the immediate or eager eagerness setting, Chrome will hold up to 50 prefetched pages and 10 prerendered pages in memory.

eagernessPrefetchPrerender
immediate/eager5010
moderate/conservative22

info

Prerendering a page can use significant resources, so it's important to use speculation rules judiciously. You should be mindful that a prerendered page has a:

  • Bandwidth cost
  • Battery usage cost
  • CPU usage cost

And it's still possible the page won't be displayed to the user.

Regardless of the speculation rules you've added to your website, prerendering won't always occur. This can happen because:

  • The user is on a device with limited memory.
  • The user has expressed a preference for limited resource usage, such as when the browser is in energy saver mode and they have a low battery.
  • Energy saver mode has automatically been enabled by the browser because of low battery life.
  • A Chrome extension, like uBlock Origin has disabled browser preloading

You should also be mindful that prerendering can lead to pages getting out of sync with the main page. Consider a scenario where a page has been prerendered with data that then becomes stale, as the user has not yet navigated to the prerendered page and may continue interacting with the main page. In such cases, you can listen for the prerenderingchange event to detect when a page has been activated, and update the page as needed.

Web APIs that are deferred during prerendering

Not all web APIs are fully usable while a page is being prerendered as some APIs are deferred during prerendering. Here are some examples:

While your code can call these APIs, they are deferred until the user visits the prerendered page.

You can find the full list here

Browser Support and detection for speculation rules

You can progressively enhance a page to use speculation rules. An unsupported browser will ignore the rules and will skip prerendering or prefetching.

if (
HTMLScriptElement.supports &&
HTMLScriptElement.supports("speculationrules")
) {
// Speculation rules is supported
}

Detecting when a page is prerendered

You might want to know if a page has been rendered - this can be useful for analytics, or to trigger certain actions when a prerendered page is activated.

  • document.prerendering returns true if the page is currently prerendering.
  • The activationStart property on a performance navigation timing entry specifies the time between the prerender starting, and the page becoming fully activated.

You can use this JavaScript snippet to detect if a page is prerendered:

const isPagePrerendered =
document.prerendering ||
window.performance?.getEntriesByType?.("navigation").at(0)?.activationStart >
0;
tip

The activationStart time for a non-prerendered page is 0.

The activation of a prerendered page can be detected using the prerenderingchange event:

function onActivated() {
// Do any work that needs to be done when the page is activated.
}

if (document.prerendering) {
document.addEventListener("prerenderingchange", onActivated, { once: true });
} else {
onActivated();
}

Speculation rules based on user personas

It can be helpful to use speculation rules to cater to different user personas. For example, you can use backend/analytics data to determine which pages to prerender for different user segments.

Consider a user who regularly visits the /trending or /issues pages on GitHub. You can use speculation rules to prerender such pages for this user.

Or consider a power user of a project management app. Such a user might want to customize which category of pages they regularly want prerendered - this could be made available as a feature from the app settings.

The takeaway is that you shouldn't prerender indiscriminately - that is, prerendering every page on your website. Instead, you should think about user journeys and prerender pages strategically.

Use speculation rules instead of single page apps

Many websites use single page apps - sometimes with heavy JavaScript frameworks, to achieve instant navigation, even though they are primarily content-based websites that include little to no interactivity. For such websites, removing the complexity of a single page app and using speculation rules can be a simpler and more efficient way to achieve instant navigation.

Exercise for the reader

Navigate to the live demo that does not use speculation rules. Then, add speculation rules to the main page to see the difference in navigation speed.

To do this:

  1. Open the Chrome DevTools console on the live demo.

  2. Paste the following code snippet into the console panel:

    const scriptEl = document.createElement("script");
    scriptEl.type = "speculationrules";
    const specRules = {
    prerender: [
    {
    urls: [
    "/demo-no-spec-rules/shop.html",
    "/demo-no-spec-rules/about.html",
    "/demo-no-spec-rules/contact.html",
    ],
    },
    ],
    };
    scriptEl.textContent = JSON.stringify(specRules);
    document.body.append(scriptEl);
  3. In Chrome DevTools, navigate to Application > Background Services > Speculative Loads > Speculations to see the speculations.

  4. Click the "Shop" page hyperlink and observe the page load feels snappy. You've now landed on a prerendered page.

  5. Paste the following code snippet in the Console Panel and observe that there's a non-zero activationStart time:

    window.performance.getEntriesByType("navigation").at(0).activationStart;

Now you've navigated away, the speculations are lost. As a bonus step, try using the DevTools Overrides feature to persist the speculation rules on all pages.

Conclusion

Speculation rules are a powerful new web platform feature that allows you to control when and how pages are prerendered or prefetched. This makes your website faster for your users, and can help improve your Core Web Vitals.

When available, DebugBear surfaces navigation data in your Web Vitals dashboard. This can highlight what percentage of your page navigations use prerendering to load pages instantly.

Navigation types in DebugBear

If you use the Real User Monitoring feature in DebugBear, you're able to see performance metrics for individual page views of your website. You can expect to see improved Largest Contentful Paint (LCP) times for pages that are prerendered, compared to pages that are not prerendered.

Page view metrics in DebugBear

tip

If you use Wordpress, there's a speculation rules plugin that you can use to add speculation rules to your Wordpress website.

In the post, you learned:

  • The code syntax for adding speculation rules to your website - including document rules and URL list rules.
  • Detecting when a page is currently being prerendered, and when it has been activated. As well as detecting browser support for speculation rules.
  • How to keep track of speculations in Chrome DevTools and how to inspect a prerendered page.
  • The difference between prerendering and prefetching.

Interested in some further reading? Use the MDN documentation to learn more about the Speculation Rules API.

Get a monthly email with page speed tips