Speculation Rules API for WordPress and WooCommerce

Speculation Rules API for WordPress and WooCommerce

Last verified: October 12, 2026
18 min read
Guide
Core Web Vitals
Full-stack developer

In 2026, users expect navigation under 2 seconds. Every additional second of loading time costs about 4.42% of conversions (Portent); the 7% figure that circulates is Akamai’s and measures 100 milliseconds. Google knows this and rewards fast sites with higher rankings.

This guide isn’t theory. It’s working code and a checklist you can implement today on your WordPress site or WooCommerce store. Speculation Rules help after checkout and cart fragments are already under control - for that sequence see the WooCommerce performance recovery case study and performance optimization 2026.

#How page speed affects bounce rate in 2026

#Bounce rate by page load time

Time to load (from 1s)Probability of bounce
3s+32%
5s+90%
6s+106%
10s+123%

Source: Google and SOASTA, mobile page speed benchmarks. The figures are the increase in the probability of a bounce relative to a one-second load, not absolute bounce rates. Think with Google

Google confirmed: Core Web Vitals are a ranking factor. In 2024, FID was replaced by INP (Interaction to Next Paint), a metric that measures page responsiveness to user interactions.

#What is perceived page speed

You can have a slow server (TTFB 800ms), but if the user sees content instantly and navigation feels instant, perceived performance is excellent.

That’s exactly what Speculation Rules API does, it preloads next pages in the background before the user clicks.

#Defer JavaScript, AVIF and TTFB in WordPress

Before implementing advanced techniques, make sure the fundamentals are solid.

#How to defer JavaScript in functions.php

// functions.php - Defer non-critical JS
add_filter('script_loader_tag', function($tag, $handle) {
    $defer_scripts = ['jquery', 'wp-embed', 'comment-reply'];
    if (in_array($handle, $defer_scripts)) {
        return str_replace(' src', ' defer src', $tag);
    }
    return $tag;
}, 10, 2);

#AVIF support in WordPress 6.5+

WordPress 6.5+ supports AVIF natively. AVIF offers 20-30% better compression than WebP.

<img 
  src="product.avif" 
  srcset="product-400.avif 400w, product-800.avif 800w"
  sizes="(max-width: 600px) 400px, 800px"
  loading="lazy"
  decoding="async"
  alt="Product"
>

#How to get TTFB under 200 ms

OptimizationTTFB Impact
PHP 8.3+ with OPcache-30%
Redis Object Cache-50%
CDN Edge Caching-70%
WP-Cron on system crontab-10%

#How to fix INP and CLS in WordPress

#How to fix INP by splitting long tasks

INP suffers when the main thread is blocked. Typical culprits:

  • Heavy page builders (Elementor, Divi)
  • Chat scripts (Intercom, Zendesk)
  • Tracking pixels (Facebook, Google Ads)

Solution: Break Long Tasks

// Split long tasks into smaller chunks < 50ms
async function longTask(items) {
    for (const item of items) {
        await processItem(item);
        // Yield to main thread
        await new Promise(resolve => setTimeout(resolve, 0));
    }
}

#How to prevent CLS from images and ads

/* Reserve space for images */
img {
    aspect-ratio: 16 / 9;
    width: 100%;
    height: auto;
}

/* Reserve space for ads */
.ad-slot {
    min-height: 250px;
}

#Speculation Rules API prefetch and prerender examples

This is the heart of this guide. Speculation Rules API is a native browser feature that allows preloading pages in the background.

<script type="speculationrules">
{
  "prefetch": [
    {
      "source": "document",
      "where": {
        "and": [
          { "href_matches": "/*" },
          { "not": { "href_matches": "/wp-admin/*" } },
          { "not": { "href_matches": "*.pdf" } }
        ]
      },
      "eagerness": "moderate"
    }
  ]
}
</script>

#Prerender for cart, checkout and product pages

<script type="speculationrules">
{
  "prerender": [
    {
      "source": "list",
      "urls": ["/cart/", "/checkout/"],
      "eagerness": "immediate"
    },
    {
      "source": "document",
      "where": {
        "or": [
          { "href_matches": "/product/*" },
          { "selector_matches": ".important-link" }
        ]
      },
      "eagerness": "moderate"
    }
  ]
}
</script>

#Prefetch vs prerender compared

