Speculation rules: load the next page before the click
Speculation rules tell the browser which page a visitor will open next so it can load it early. How prefetch and prerender differ, and how to use both safely.
In this guide
The idea: load the next page early
Most guides on this site are about making the page a visitor is on load faster. Speculative loading helps the next one. MDN defines it as performing navigation work, such as fetching or rendering a page, before the visitor goes there, based on a prediction of where they will go.
The browser does some of this on its own. MDN says Chrome prerenders a page when you type something into the address bar that it is confident you will open. The rest is up to the site. A page can list the links it expects to be followed, and the browser decides what to do with that hint. It uses the Speculation Rules API.
Three points before the details:
- It works on whole pages, not on single files. For images, scripts and the like, use resource hints such as
<link rel="prefetch">. - It suits sites where each page is a separate document, which MDN calls multi-page sites. It does not suit single-page apps.
- It does nothing for the page you are on. The Web Almanac puts it this way: the rules do not help the current page, but they can make the next one load almost at once.
Prefetch and prerender
There are two actions. Their cost and their payoff are very different:
| Prefetch | Prerender | |
|---|---|---|
| What the browser loads | The page's HTML only | The whole page, in a hidden tab: its files, its scripts, and the data those scripts ask for |
| Where it waits | In memory, thrown away when the visitor leaves the current page | In memory, thrown away in the same way |
| What a click does | The page loads faster, because the HTML is already there | The hidden tab is shown, which is near-instant |
| Cost if never opened | Small | Larger. MDN says a prerender uses about as much as rendering an iframe. |
| Other sites | Possible, but only when the visitor has no cookies for the target site | Not possible. Same-site, different-origin pages need the target to opt in with a header. |
| Use it | Widely, on pages that are safe to load early | Sparingly, on links that are very likely to be followed |
A page that is prerendered is also prefetched. Chrome keeps a prefetched page for a short time. MDN gives five minutes, so a visitor can see content that is up to five minutes old.
Speculation rules replace two older tools. <link rel="prefetch"> stores pages in the HTTP cache, where Cache-Control headers such as no-store can block it. <link rel="prerender"> was Chrome-only and, as MDN says, no longer prerenders. Speculation rules prerender does not depend on Cache-Control.
Your first rules
Rules are JSON inside a script tag with the type speculationrules. This example prefetches most links on the site and prerenders links marked with a class:
<script type="speculationrules">
{
"prefetch": [
{
"where": {
"and": [
{ "href_matches": "/*" },
{ "not": { "href_matches": ["/logout", "/cart", "/checkout"] } },
{ "not": { "selector_matches": "[rel~=nofollow]" } },
{ "not": { "selector_matches": ".no-prefetch" } }
]
},
"eagerness": "moderate"
}
],
"prerender": [
{
"where": { "selector_matches": ".next-step" },
"eagerness": "conservative"
}
]
}
</script>Read it from the top:
- `prefetch` and `prerender` are the two actions. Each holds a list of rules.
- `where` tests every link on the page.
href_matchescompares the link's address with a pattern, where*is a wildcard.selector_matchescompares the link with a CSS selector.and,orandnotcombine tests. - *`/
** matches every page on your site. The threenottests then remove the pages with side effects, links markednofollow`, and any link with a class you choose. - `eagerness` says how quickly to start, explained next.
You can also give a rule a fixed list instead of a test: "urls": ["/pricing", "/contact"]. A rule can have where or urls, not both.
Eagerness
Eagerness is a hint, and the browser can overrule it. MDN describes four levels:
| Value | The browser starts |
|---|---|
immediate | As soon as the rules are read |
eager | On any slight sign of interest, such as the pointer moving toward a link or a pause in scrolling |
moderate | When a link has been in view and the pointer or keyboard rests on it for a while |
conservative | When the visitor starts to click (on mousedown or pointerdown) |
A rule with a list of addresses starts immediate unless you say otherwise. A rule with where starts conservative. A good order of work is to begin with conservative, which has the lowest cost and risk, and to move up only for links you are sure about.
Where to put the rules
- In the page, as above. If your site sends a
Content-Security-Policythat limits scripts, it must allow inline speculation rules with the'inline-speculation-rules'source, or a hash or nonce. - In a file, named by a
Speculation-Rulesresponse header. The file must be served asapplication/speculationrules+json. This helps when you cannot edit the page. - By script. Check
HTMLScriptElement.supports("speculationrules")first, then add the script element yourself.
Which pages to speculate on
Prefetch is the broad tool. MDN encourages adopting it widely, for the significant pages of the site, as long as they are safe to load early.
Prerender is for the few links that are very likely to be next. A landing page with one main button is the best case. A page with fifty equal links is the worst, because the guess is rarely right. Each wrong guess costs memory and bandwidth.
Exclude any address where loading the page does something. MDN lists these examples:
- sign-out links
- language switchers
- "add to cart" links
- sign-in steps that send a one-time code by text message
- links that use up an allowance, such as a free-article count
- links that record an ad conversion
A quick way to find them: look at the Disallow lines in your robots.txt file. MDN suggests it, because the pages you hide from search engines are often private or action pages.
The safety problem: the page runs before anyone sees it
A prefetch is an ordinary request, so anything the server does for that address happens, even if the visitor never goes there. A prerender goes further and runs the page's scripts. Four problems follow.
Server actions
If a request changes something on the server, speculation will make it happen early. Prefetch requests carry the header Sec-Purpose: prefetch, and prerender requests carry Sec-Purpose: prefetch;prerender. The server can read it and hold back the action. MDN adds that a response outside the 2xx range stops the speculation, and so do 204 and 205 for prerender. It still recommends letting the speculation happen and using scripts to delay the action, so that the click is fast.
Scripts that count a visit that never happened
A prerendered page runs its analytics, its tags and its chat widget. A visitor who never opens the page still gets counted. MDN gives the fix. A page can ask whether it is being prerendered, and wait for the moment it is shown:
function start() {
initAnalytics(); // your own function
}
if (document.prerendering) {
document.addEventListener('prerenderingchange', start, { once: true });
} else {
start();
}document.prerendering is true while the page is hidden, and the prerenderingchange event fires when the visitor opens it. MDN advises choosing analytics tools that already understand prerendering and holding back scripts that do not. It names Google Analytics and New Relic as examples. See third-party scripts.
The browser helps in some ways. It delays frames from other sites until the page is shown. It defers a long list of interfaces, such as notifications, geolocation and the microphone. It makes alert and confirm return at once without a dialog, and it holds back downloads.
Stale data
A page loaded early can be out of date when it is shown. MDN gives two examples:
- Sign-in. A visitor has two tabs. A page in one tab is prerendered while they are signed out. They sign in, in the other tab, and open the prerendered page. It still shows the signed-out view.
- The cart. A product page prerenders the cart page with no items. The visitor adds an item without a page load, opens the cart, and sees it empty.
The best fix is for the page to refresh itself when needed, using a fetch() request, a WebSocket or the Broadcast Channel API. Where that is not possible, the server can send Clear-Site-Data: "prefetchCache", "prerenderCache" with a response to a request that changes state, such as an add-to-cart call. That discards the early copies.
Addresses that differ only by a tag
Pages often come with tracking tags in the address. Two addresses that differ only by a tag are the same page to a visitor. A No-Vary-Search response header tells the browser that, and the expects_no_vary_search option in a rule lets you say it ahead of time. MDN warns that a prerendered page can start with different parameters than the visitor finally arrives with, so code that reads them should run only after the page is shown.
Browser support
According to MDN's compatibility data, Chrome supports speculation rules, and so do browsers built on it, such as Edge. Chrome added prerender in version 105 and prefetch in version 110 on desktop. Firefox has it only in preview builds, for lists of addresses, and Safari 26.2 has it behind a setting. The Web Almanac describes it the same way: implemented mostly in Chromium-based browsers, with a partial Safari version behind a flag.
A browser that does not know speculationrules ignores the script, and the page works as before. That makes the rules safe to add. Even in Chrome, the browser can decide not to act. MDN lists user settings and memory use as reasons, and says prefetching does not happen in Battery Saver or Data Saver mode.
WordPress
Since WordPress 6.8, core prints speculation rules itself. The rules apply to visitors who are not logged in, on sites with pretty permalinks. According to the core source, the defaults are prefetch with conservative eagerness. The generated rule leaves out:
- login and admin files and paths
- the content, uploads, plugins and theme folders
- addresses with query parameters, when pretty permalinks are on
- links with
rel="nofollow" - links with a
no-prefetchclass, or a parent that has it (andno-prerenderwhen the mode is prerender)
A plugin or a developer can change the mode and eagerness with the wp_speculation_rules_configuration filter, add excluded paths with wp_speculation_rules_href_exclude_paths, and add rules with the wp_load_speculation_rules action. Returning null from the first one turns the feature off.
The Web Almanac found that rules were on only 3% of the top 1,000 sites' desktop home pages and 5% of the mobile ones, and much more widely lower down the ranking. It connects that to WordPress including them by default.
How to check that it works
- View the source of the page, or look in the Elements panel, and confirm the script is there and the JSON is valid. A script that is not valid JSON throws an error.
- Look at the requests your server receives. Speculative requests carry a
Sec-Purposeheader, so your server logs can show them. - After you open a prerendered page, run this in the console. A value above zero means that the page was prerendered. It comes from MDN:
performance.getEntriesByType('navigation')[0].activationStart;- Open a page you did not speculate on, to compare. The difference is what a visitor feels.
- Test the risky pages by hand: sign in and out, add to the cart, switch language, with the rules switched on.
What it does to your numbers
- Lab tests will not show it. A test loads one page from nothing. The gain comes on the next navigation.
- Pageviews can be counted early. Hold analytics until
prerenderingchange, as above. - Field data changes. For a prerendered page,
activationStartrecords the time between the start of the prerender and the moment it was shown, so tools can tell the two apart. See how to measure Core Web Vitals. - Server load goes up. Every speculation is a request, some of them for pages nobody opens. Watch your server and your cache. See caching explained.
Mistakes to avoid
- Prerendering every link. It wastes memory and bandwidth. Use prefetch widely and prerender sparingly.
- Forgetting the side-effect links. Sign-out and add-to-cart links are the usual ones.
- Leaving tags to run early. Analytics, chat and ad tags should wait until the page is shown.
- Assuming one test is enough. Test signed in, signed out, with a full cart and in each language.
- Using it as a fix for a slow site. It does nothing for the first page a visitor sees. Fix the server and the page first.
Check your own page
Run the free audit on a landing page. It measures the first load, which speculation rules cannot change. Use it to fix what makes the page slow, then add the rules for the pages a visitor opens next. Compare the real-visitor numbers over the following weeks.
Sources
- Speculation Rules API and `<script type="speculationrules">` on MDN: how prefetch and prerender work, the rule syntax, eagerness, the unsafe conditions, the
Sec-Purposeheader and the browser compatibility data. - Speculative loading on MDN: the older mechanisms and when to use each.
- Performance chapter, Web Almanac 2025: how widely the rules are used, and the WordPress connection.
- WordPress core: speculative-loading.php: the default mode, eagerness, exclusions and filters.
Start here
Free website audit
Live Google data for any public page: mobile and desktop.
Mobile + desktop · Lighthouse lab test · Real-user Chrome data when Google has it
Rather have this done for you? Speed optimization · Book a call