Migrating From instant.page to the Speculation Rules API
This site previously used instant.page to optimize internal navigation. Its working model is easy to understand: when the user hovers over a link, the script inserts <link rel="prefetch" as="document"> and downloads the next page’s HTML in advance. When the user actually clicks, the browser waits for one fewer network request, so the page feels faster.
That approach is lightweight and reliable. But it is still a third-party script, and what it does essentially stops at prefetch: it can fetch the target document ahead of time, but it cannot start running the page ahead of time.
Chromium-based browsers now offer a more native option: Speculation Rules API. It lets us use a piece of JSON to tell the browser which pages are likely to be visited and how far it should prepare them in advance.
Scope
Speculation Rules API is for document navigation, meaning navigation from one HTML document to another HTML document. It is especially suitable for MPAs, static sites, content sites, and flows such as product listings to product detail pages.
It is not a general-purpose resource preloading tool. The MDN docs explicitly point out that Speculation Rules API does not prefetch a page’s subresources. If you want to load a JS chunk, font, or image ahead of time, that is still a matter for <link rel="prefetch">, preload, or the framework’s own resource scheduling.
It is not a mandatory command either. The browser treats the rules as hints, then decides whether to execute them based on network conditions, memory, battery, user settings, and its own heuristics. Browsers that do not support it ignore <script type="speculationrules">, so it is well suited as progressive enhancement.
prefetch and prerender
The two most common actions in Speculation Rules are prefetch and prerender.Action What the browser does Cost Suitable for prefetchRequests the target document in advance; does not load subresources or run page scripts Low A safer replacement for instant.page prerenderLoads and renders the target page in the background, including subresources and scripts High Targets that are very likely to be visited, with controllable side effects
The table shows that prerender is a more aggressive optimization: the browser prepares a hidden page in the background, and the target page’s DOM, styles, layout, and scripts may already have run. When the user clicks, the browser can directly activate the background page into the foreground. If the background page is not fully ready yet, it can continue loading with the work already completed.
Public case studies show its upper bound. web.dev has a few relevant numbers: after Ray-Ban used prerender, mobile LCP dropped from 4.69 seconds to 2.66 seconds; Monrif improved desktop LCP by 17.9% and user engagement by 8.9%.[1] These numbers do not mean every blog can reproduce the same gain, but they are enough to show that the API can provide real value in the right scenario.
Example Rules for a Blog
If the goal is just to replace instant.page, prefetch is enough. For this site, internal links in a static blog have relatively simple state, so some ordinary article navigations can be handed to prerender.
A restrained starting point can look like this:<script type="speculationrules"> { "prerender": [ { "where": { "and": [ { "href_matches": "/*" }, { "not": { "selector_matches": "a[href^='#']" } }, { "not": { "selector_matches": "a[href*='?']" } }, { "not": { "selector_matches": "a[target='_blank']" } }, { "not": { "selector_matches": "a[download]" } }, { "not": { "selector_matches": "a[rel~='nofollow']" } }, { "not": { "selector_matches": "a[data-no-prerender]" } } ] }, "eagerness": "moderate" } ] }</script>
If the site is more complex, change "prerender" above to "prefetch" first, replace instant.page with the browser’s native capability, and only then consider whether to use prerender. That is the more conservative migration order.
Choosing eagerness
eagerness controls when the browser starts predictive loading. It is not “the more aggressive, the better”; it is about finding a point between hit rate and wasted resources.Value Rough trigger timing My interpretation immediateStarts as soon as possible after the rule is observed Only suitable for a very small number of almost-certain entries eagerEarlier than moderateGood for a few high-probability links; not for site-wide use moderateOn desktop, usually about 200ms after hover, or earlier on pointerdown A balanced starting point for ordinary content sites conservativeClose to the actual mouse press or touch Saves the most resources, with the most limited gain
Mobile has no hover, so Chrome uses touch- and viewport-related heuristics to infer intent. Do not mechanically understand moderate as “mouse hover for 200ms.” This means the same rules can trigger differently on different devices, and the browser will suppress some predictive loading depending on the current environment.
Chrome also has hard limits to prevent sites from overusing user device resources. The current documentation lists these limits:eagernessPrefetch Prerender immediate50 10 eager / moderate / conservative2, FIFO 2, FIFO
In other words, for interaction-driven rules such as moderate, the browser usually keeps only two candidates at the same time. When a new candidate comes in, an old one will be canceled. Add Save-Data, low-power mode, memory pressure, users disabling “preload pages,” and extensions that actively block preloading, and the final decision still belongs to the browser.
Side Effects This Site Needs to Avoid
The risks of prerender depend on the type of application. For a personal blog like this one, there is no login, logout, shopping cart, payment, inventory, or similar state, so there is no need to import every pitfall from business systems.
The first thing this site needs to handle is analytics bias. prerender can run target-page scripts in the background, so pageview counts may fire before the user truly enters the page. If the user never clicks the link, analytics will be higher than actual visits.const whenActivated = new Promise((resolve) => { if (document.prerendering) { // The current page is still prerendering in the background. // Continue only after it is actually opened by the user. document.addEventListener("prerenderingchange", resolve, { once: true }); } else { // A page entered through normal navigation is already visible, // so later initialization can run directly. resolve(); }});whenActivated.then(() => { // These should run only after the page is truly displayed, // to avoid polluting analytics during prerendering. initAnalytics(); initComments();});
The second issue is extra request pressure. If immediate is used on a large number of links, server request volume will increase accordingly, especially when some of those links include expensive computation or resource requests. The bill follows 🧾
That is also why this site uses moderate: wait until the user shows intent before prerendering, which wastes fewer resources.
Conflict Between prerender and Swup/PJAX
The prerequisite for prerender is document navigation, meaning the browser switches from one HTML document to another HTML document.
Swup and PJAX intercept link clicks, fetch HTML themselves, and update the page content. Throughout this process, the browser still sees only the same document; no real page navigation has happened. Since that is the case, a prepared prerendered page has no way to be activated.
Therefore, this site eventually abandoned Swup, returned to browser-native navigation, and used the cross-document View Transitions API for a small optimization. The current effect is simple: during page switches, the navigation bar no longer flickers with the full page reload.
But all of that was generated by Codex. I do not know the implementation principle at all. After I understand it, I will write a separate analysis.
Verification Method
The verification method is difficult to explain in text. It takes effort and gives little back. I am tired by this point, so if you are interested, watch the video yourself 👇
Conclusion
If the goal is only to replace instant.page, start with Speculation Rules prefetch. If you want to use prerender, consider the side effects above and its compatibility with SPA navigation approaches such as Swup/PJAX.
Data source: web.dev’s Ray-Ban and Monrif case studies, respectively Ray-Ban case study and Monrif case study; accessed on 2026-06-04. ↩︎