TechniqueWhat It DoesWhen to UseResource Cost
PrefetchDownloads the HTML response only, no subresourcesBroad navigationLow
PrerenderLoads, renders and runs the page in a hidden tabHigh click probabilityHigh

#What the eagerness levels mean

  • conservative: on pointer down or touch down, the default for document rules
  • moderate: on desktop after a 200 ms hover (or pointer down if sooner); on mobile 500 ms after scrolling stops, for large links near the last tap
  • eager: since Chrome 143, after a 10 ms hover on desktop and 50 ms after a link enters the viewport on mobile
  • immediate: as soon as the browser reads the rules, the default for list rules

Timings come from the Chrome prerender guide. Before Chrome 143, eager behaved like immediate, so older articles that call it “immediately, aggressively” describe the previous behaviour.

#What WordPress 6.8 does with speculative loading by default

Since WordPress 6.8 the Speculation Rules API is part of core. The feature was ported from the Speculative Loading plugin, which ran on more than 50,000 sites before the merge, and the core dev note reports that sites using it improved their LCP passing rate by about 1.9% at the median, based on HTTP Archive and CrUX data. The same note says more than 8% of Chrome navigations already rely on speculation rules.

#Default speculative loading settings in WordPress core

Out of the box, core prints one ruleset on the frontend with mode prefetch and eagerness conservative. Both are stored as auto, so a future release can change what auto resolves to without breaking your configuration. Prefetching starts when the user presses the pointer on a link, which gives a small head start of a few hundred milliseconds and costs almost nothing in wasted requests.

Core switches the feature off in three situations:

  • for logged-in users, so the toolbar, previews and admin links are never speculated,
  • on sites without pretty permalinks,
  • for URLs with query parameters, which are excluded from prefetch and prerender by default.

The last rule matters for WooCommerce. Add-to-cart links use a query string, so the default configuration never prefetches them. A plugin that exposes other “action URLs” (GET requests that change state) still has to exclude them itself, especially if you raise the eagerness.

#How to change speculative loading with WordPress filters

Core exposes two filters and one action. wp_speculation_rules_configuration receives an array with mode and eagerness, or null when speculation is disabled for the request. Valid modes are auto, prefetch and prerender; valid eagerness values are auto, conservative, moderate and eager. immediate is rejected on purpose, because it is strongly discouraged for document-level rules.

// Switch the core rule to prerender on hover
add_filter( 'wp_speculation_rules_configuration', function ( $config ) {
    if ( is_array( $config ) ) {
        $config['mode']      = 'prerender';
        $config['eagerness'] = 'moderate';
    }
    return $config;
} );

// Keep personalised paths out of prerender only
add_filter( 'wp_speculation_rules_href_exclude_paths', function ( $paths, $mode ) {
    if ( 'prerender' === $mode ) {
        $paths[] = '/my-account/*';
    }
    return $paths;
}, 10, 2 );

// Add an extra rule next to the core rule
add_action( 'wp_load_speculation_rules', function ( WP_Speculation_Rules $rules ) {
    $rules->add_rule( 'prerender', 'shop-cart', array(
        'source'    => 'list',
        'urls'      => array( '/cart/' ),
        'eagerness' => 'moderate',
    ) );
} );

The exclude paths filter takes patterns in URL Pattern syntax, relative to the site frontend, and an optional $mode argument. The wp_load_speculation_rules action hands you a WP_Speculation_Rules object, and add_rule() accepts both list rules and document rules with a where condition. Returning null from the configuration filter turns speculation off for that request.

Editors can opt out single links without code. Add no-prefetch in the “Additional CSS class(es)” field of a block’s Advanced panel to exclude its links from speculative loading entirely, or no-prerender to allow a prefetch but block the prerender. Because prefetching is part of prerendering, no-prefetch covers both modes. This is the quickest fix when one widget, such as a booking calendar, misbehaves after a prerender.

#Speculative Loading plugin settings compared with core

The Speculative Loading plugin from the WordPress Performance Team still exists and is more aggressive than core. Its defaults are prerender with moderate eagerness, so a page is rendered in the background when the user hovers over a link. Mode and eagerness are configurable under Settings, Reading.

SettingWordPress core 6.8+Speculative Loading plugin
Default modeprefetchprerender
Default eagernessconservativemoderate
Logged-in usersalways offoff by default, opt in for all users or administrators
Excluded by defaultquery string URLswp-login.php, wp-admin, nonce URLs, nofollow links
RequirementsWordPress 6.8WordPress 6.9+, PHP 7.4+

