# The Speculation Rules API Explained

Source: https://www.egnworks.com/blog/speculation-rules-api-explained  
Author: Jacob Val  
Published: 2026-09-15  
Updated: 2026-09-15  
Category: Frontend Architecture  
Tags: Speculation Rules, Web Performance

> A deep technical guide to the Speculation Rules API, covering prefetch and prerender rules, eagerness levels, document rules with URL and selector matching, what changes for a prerendered page, safety restrictions, and current browser support.

---

Every ordinary navigation starts from zero the moment a visitor clicks a link. The browser resolves DNS, opens a connection, sends the request, waits for a response, then parses and renders whatever comes back, all after the click has already happened. The Speculation Rules API lets a page tell the browser to do some or all of that work in advance, for a link the visitor has not clicked yet, so the navigation that eventually happens has less left to do or nothing left to do at all.

## Why a Click Has Always Started From Zero

A `<link rel="prefetch">` hint has existed for years and tells the browser to download a resource ahead of time, but for a full page navigation this only saves the network round trip. The browser still has to parse the HTML, discover and fetch subresources, run scripts, and lay out the page after the click, which is most of the actual work involved in a slow feeling navigation.

A separate, nonstandard `<link rel="prerender">` existed in Chrome for a period and went further, but it offered no way to control when prerendering happened, which links qualified, or how many speculative loads ran at once, and different browsers implemented it inconsistently or not at all. The Speculation Rules API replaces both with a single, structured mechanism that covers prefetching, full prerendering, and the safety and control primitives that a heuristic like this needs.

## Prefetch and Prerender Are Not the Same Thing

Rules are declared as JSON inside a `<script type="speculationrules">` element, under two possible top level keys.

```html
<script type="speculationrules">
{
  "prefetch": [{ "urls": ["/pricing"] }],
  "prerender": [{ "urls": ["/docs"] }]
}
</script>
```

A `prefetch` rule downloads the response body ahead of time, so the network request is already finished by the time the visitor clicks, but the browser still parses, runs scripts, and renders after the click. A `prerender` rule goes further, loading the destination into a hidden, fully rendered background tab, including running its JavaScript, so that clicking the link only has to swap that already rendered tab into view. Prerendering costs more, both in bandwidth and in the resources spent rendering a page that might never be viewed, which is why it needs more deliberate targeting than prefetching does.

## Writing Rules by URL List

The simplest rule form lists exact URLs to prefetch or prerender.

```html
<script type="speculationrules">
{
  "prerender": [
    { "urls": ["/product/hats", "/product/shoes"] }
  ]
}
</script>
```

This works well for a small, known set of likely next pages, such as the next page of a paginated list, but it does not scale to a page with dozens or hundreds of links where the destination is not known ahead of time.

## Writing Rules by Document Pattern

A document rule matches links already present on the page instead of listing URLs by hand, using a `where` clause built from `href_matches`, `selector_matches`, and the logical operators `and`, `or`, and `not`.

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

This rule prerenders every link whose URL matches the `/product/*` pattern, excluding any link carrying a `no-prerender` class, without the page needing to know those URLs in advance. A single document rule like this can cover an entire category of links across a site that changes its content constantly, such as a product catalog or a blog index.

## Controlling When Speculation Starts With Eagerness

Prerendering every matching link the instant the rule is parsed would waste bandwidth on links the visitor never intends to follow. The `eagerness` field controls how confident the browser needs to be before it starts.

| Eagerness | When speculation starts |
| --- | --- |
| `immediate` | As soon as the rule is evaluated, the default for URL list rules |
| `eager` | After roughly 10 milliseconds of pointer hover on desktop, or shortly after a link becomes visible on mobile |
| `moderate` | After roughly 200 milliseconds of hover or on pointer down on desktop, or after scrolling settles near the link on mobile |
| `conservative` | Only once the visitor has actually pressed down on the link, the default for document rules |

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

`moderate` is a reasonable default for document rules covering many links, since it only spends resources on links a visitor has shown some intent toward, while `conservative` is closer to guaranteed intent at the cost of less time to actually finish prerendering before the click lands.

## What Changes for a Prerendered Page

A page loading inside a prerendered tab is not actually visible yet, so a number of platform features that assume an active, foreground page are deferred until the tab is activated. Geolocation, camera and microphone access, notifications, storage persistence prompts, and service worker registration all wait for activation rather than running during prerendering. `window.alert`, `confirm`, and `prompt` return immediately without blocking, and cross-site navigation and cross-origin iframe loading are restricted while the page is still hidden.

None of this requires special handling for a typical content page, but a page that fires an analytics event or starts a session timer as soon as it loads needs to account for the possibility that this happens during prerendering, before the visitor has actually seen anything.

## Detecting a Prerendered Page in Code

`document.prerendering` reports whether the current page is currently in the prerendered, not yet activated state, and the `prerenderingchange` event fires the moment it becomes the active page.

```js
if (document.prerendering) {
  // defer analytics until the page is actually seen
} else {
  sendPageViewEvent();
}

document.addEventListener("prerenderingchange", () => {
  sendPageViewEvent();
});
```

A server can perform the equivalent check by watching for the `Sec-Purpose` request header, which carries `prefetch` or `prefetch;prerender` on a speculative request, useful for a backend that wants to avoid counting a prerender as a real page view before the client side check above even runs.

## Rules That Should Never Be Prefetched or Prerendered

Speculatively loading a URL runs whatever that page does on load, which is unsafe for a URL whose mere loading has a side effect.

| URL type | Why it is unsafe to speculate |
| --- | --- |
| Sign-out links | Loading the page logs the visitor out before they clicked anything |
| Add-to-cart or checkout actions | Loading the page can add an item or charge a payment method |
| Links that consume a limited allowance, such as a one-time download | Loading the page burns the allowance without an actual visit |
| Ad click and conversion tracking links | Loading the page fires a tracked click that never really happened |

A `where` clause that excludes these URLs by pattern or by a marker class, the same way the earlier `not: { selector_matches }` example excluded `.no-prerender`, keeps a broad document rule from accidentally covering something like this.

## Browser Support Today

Speculation rules currently run in Chromium based browsers, including Chrome, Edge, and Opera. Firefox has no support, and Safari does not support it either as of this writing. Because the feature is declared as inert JSON inside a script tag, a browser without support simply ignores it entirely rather than erroring, which makes it safe to ship as a progressive enhancement without a feature detection branch, though `HTMLScriptElement.supports("speculationrules")` is available for code that wants to confirm support before relying on the behavior it produces.

## Conclusion

The Speculation Rules API turns "load the next page before the click" from a browser specific hack into a declarative, JSON based mechanism with real controls over scope, timing, and safety. Prefetch and prerender cover different amounts of the work a navigation eventually needs, document rules let a single declaration cover links a page did not know about in advance, and eagerness levels tune how much confidence the browser needs before it spends the bandwidth. With support currently limited to Chromium based browsers, it is a genuine progressive enhancement today, one that makes navigation feel instant for the visitors whose browser supports it, without changing anything for the ones whose browser does not.

## References

[MDN: Speculation Rules API](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API)

[MDN: script type="speculationrules"](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script/type/speculationrules)

[Chrome for Developers: Prerender Pages in Chrome](https://developer.chrome.com/docs/web-platform/prerender-pages)

[Can I Use: Speculation Rules](https://caniuse.com/mdn-html_elements_script_type_speculationrules)
