On a static, multi-page site with no JavaScript framework, every click on a link triggers a real page load. That's what makes these sites light and reliable. But it also means there's a small dead time on every navigation: the request goes out, the server responds, the page renders. A recent browser API, the Speculation Rules API, lets that dead time start before the click happens. Here's what it does, and how I use it — carefully.
The problem it solves
Sites that feel instantly fast are, most of the time, JavaScript applications that handle navigation themselves (client-side routing): they just swap the page content without a full reload. It works, but it has a cost — more JavaScript to download and run, which usually means less reliability and a slower time-to-interactive on the first load.
On the sites I build, I prefer the opposite: little JavaScript, real pages, a real reload on every navigation. The Speculation Rules API lets me keep that simple architecture while cutting the perceived dead time between pages, without writing a single line of routing code.
What the API actually does
The idea: you declare, in a JSON block, which pages the browser is allowed to fetch ahead of time — before the visitor even clicks. There are two levels. prefetch just downloads the server response in the background. prerender goes further: it loads and renders the page in a hidden tab, ready to appear instantly on click.
It's declared with a simple <script type="speculationrules"> block:
<script type="speculationrules">
{
"prerender": [
{
"where": {
"and": [
{ "href_matches": "/*" },
{ "not": { "href_matches": "/contact" } }
]
},
"eagerness": "moderate"
}
]
}
</script>
The eagerness field controls how aggressive the browser is: conservative waits for an actual click to start (mousedown), moderate triggers as soon as a link is hovered or scrolled into view, immediate loads right away. The more aggressive the setting, the faster the next navigation feels — and the more pages get loaded that a visitor may never actually visit.
What I use, and what I avoid
I always start at moderate: a good balance that mostly preloads pages a visitor is genuinely looking at (hover, scroll), without blindly preloading everything. And I explicitly exclude certain links from prerender: a contact page if it contains a form, any logout link, any external link. The reason is simple — a prerender loads and runs the page in the background, JavaScript included. If that page triggers a side effect (firing an analytics event, invalidating a session), it would happen before the visitor has even clicked.
It's also one more reason I don't add third-party trackers to the sites I ship: fewer scripts with side effects means fewer risks like this one with speculative preloading.
One more caution: it doesn't work everywhere yet
This API isn't a universally supported standard. Today it works in Chromium-based browsers (Chrome, Edge); Firefox and Safari don't implement it yet, and it isn't considered "Baseline" (MDN's marker for a feature that reliably works everywhere). That's not a real problem — it's exactly the kind of feature to treat as progressive enhancement. A browser that doesn't understand it simply ignores the <script> block and loads the page normally, as before. Nothing breaks, no one is penalized — some visitors just get a faster navigation than others.
What it changes for a visitor
In practice: on a site that uses prerender carefully, clicking an internal link can feel like the next page was already there. No client-side routing, no extra framework, just a small JSON block in the <head>. That's the kind of improvement I like: it adds no complexity for the visitor, asks for no compromise on the site's simplicity, and only ever moves in one direction — toward faster, never toward less reliable.
Got a site that drags on navigation, or a project worth rebuilding on lighter foundations? Let's talk.