The plugin warns when you enable speculation for logged-in users without a persistent object cache, because every speculated page then costs a full uncached PHP request. Its exclusion filter is called plsr_speculation_rules_href_exclude_paths. On a WooCommerce store with heavy logged-in traffic, keep logged-in speculation off until an object cache such as Redis is in place.

#How to add Speculation Rules in WordPress

#Method 1: add the rules in a custom plugin

On WordPress 6.8 and newer, core already prints its own speculationrules script. A custom script in wp_head adds a second ruleset next to it, so use this method only on older versions, or switch the core rule off first by returning null from wp_speculation_rules_configuration. On current versions the filters shown above are the cleaner path.

<?php
/**
 * Plugin Name: Speculation Rules API
 */
add_action('wp_head', function() {
    if (is_admin()) return;
    ?>
    <script type="speculationrules">
    {
      "prefetch": [
        {
          "source": "document",
          "where": {
            "and": [
              { "href_matches": "/*" },
              { "not": { "href_matches": "/wp-*" } }
            ]
          },
          "eagerness": "moderate"
        }
      ]
    }
    </script>
    <?php
});

#Method 2: dynamic rules for cart and pagination

add_action('wp_head', function() {
    $prerender_urls = [];
    
    // Prerender products from cart
    if (function_exists('WC') && WC()->cart) {
        foreach (WC()->cart->get_cart() as $item) {
            $prerender_urls[] = get_permalink($item['product_id']);
        }
    }
    
    // Prerender next archive page
    if (is_archive() || is_home()) {
        $next_link = get_next_posts_link();
        if ($next_link) {
            preg_match('/href="([^"]+)"/', $next_link, $matches);
            if (!empty($matches[1])) {
                $prerender_urls[] = $matches[1];
            }
        }
    }
    
    if (empty($prerender_urls)) return;
    
    $rules = [
        'prerender' => [[
            'source' => 'list',
            'urls' => array_unique($prerender_urls),
            'eagerness' => 'moderate'
        ]]
    ];
    
    echo '<script type="speculationrules">' . json_encode($rules) . '</script>';
});

#Speculation Rules results on a WooCommerce store and a blog

#Case study 1: WooCommerce store (500 products)

Problem: Navigation from category to product took seconds

Solution:

  • Prefetch for links in viewport
  • Prerender for “Add to Cart” and “Checkout”

Result:

  • Before: seconds of wait
  • After: perceived as instant
  • Bounce Rate: fell noticeably

#Case study 2: WordPress blog (1000+ articles)

Problem: INP outside the green band, users felt “lag”

Solution:

  • Defer all scripts
  • Prerender for “Read more”
  • Object Cache (Redis)

Result:

  • INP: moved into the green band
  • LCP: moved into the green band
  • Organic Traffic: grew

#Speculation Rules limitations and pages to exclude

#Which pages not to prerender

  • Pages with authentication (login, user panel)
  • Pages with side effects (subscriptions, payments)
  • External URLs

#Data Saver, browser support and the prerender limit

  • Data Saver disables speculation, see the full list of blocking conditions below
  • Non-supporting browsers (Firefox, and Safari without the experimental flag) ignore the rules
  • Prerender limit: Chrome allows 10 prerenders for immediate rules and only 2 for eager, moderate and conservative, where the oldest is dropped first

#Chrome speculation limits per eagerness level

Chrome caps how many speculations a page may hold at once, and the cap depends on eagerness. The figures below come from the Chrome prerender guide.

EagernessPrefetchPrerender
immediate5010
eager, moderate, conservative22

For the three interaction-based levels the queue works first in, first out: a new speculation cancels the oldest one. A cancelled URL can be speculated again later, and its cacheable resources are usually still in the HTTP cache. Removing a list rule script from the page frees immediate capacity, which is useful when a cart rule should give way to a different rule after checkout.

#When Chrome ignores speculation rules

Speculation rules are a hint, and Chrome drops them when:

  • the user has Save-Data enabled,
  • Energy Saver is on and the battery is low,
  • the device is short on memory,
  • the “Preload pages” setting is off, which some extensions such as uBlock Origin do,
  • the page is open in a background tab.

Prerendered pages also hold back cross-origin iframes until activation, so an embedded map or video player loads only when the user arrives. Speculation rules inside a prerendered page are processed after that page is activated, and rules in iframes are ignored.

