The Speculation Rules API is a browser primitive that lets you instruct Chromium-based browsers to prefetch or prerender future navigations based on structured rules you supply. Unlike resource hints, which target individual files, Speculation Rules target full document URLs — making them purpose-built for multi-page applications (MPAs).
A fully prerendered page is held in an invisible, in-memory browsing context. The browser fetches the HTML, discovers and loads all subresources (CSS, images, fonts), runs JavaScript, and completes layout — all before the user has clicked a single link. When the user does navigate, the browser swaps in the already-rendered page near-instantly instead of starting a fresh fetch cycle.
Real-world data from CoreDash shows prerendered navigations achieving a p75 LCP of 320 ms versus 1,800 ms for standard navigations on the same sites — an 82% improvement attributable to this single API. Even Google Search uses speculation rules to prefetch top results, saving approximately 67 ms on Android LCP per click. Numbers like that are hard to ignore.
Three Speculation Types: Choosing the Right Level of Commitment
The API offers three speculation types, each representing a different point on the cost-versus-speed tradeoff curve. So, let's walk through them.
Prefetch
Prefetch downloads the HTML document and stores it in the HTTP cache. It doesn't parse, render, or run any JavaScript. When the user navigates, the browser skips the network round-trip but still must parse the DOM, discover subresources, and execute scripts. Prefetch is cheap — roughly one extra network request — and safe for almost any URL. Use it for broad coverage when prediction confidence is low.
Full Prerender
Full prerender builds a complete, live browsing context in the background. HTML is parsed, CSS applied, JavaScript executed, subresources fetched, and layout completed. Activation swaps in this hidden page with essentially zero latency. The cost is proportionally higher — memory, CPU, and network equivalent to loading the page in a background tab. Reserve full prerender for high-confidence next steps (e.g., a dedicated "Start Checkout" button). Don't spray it everywhere.
Prerender-Until-Script (Chrome 144+, 2026)
The newest addition, shipping as an origin trial from Chrome 144 (January 2026), sits between the two: the browser fetches and parses the HTML, begins rendering, and loads all subresources — but halts at the first synchronous <script> tag rather than executing JavaScript. The result is that CSS, images, and fonts are cached and the DOM is built, but no script side-effects (analytics pings, ad calls, server mutations) occur until the user actually navigates. Compared to full prerender it's meaningfully cheaper and safer; compared to plain prefetch, activation is significantly faster because layout has already started.
- Prefetch — low-confidence predictions, pages with heavy scripts or side-effects you can't control
- Prerender-until-script — moderate-confidence predictions, pages with complex scripts you want to keep safe from side-effects
- Full prerender — high-confidence predictions where scripts are analytics-safe via the
document.prerendering guard
Implementing Speculation Rules: Four Methods
There are four ways to deliver speculation rules to the browser, each suited to a different deployment context. Pick the one that fits your stack.
Method 1: Inline HTML Script Tag
The simplest approach — drop a <script type="speculationrules"> block anywhere in the document. The browser parses the JSON and acts immediately.
<script type="speculationrules">
{
"prefetch": [
{
"where": { "href_matches": "/*" },
"eagerness": "moderate"
}
],
"prerender": [
{
"where": { "href_matches": "/product/*" },
"eagerness": "moderate"
}
]
}
</script>
This rule prefetches any same-origin URL on moderate hover intent and fully prerenders product pages on the same signal. It's the best starting point for most content or e-commerce sites — I'd typically start here and tighten from there based on field data.
Method 2: Dynamic JavaScript Rules
For logic-driven speculation — such as prerendering the checkout page only after an item is added to the cart — inject rules at runtime:
function addSpeculationRule(rules) {
if (!HTMLScriptElement.supports?.('speculationrules')) return;
const script = document.createElement('script');
script.type = 'speculationrules';
script.textContent = JSON.stringify(rules);
document.head.appendChild(script);
}
document.getElementById('add-to-cart').addEventListener('click', () => {
addSpeculationRule({
prerender: [{ urls: ['/checkout'], eagerness: 'eager' }]
});
});
Always guard with HTMLScriptElement.supports?.('speculationrules'). The optional chaining ensures silent fallback in Firefox and Safari without runtime errors.
Method 3: HTTP Response Header
Deliver rules via a Speculation-Rules HTTP header pointing to a JSON file. This requires no HTML changes, making it ideal for CDN-level deployment:
# Nginx example
location / {
add_header Speculation-Rules '"/speculation-rules.json"';
}
// /speculation-rules.json
{
"prefetch": [
{
"where": { "href_matches": "/*" },
"eagerness": "moderate"
}
]
}
Note the double-quoting: the header value is a JSON string that contains a URL path to the rules file. It's a small gotcha that trips people up the first time.
Method 4: WordPress Plugin
If you run WordPress, the official Speculation Rules plugin (developed by the Chrome team in collaboration with WordPress Core) provides a settings panel to enable prefetch or prerender site-wide with a single toggle — no code required. Set eagerness to moderate for an immediate performance win.
Eagerness Settings: Controlling When Speculation Fires
Eagerness is the most important tuning knob in the API. It determines what user signal triggers the speculation, and it controls Chrome's concurrency limits for background loading. Get this right and you'll see real gains; get it wrong and you'll hammer your servers unnecessarily.
| Setting | Desktop trigger | Mobile trigger (Chrome 144+) | Concurrency cap |
immediate | On script parse | On script parse | 50 prefetch / 10 prerender |
eager | 10 ms hover | 50 ms after link enters viewport | 50 prefetch / 10 prerender |
moderate | 200 ms hover or pointerdown | pointerdown | 2 prefetch / 2 prerender (FIFO) |
conservative | pointerdown / touchstart | touchstart | 2 prefetch / 2 prerender (FIFO) |
Recommendation for most sites: moderate eagerness. The 200 ms hover threshold captures genuine intent while filtering out accidental cursor drift. The FIFO concurrency limit of 2 keeps memory and bandwidth modest. immediate is suitable only for critical funnel steps where user intent is near-certain (think: the one button the user is almost certainly going to click next). Note that Chrome 144 made a significant change for mobile: eager now triggers 50 ms after a link enters the viewport, rather than waiting for hover — enabling aggressive mobile prefetching without requiring touch interaction.
Chrome automatically disables all speculation when the user has Data Saver mode enabled, the device is in Energy Saver mode with low battery, or the user has turned off the "Preload pages" Chrome setting. You don't need to build your own device-aware fallback — the browser handles it.
Prerender-Until-Script: The 2026 Middle Ground
The prerender_until_script type is available as an origin trial from Chrome 144 through Chrome 150. Enable it by registering for a token at the Chrome Origin Trials portal, or test locally via chrome://flags/#prerender-until-script.
<script type="speculationrules">
{
"prerender_until_script": [
{
"where": { "href_matches": "/blog/*" },
"eagerness": "moderate"
}
],
"prefetch": [
{
"where": { "href_matches": "/blog/*" },
"eagerness": "moderate"
}
]
}
</script>
Notice the companion prefetch rule. Browsers that don't recognise prerender_until_script skip it and honour the prefetch rule instead. This gives you progressive enhancement: the best experience on Chrome 144+, a solid fallback on older Chromium versions, and graceful degradation everywhere else.
Key caveats for prerender_until_script:
- The parser halts at the first synchronous
<script> tag, including inline scripts. An inline script early in <head> (e.g., a cookie check) becomes the stop point — audit your markup and move critical inline scripts as late as possible.
- Inline event handlers like
onload="..." and javascript: URLs are not script elements and may still execute — scan your HTML for these patterns.
document.prerendering is not readable (since JS doesn't run), but performance.getEntriesByType('navigation')[0].activationStart will be non-zero on activation, which you can use for post-activation analytics.
Excluding Sensitive Routes
Never speculate on URLs that trigger server-side side-effects. The most dangerous candidates are state-mutation endpoints — and yes, I've seen speculation rules accidentally prefetch logout URLs in production. Don't be that person.
<script type="speculationrules">
{
"prefetch": [
{
"where": {
"and": [
{ "href_matches": "/*" },
{ "not": { "href_matches": "/logout" } },
{ "not": { "href_matches": "/cart/add*" } },
{ "not": { "href_matches": "/account/delete*" } },
{ "not": { "href_matches": "/*\?*" } }
]
},
"eagerness": "moderate"
}
]
}
</script>
The pattern { "not": { "href_matches": "/*\?*" } } excludes all URLs containing query strings — a safe default since query strings often indicate search results, filtered listings, or session tokens. Adjust the exclusion list based on your specific URL structure.
Making Analytics and Ads Prerender-Safe
The most common concern about prerendering is that analytics events fire before the user actually views the page, inflating pageview counts. Honestly, this is the question I get asked most often about this API. The fix is the document.prerendering property — set to true while the page is prerendering — combined with the prerenderingchange event that fires on user activation:
function sendPageView() {
// Your analytics call here
gtag('event', 'page_view', { page_path: location.pathname });
}
if (document.prerendering) {
document.addEventListener('prerenderingchange', sendPageView, { once: true });
} else {
sendPageView();
}
Google Analytics 4 and Google Publisher Tag (GPT) implement this guard natively as of 2025. If your analytics stack uses these, you're covered without additional code. For custom event tracking or other providers, add the guard manually around every tracking call that fires at page load.
Measuring the Impact on Core Web Vitals
Prerendered navigations report Core Web Vitals differently. Because the page is already rendered when the user arrives, LCP, INP, and CLS are measured from the activation timestamp (activationStart) rather than navigation start. This means CWV scores for prerendered pages often look exceptional in lab tools like Lighthouse; field data from CrUX and Google Search Console reflects actual user experience correctly.
For SPAs and sites using the Soft Navigations API, it's worth understanding how Core Web Vitals are measured across soft navigations in 2026 — the measurement model shares meaningful nuance with prerendered activation timestamps.
Prerendering also interacts positively with the Back/Forward Cache (bfcache): a prerendered page that the user navigates to is stored in bfcache normally after activation, meaning subsequent back-button taps are also instant with no additional work. It's a nice compounding effect.
Debugging Speculation Rules in Chrome DevTools
Chrome DevTools has a dedicated interface for inspecting speculation rules at runtime:
- Open DevTools and go to the Application panel.
- Under Background Services in the left sidebar, click Speculative loads.
- The panel shows all active rules, each URL currently being speculated on, and its status (success, skipped due to Energy Saver mode, failed, etc.).
For programmatic detection, check the activationStart property on the navigation timing entry:
const nav = performance.getEntriesByType('navigation')[0];
if (nav.activationStart > 0) {
console.log('Page activated from prerender');
console.log(`Activation delay: ${nav.activationStart.toFixed(1)} ms`);
}
Browser Support and Progressive Enhancement
As of mid-2026, support is as follows:
- Chrome / Edge 109+: Full prefetch and prerender support
- Chrome 144+: Origin trial for
prerender_until_script
- Firefox: Positive standards position on prefetch; no shipping support yet
- Safari: No support announced
Chromium-based browsers cover roughly 79% of global browser traffic, so the majority of your users benefit immediately. Non-supporting browsers silently ignore the <script type="speculationrules"> block — no polyfill required, no risk of errors. For maximum reach on Firefox and Safari, pair your speculation rules with <link rel="prefetch"> for critical next-step URLs; Chromium takes the richer Speculation Rules path while other browsers use the link hint.
Common Pitfalls to Avoid
Over-Speculating on Mobile
Bandwidth and memory are constrained on mobile. Stick to moderate or conservative eagerness for prerender rules, and prefer prefetch for broad URL patterns. Chrome's concurrency limits prevent the worst-case scenario, but thoughtful rule design — targeting high-probability navigations rather than entire site sections — keeps the user experience consistent on mid-range devices.
Ignoring Backend Load at Scale
At traffic scale, speculation rules multiply backend request volume. A page with 20 links and eager prerender can generate up to 10 simultaneous background page loads per active user. Audit server capacity before enabling aggressive rules, and consider disabling speculation rules during peak events (flash sales, product launches) by feature-flagging the script block.
Speculating on Cross-Origin URLs
Cross-site prefetches only work if the user has no existing cookies for the destination site — a privacy safeguard against speculation-based tracking. Cross-origin prerender isn't supported at all. Keep speculation rules to same-origin URLs unless you have a specific cross-origin prefetch case and understand the cookie constraint.
A Production-Ready Baseline Configuration
Here's a battle-tested starting configuration for a content site or e-commerce shop. Copy it into your <head> and adjust the URL patterns to match your routes:
<script type="speculationrules">
{
"prefetch": [
{
"where": {
"and": [
{ "href_matches": "/*" },
{ "not": { "href_matches": "/logout*" } },
{ "not": { "href_matches": "/checkout/confirm*" } },
{ "not": { "href_matches": "/*\?*" } }
]
},
"eagerness": "moderate"
}
],
"prerender": [
{
"where": {
"or": [
{ "href_matches": "/product/*" },
{ "href_matches": "/blog/*" },
{ "href_matches": "/pricing" }
]
},
"eagerness": "moderate"
}
]
}
</script>
This configuration prefetches broadly on hover intent while reserving full prerender for high-value content paths. The exclusion list prevents state-mutating endpoints from receiving speculative fetches. Start here, measure with CrUX field data in Google Search Console, then iterate toward tighter URL targeting on your highest-traffic pages.
If you're also optimizing how scripts load on these pages, pairing speculation rules with JavaScript bundle optimization techniques means users not only arrive instantly but also see scripts that execute fast once they do.
Frequently Asked Questions
Does the Speculation Rules API work on all browsers?
No — the API is currently supported only in Chromium-based browsers (Chrome and Edge 109+), which cover roughly 79% of global traffic. Firefox has a positive standards position on the prefetch portion but hasn't shipped support yet. Safari has made no announcement. Unsupporting browsers silently ignore the script block without errors, making the API safe to deploy as a progressive enhancement.
Will prerendering double my server load?
It can increase backend requests, especially with aggressive eagerness settings. Using moderate eagerness with Chrome's concurrency limit of 2 concurrent prerenders keeps overhead manageable for most sites. For high-traffic or peak-event scenarios, feature-flag the speculation rules block and disable it during those windows to protect server capacity.
Will analytics fire twice if a page is prerendered?
Not if you use the document.prerendering guard. Google Analytics 4 and Google Publisher Tag handle this natively since 2025. For custom tracking code, wrap page-load analytics calls in a check: fire immediately if document.prerendering is false, or listen for the prerenderingchange event and fire on activation.
What is prerender-until-script and how does it differ from full prerender?
prerender_until_script (Chrome 144 origin trial) fetches HTML, begins rendering, and loads all subresources — but pauses before executing any JavaScript. It's cheaper and safer than full prerender (no script side-effects such as analytics or server mutations), while being significantly faster on activation than plain prefetch because the DOM is built and subresources are cached.
How do I check which pages are actually being prerendered?
Open Chrome DevTools, go to the Application panel, and click "Speculative loads" under Background Services. This panel lists every active rule, each URL the browser is speculating on, and the outcome (success, skipped, failed). You can also detect a prerendered activation in JavaScript by checking whether performance.getEntriesByType('navigation')[0].activationStart is greater than zero.