How to prefetch the next page with speculation rules
A small JSON block tells Chromium browsers to load a page before the visitor clicks its link. No JavaScript needed, and other browsers just ignore it.
You click a link, and for a moment nothing happens. The browser asks the server for the next page and waits for the answer. On a fast site that wait is short, but you still feel it. What if the browser asked a little earlier, while your mouse is still on its way to the link?
Guessing the next click
Chromium browsers (Chrome, Edge, Opera) can do that with speculation rules. Speculation here means the browser guesses which page you will open next and loads it in the background. If the guess is right, the click shows a page that is already there. If it is wrong, the browser has loaded one page for nothing.
Think of a waiter who sees you look at the dessert menu and walks to the kitchen before you order. If you order the cake, it arrives at once. If you change your mind, the walk was wasted. The analogy stops at the cost: the browser pays with a bit of data and server time, not with anyone's patience.
The rules are data, not code
You don't write a script for this. You put a block of JSON into the page, and the browser reads it like it reads a stylesheet:
<script type="speculationrules">
{
"prefetch": [{
"where": { "and": [
{ "href_matches": "/*" },
{ "not": { "href_matches": "/api/*" } }
]},
"eagerness": "eager"
}]
}
</script>
where describes which links count: here every link on the same site, except the API. The browser finds those links in the page by itself, so a new page needs no extra work. prefetch means it only downloads the page's HTML. Browsers without support skip the block, so Firefox and Safari behave exactly as before.
On this site, the pages that show notes load no JavaScript at all, and that is a rule with a test. The block didn't break it, because the browser never runs it as code.
How eager is eager
eagerness says when the browser starts guessing. According to Chrome's documentation on speculation rules (opens in a new tab), the four values work like this in current Chrome:
| Value | Desktop | Mobile |
|---|---|---|
immediate | as soon as the rules are read | as soon as the rules are read |
eager | pointer rests on the link for about 10 ms | about 50 ms after the link enters the viewport |
moderate | hover of 200 ms, or pointer down | 500 ms after scrolling stops, for links near the last touch |
conservative | pointer down | touch down |
A phone has no hover, so Chrome uses the viewport there instead: the part of the page you can see. Chrome also caps the guesses. immediate may keep up to 50 prefetches, eager, moderate and conservative only 2. When a third one starts, the oldest is dropped.
I picked eager, because I wanted the links in view to load first on a phone. The cap doesn't stop the requests, though. On a phone, scrolling through a long list like the notes page can start a prefetch for every link that stays in view for 50 ms. For small HTML pages that is cheap, but it isn't free.
And I picked prefetch, not its bigger sibling prerender. Prerender runs the whole page in a hidden tab, scripts included. On this site that could count a visit for a page nobody opened.
What it did
I measured it locally in headless Chromium 153 on desktop, over 5 runs with and 5 without the block. The test server waited 300 ms before every page, like a slow network. The script hovered a note link, waited, and clicked it.
With the block, my script timed 62 to 77 ms from the click to the loaded next page. Without it, the same timing was 368 to 386 ms. The browser's own timing entry marked the fast pages as served from a navigational prefetch, and the server saw one request per run with the header Sec-Purpose: prefetch. So only the hovered link was fetched, not every link on the page.
I only measured desktop. In a phone profile on the same desktop Chromium, the page only loaded on the tap, so mobile emulation did not trigger the viewport rule.
Try it: open Chrome DevTools on a page with the block, open the Speculative loads section in the Application panel, and watch the list while you move the mouse over links.