#Prefetch fallback for browsers without support

if (!HTMLScriptElement.supports?.('speculationrules')) {
    // Fallback: classic prefetch
    document.querySelectorAll('a[href^="/"]').forEach(link => {
        link.addEventListener('mouseenter', () => {
            const prefetch = document.createElement('link');
            prefetch.rel = 'prefetch';
            prefetch.href = link.href;
            document.head.appendChild(prefetch);
        }, { once: true });
    });
}

#How to make WooCommerce pages safe to prerender

A prerendered page runs its JavaScript before the user sees it. That is the reason it feels instant, and the reason it can break a shop if the code assumes a real visit.

#Which WooCommerce URLs are unsafe to prefetch or prerender

MDN lists URLs with server-side side effects as unsafe for both prefetch and prerender: sign-out, language switching, add-to-cart, sending one-time SMS codes, consuming usage allowances and ad conversion tracking. In a WooCommerce store that means the logout link in My Account, a currency or language switcher implemented as a GET link, and any custom “buy now” URL. Pages are additionally unsafe to prerender when their scripts write client-side storage that other open tabs read, or when they send analytics or ad impressions before the user has seen the page.

Prerendered pages can also go stale. A page prerendered while the visitor was logged out still shows the signed-out view if the visitor logs in in another tab. Chrome may keep a prefetched page for about five minutes, so the content can be up to that old when it is shown.

#How to clear speculated pages after add to cart

The Clear-Site-Data response header accepts the values prefetchCache and prerenderCache. Sent on any same-site request, for example the AJAX call that adds a product to the cart, it discards speculations made before the cart changed. The next hover then fetches a fresh cart or checkout page instead of showing the old one.

// Drop stale speculations after WooCommerce changes the cart
add_action( 'woocommerce_add_to_cart', function () {
    if ( ! headers_sent() ) {
        header( 'Clear-Site-Data: "prefetchCache", "prerenderCache"' );
    }
} );

#How to detect speculative requests on the server

Chrome marks speculative requests with the Sec-Purpose request header. A prefetch sends Sec-Purpose: prefetch, a prerender sends Sec-Purpose: prefetch;prerender. Any final response outside the 200 to 299 range, after redirects, stops the speculation, and status 204 or 205 stops a prerender while still allowing a prefetch. Returning an error is the bluntest way to block speculation for a route. MDN recommends allowing the request and deferring side effects in JavaScript instead, because a blocked speculation is a lost speed gain.

#How to delay analytics until a prerendered page is shown

document.prerendering is true while the page renders in the background, and the prerenderingchange event fires when the user activates it. Wrap analytics, ad impressions and anything else that should count a real view:

function initTracking() {
    // analytics, ad impressions, chat widgets
}

if (document.prerendering) {
    document.addEventListener('prerenderingchange', initTracking, { once: true });
} else {
    initTracking();
}

Several browser APIs wait for activation on their own. Geolocation, notification permission requests, service worker registration and camera access return a pending promise until the page is shown, while alert() returns at once and confirm() returns false, according to MDN. Code that relies on those results during page load needs the same guard.

#Speculation Rules browser support in 2026

BrowserPrefetchPrerenderNotes
Chrome 121+YesYesPrefetch since 110, prerender since 105, document rules and eagerness since 121
Edge 121+YesYesSame versions as Chrome
Opera 107+YesYesDocument rules since 107
Safari 26.2Flag onlyNoPrefetch behind the “SpeculationRules prefetch” preference
FirefoxNoNoNot implemented

Versions come from MDN browser compatibility data, which still marks the feature as experimental and not Baseline. In practice the rules speed up Chromium users and do nothing elsewhere, which is why WordPress core treats them as progressive enhancement.

#How to use Speculation Rules with a Content Security Policy

#How to allow speculation rules under a strict CSP

A speculation rules block is a <script> element, so a strict script-src policy blocks it like any inline script. MDN lists three ways to allow it: a nonce, a hash, or the 'inline-speculation-rules' keyword. The Chrome guide adds that the keyword covers rules injected with a hash or nonce, so on strict-CSP sites the rules are usually inserted with JavaScript. If the Speculative loads panel shows no rules on a site with a security plugin, the CSP header is the first thing to check.

#How to serve speculation rules with the Speculation-Rules header

