TL;DR / Speculative prerendering lets the browser fully render a page in a hidden tab before the user navigates to it, making the navigation appear instant.
How It Works
┌──────────────┐ ┌────────────┐ ┌──────────────┐
│ Current Page │ hint │ Browser │prerender Hidden Tab │
│ /products │───────→│ Prerender │───────→│ /products/42 │
└──────────────┘ └────────────┘ └──────────────┘
User hovers link fully rendered, JS executed
On click:
┌─────────────┐ ┌──────────────┐
│ User clicks │────────────→│ Instant swap │ ~0ms perceived load
└─────────────┘ └──────────────┘
Speculative prerendering is a browser-level optimization where a page is fully loaded, rendered, and executed in a hidden background context before the user actually navigates to it. When the user clicks the link, the browser swaps the hidden page into the visible tab. From the user's perspective, the page loads instantly — zero network wait, zero rendering delay.
The Speculation Rules API
Modern browsers (Chrome 121+) support the Speculation Rules API, which replaced the deprecated <link rel="prerender">. You provide hints about which pages the user is likely to visit next, and the browser decides whether to prerender them based on available resources and heuristics.
The API uses a JSON-based declarative syntax embedded in a <script type="speculationrules"> tag:
{
"prerender": [
{
"where": { "href_matches": "/products/*" },
"eagerness": "moderate"
}
]
}
The eagerness property controls when prerendering triggers: immediate starts prerendering as soon as rules are parsed, eager starts on minimal signal (hover), moderate starts on hover with a 200ms delay, and conservative starts only on mousedown/touchstart.
Prefetch vs. Prerender
Prefetching downloads the resource but does not execute it. Prerendering downloads, parses, renders, and executes the page — HTML, CSS, JavaScript, data fetches — everything. The page is in a fully interactive state in the hidden tab. This is why the navigation feels instant: there is literally nothing left to do except swap the tab into view.
The Speculation Rules API supports both: "prefetch" for lighter-touch resource loading and "prerender" for full page preparation. Prefetch is cheaper (just a network fetch) but provides less benefit. Prerender is more expensive (full page lifecycle) but eliminates all loading time.
How the Browser Manages Prerendered Pages
Prerendered pages live in a separate browsing context that shares the same storage partition as the current page. The browser imposes restrictions on the prerendered page until it is activated:
- No permission prompts — notification, geolocation, camera, and microphone requests are deferred until activation.
- No disruptive APIs —
window.alert(),window.confirm(), andwindow.print()are suppressed. - No audio playback — media autoplay is blocked.
- Gamepad, serial, USB, Bluetooth — APIs that interact with hardware are deferred.
When the user navigates to the prerendered page, the browser "activates" it by swapping it into the visible tab. The page receives a prerenderingchange event, and document.prerendering flips from true to false. Deferred operations then execute. This activation model prevents prerendered pages from affecting the user experience before navigation.
Analytics and Side Effects
Prerendering creates a measurement problem. If your page fires analytics events on load, a prerendered page will fire them before the user actually visits — or even if the user never visits. The solution is to check document.prerendering and defer analytics until the prerenderingchange event:
if (document.prerendering) {
document.addEventListener('prerenderingchange', () => {
trackPageView();
}, { once: true });
} else {
trackPageView();
}
This pattern applies to any side effect that should only trigger on actual navigation: ad impressions, A/B test enrollments, session starts, and timer-based events.
Framework Integration
Frameworks are beginning to integrate speculation rules. Astro supports injecting speculation rules via its <ClientRouter> component. Next.js uses its own prefetching mechanism for <Link> components (router-level, not the Speculation Rules API). You can also manage rules dynamically by injecting or removing <script type="speculationrules"> tags based on user behavior, viewport content, or application state.
The browser respects resource constraints. It will not prerender if the device is low on memory, the connection is slow (Save-Data header), or too many pages are already prerendered. Chrome currently limits concurrent prerenders and will discard the oldest prerendered page when the limit is reached.
Gotchas
- Prerendering is expensive. Each prerendered page consumes memory, CPU, and network bandwidth as if the user visited it. Prerendering too aggressively wastes resources and can slow down the current page.
- Analytics double-counting is easy to introduce. Always gate page view tracking behind the
prerenderingchangeevent or adocument.prerenderingcheck. Most analytics libraries do not handle this by default. - Cross-origin prerendering has restrictions. Same-site prerenders work broadly, but cross-site prerenders are more restricted and require opt-in via response headers.
- State mutations in prerendered pages can cause issues. If a prerendered page writes to
localStorageor modifies shared state, and the user never navigates there, that state change persists silently. - The Speculation Rules API is Chrome-only as of early 2026. Firefox and Safari do not yet support it. Always treat prerendering as a progressive enhancement, not a requirement.