Rules can also live in a JSON file referenced by an HTTP response header, which keeps them out of the HTML and out of the CSP problem. The URL in the header must be in quotes, the file must use the application/speculationrules+json MIME type, and a cross-origin file must pass a CORS check. By default, relative URLs in the file resolve against the JSON file, so add "relative_to": "document" to a rule if its paths are relative to the page.

Speculation-Rules: "/speculationrules.json"

Rules from the header and inline rules are merged into one set. Chrome 136 added the tag field, which is sent in the Sec-Speculation-Tags request header, so a CDN or server can tell which ruleset triggered a request and treat it differently.

#Which cross-origin speculations Chrome allows

Prerender is limited to the same origin by default. A same-site subdomain, such as a shop on its own subdomain, can be prerendered only if it answers with the Supports-Loading-Mode: credentialed-prerender header, and cross-site prerender is not possible at all. Cross-site prefetch works only when the user has no cookies for the target site, which prevents tracking. Rejected speculations of this kind show up in the Speculative loads panel of DevTools.

#How to monitor Speculation Rules prefetches

#Tools to check speculative loads

  • Chrome DevTools: the Speculative loads panel in the Application tab
  • Lighthouse CI: Performance test automation
  • WebPageTest: Real tests from different locations
  • DebugBear: Real User Monitoring (RUM)

#How to track speculative hits in GA4

Resource Timing has no “speculation” initiator type, so a speculative load cannot be observed from the page that triggered it. Measure on the page the user lands on instead: activationStart above zero means the page was prerendered, and a deliveryType of navigational-prefetch means it came from a prefetch. Both fields are documented on MDN.

// Report how the current page was delivered
const nav = performance.getEntriesByType('navigation')[0];
let delivery = 'normal';
if (nav.activationStart > 0) {
    delivery = 'prerender';
} else if (nav.deliveryType === 'navigational-prefetch') {
    delivery = 'prefetch';
}
gtag('event', 'page_delivery', { delivery_type: delivery });

Compare the number of prerender and prefetch hits with the number of speculative requests your server logs show (see the Sec-Purpose header above). The gap is the waste. Chrome measures Core Web Vitals for a prerendered page from activation, not from the start of the prerender, and the web-vitals library from version 3.1.0 reports such navigations with a navigationType of prerender, according to the Chrome prerender guide. Segment your field data by that value, or the near-zero LCP of prerendered views will hide a slow normal navigation.

#Speculation Rules implementation checklist for WordPress

#Before implementation

  • Measure baseline Lighthouse score
  • Check TTFB < 200ms
  • Ensure Object Cache is active
  • Images are served as AVIF

#During implementation

  • Add basic prefetch (moderate)
  • Analyze heatmaps (Hotjar, Clarity)
  • Identify top 3 navigation paths
  • Add prerender for high-intent links
  • Test on 10% traffic (A/B)
  • Monitor “wasted” prefetches

#After implementation

  • Compare LCP, INP, Navigation Time
  • Check Cache Hit Ratio
  • Long-term: Bounce Rate, Conversion Rate

#Summary

Speculation Rules API is a significant shift for 2026. By preloading pages in the background, navigation becomes instant, without any infrastructure changes.

Key takeaways:

  1. Start with prefetch with moderate eagerness, it’s safe
  2. Add prerender for checkout flow in e-commerce
  3. Monitor metrics, don’t guess, measure

Need professional optimization? As a WordPress specialist, I help speed up WordPress and WooCommerce sites. Also see WordPress speed optimization.

Next step

Turn the article into an actual implementation

This block strengthens internal linking and gives readers the most relevant next move instead of leaving them at a dead end.

Related cluster

Explore other WordPress services and knowledge base

Strengthen your business with professional technical support in key areas of the WordPress ecosystem.

Article FAQ

Frequently asked questions

Practical answers to apply the topic in real execution.

SEO-readyGEO-readyAEO-ready3 Q&A
What does the Speculation Rules API do in WordPress?#
It lets the browser prefetch or prerender likely next pages, which can make navigation feel instant when used on the right internal paths.
Is prefetch or prerender better for WooCommerce?#
Prefetch is safer for broader navigation. Prerender is stronger, but should be limited to high-intent paths like product to cart or cart to checkout.
Can the Speculation Rules API hurt Core Web Vitals?#
Yes, if you prerender too aggressively. It works best after image, JavaScript and server bottlenecks are already under control.

Need an FAQ tailored to your industry and market? We can build one aligned with your business goals.

Let’s discuss

Related Articles