Compiling ideas into code…
Wiring up APIs and UI…
Sit back for a moment while the site gets ready.
ShopifyArchitecture

Speculation Rulesin Shopify

What the Speculation Rules API Changes

The traditional approach to page speed optimization focuses on everything that happens after the click. Compress images, split code bundles, configure CDN caching, optimize server response times. These are table-stakes optimizations, and most Shopify stores have already done them. The Speculation Rules API shifts the strategy to what happens before the click.

While the user is still browsing a collection page, deciding which product to click, the browser quietly loads the most likely next pages in the background. When the user finally clicks, the destination page is already fully rendered in a hidden browsing context. The navigation swap appears instant. For e-commerce where every 100ms of load time affects conversion rate, this is the highest-impact performance optimization available without touching server infrastructure.


Prefetch vs Prerender

The API offers two levels of speculation, and choosing the right one matters.

Prefetch downloads the HTML document and critical subresources ahead of time. It does not execute JavaScript or render the page. The cost is modest, roughly 50-200KB of bandwidth per speculated page. When the user navigates, the browser still needs to parse and render, but the network round-trip is eliminated.

Prerender goes much further. It fully loads, parses, renders, and executes JavaScript in an invisible browsing context. The result is near-zero latency when the user navigates, the browser swaps in a page that's already been fully painted. The cost is real: CPU, memory, and bandwidth equivalent to loading an invisible page.

When to use each: prefetch works best for many likely targets with uncertain intent, all product links on a collection page, triggered on hover. Prerender suits high-confidence single targets, the checkout button on the cart page, or the first product in a curated hero collection.


The Speculation Rules JSON Format

Unlike the older <link rel="prefetch"> approach, Speculation Rules use a structured JSON format inside a dedicated script tag. This gives you fine-grained control over targeting, conditions, and timing.

speculation-rules.json
{
  "prefetch": [{
    "source": "document",
    "where": {
      "and": [
        { "href_matches": "/products/*" },
        { "not": { "href_matches": "/products/*.js" } },
        { "selector_matches": ".product-card a" }
      ]
    },
    "eagerness": "moderate"
  }],
  "prerender": [{
    "source": "document",
    "where": {
      "selector_matches": ".featured-product a"
    },
    "eagerness": "eager"
  }]
}

source: "document" tells the browser to scan the current page's DOM for links matching the specified conditions. This is the most useful mode for Shopify themes, the browser dynamically discovers speculative targets as the page renders.

where defines the matching conditions. You can combine href_matches (URL patterns with wildcards), selector_matches (CSS selectors), and logical combinators (and, not, or) to precisely target the right links.

eagerness controls when the speculation triggers. This is where the performance-versus-resource trade-off lives, and it deserves its own explanation.


Eagerness Levels Explained

immediate triggers as soon as the rules are parsed. The browser begins speculating without waiting for any user interaction. Use this for known next-page scenarios, checkout after cart, the next step in a paginated flow.

eager triggers when a matching link enters the viewport. Good for above-fold product cards where you're reasonably confident the user will engage with the visible content.

moderate triggers on hover with a short dwell threshold of roughly 200ms. This is the best option for product grids, it only fires when the user shows genuine interest in a specific link, keeping resource usage low while still providing a meaningful head start.

conservative triggers on pointer-down or touch-start, the moment just before the browser would begin navigation anyway. The lowest resource cost, highest confidence, but the smallest time advantage.

For most Shopify stores, moderate is the sweet spot. It fires on hover, which gives roughly 300-500ms of head start before the click. For prefetch, this is usually enough to download the entire HTML document. For prerender, it may not complete before the click, but partial prerender still helps, the browser has already begun fetching subresources and parsing.


Integrating with Shopify Liquid Themes

Adding Speculation Rules to a Shopify theme means injecting a <script type="speculationrules"> block in your theme.liquid layout. Here's a production-ready configuration that covers the most common Shopify navigation patterns.

theme.liquid
<script type="speculationrules">
{
  "prefetch": [{
    "source": "document",
    "where": {
      "and": [
        { "href_matches": "{{ routes.root_url }}products/*" },
        { "selector_matches": ".product-card a, .product-grid a" }
      ]
    },
    "eagerness": "moderate"
  },
  {
    "source": "document",
    "where": {
      "href_matches": "{{ routes.root_url }}collections/*"
    },
    "eagerness": "conservative"
  }],
  "prerender": [{
    "source": "document",
    "where": {
      "selector_matches": ".hero-product a, .featured-collection a:first-child"
    },
    "eagerness": "eager"
  }]
}
</script>

The {{ routes.root_url }} Liquid object is Shopify's locale-aware root URL. On a single-language store, it resolves to /. On multi-language stores, it changes to /fr/, /de/, or whatever the active locale prefix is. Using it in href_matches patterns ensures your speculation rules work correctly across all locales without hardcoding paths.

Place the speculation rules script just before the closing body tag. The browser needs to parse the DOM before it can match CSS selectors in your selector_matches conditions. Placing the script in <head> would require waiting for the DOM to be ready, delaying when speculation begins.


Targeting the Right Pages

Not every page deserves the same speculation strategy. The right approach depends on the user's likely next action at each point in the browsing journey.

Collection pages, prefetch product pages on hover (moderate). Most collection pages show 20-50 products. Prefetching all of them on viewport entry would waste bandwidth on links the user never intends to click. Hover-triggered prefetch is the right balance: low resource cost, meaningful speed improvement for the pages the user actually considers.

Product pages, prerender checkout or the first "You may also like" product (eager). The customer has high purchase intent on PDP. The most likely next click is either "Add to Cart" followed by checkout, or browsing to a recommended product. Prerendering the most probable target makes the transition feel instant.

Cart page, prerender checkout (immediate). The customer is actively moving toward purchase. The next page is almost certainly checkout, and the conversion impact of a faster checkout transition is significant.

Homepage, prefetch featured collection links (moderate). Don't prerender here, there are too many possible next clicks to make a confident prediction. Prefetching on hover gives a speed boost without wasting resources on pages the user may never visit.


Excluding URLs That Shouldn't Be Speculated

Some same-origin URLs trigger side effects when loaded, adding items to cart, initiating checkout sessions, or hitting API endpoints. These must be explicitly excluded from speculation rules.

speculation-rules-with-exclusions.json
{
  "prefetch": [{
    "source": "document",
    "where": {
      "and": [
        { "href_matches": "/products/*" },
        { "not": { "href_matches": "/cart*" } },
        { "not": { "href_matches": "/checkout*" } },
        { "not": { "href_matches": "https://external-domain.com/*" } },
        { "not": { "selector_matches": "[data-no-prefetch]" } }
      ]
    },
    "eagerness": "moderate"
  }]
}

The [data-no-prefetch] selector exclusion is particularly useful as a safety valve. Adding data-no-prefetch to any link in your theme markup instantly excludes it from speculation, giving theme developers fine-grained control without modifying the rules themselves.

Speculation Rules only apply to same-origin navigations. Links to external domains are automatically excluded by the browser. Shopify checkout URLs (checkout.shopify.com) are cross-origin, so they're excluded by default. The exclusions above target same-origin URLs that shouldn't be speculated, like AJAX cart endpoints or internal API routes.


Performance Measurement

Verifying that speculation rules are working correctly requires checking multiple signals.

Chrome DevTools → Application → Speculative loads shows which URLs were prefetched or prerendered, along with the rule that triggered each speculation and any failures. This is the primary debugging tool.

Network panel, filter requests by "prefetch" to see speculated network activity. Prefetched resources appear with a distinct initiator type in the network waterfall.

Navigation timing, you can programmatically detect whether a page was prerendered by checking the activationStart property on the navigation timing entry.

detect-prerender.js
if (performance.getEntriesByType) {
  const navEntry = performance.getEntriesByType('navigation')[0];
  if (navEntry.activationStart > 0) {
    console.log('Page was prerendered!');
    console.log('Activation time:', navEntry.activationStart, 'ms');
  }
}

For production measurement, track LCP and INP before and after deploying speculation rules using the Chrome UX Report or the web-vitals library. The improvement should be visible within a few weeks of deployment as CrUX data aggregates.


Browser Support in 2026

Chrome 121+ has full support: prefetch, prerender, and document rules all work. Edge 121+ shares the same Chromium implementation. Safari 18.2+ supports prefetch, with prerender available behind a feature flag. Firefox has no support as of February 2026. This coverage translates to roughly 80-85% of typical Shopify store traffic.

The remaining browsers aren't penalized, <script type="speculationrules"> is silently ignored by unsupported browsers. No JavaScript errors, no broken functionality, no console warnings. The page loads exactly as it would without the rules. This makes Speculation Rules a textbook case of progressive enhancement: browsers that understand it get near-instant navigation, and everyone else gets the standard experience.


Edge Cases for Production Stores

Analytics double-counting. Prerendered pages execute JavaScript, which means analytics scripts fire during prerender, before the user has actually navigated. Use the document.prerendering property to defer tracking until the page is activated.

analytics-guard.js
if (!document.prerendering) {
  trackPageView();
}

Dynamic content and inventory. Prerendered pages reflect the state at prerender time. If inventory changes between prerender and activation, another customer buys the last unit, the user sees stale data until the page re-checks availability. For high-velocity products, consider re-fetching critical data on activation.

Memory on mobile devices. Prerendering consumes roughly 50-100MB per page on mobile. Limit prerender rules to 1-2 pages maximum. Prefetch is far lighter and works better for broader speculation on resource-constrained devices.

Third-party Shopify apps. App scripts execute during prerender like any other JavaScript. Well-behaved apps work fine, but poorly coded apps that manipulate the DOM on load may display visual artifacts. Test with your specific app stack before deploying to production.

Cart state synchronization. If the user adds an item to their cart while a product page is prerendered, the prerendered page shows stale cart data, wrong item count, missing items. Cart drawer and cart icon sections should re-fetch their state on page activation to stay consistent.

A/B testing tools. Prerendered pages receive the same test variant as the triggering page. If your A/B tool assigns variants on page load, the prerendered page locks in its variant early. Some testing platforms need explicit configuration to handle prerendered navigations correctly, check your tool's documentation.


Combining with View Transitions

If your theme already uses the Cross-Document View Transition API, Speculation Rules complement it perfectly. Prerender ensures the destination page is ready instantly, and the View Transition API provides the visual animation during the swap. The result: navigation that feels both instant and polished, the prerendered page swaps in with a smooth cross-fade or morph animation instead of a hard cut.

Together, these two APIs represent the modern browser-native approach to SPA-like navigation without the SPA architecture. No JavaScript frameworks, no client-side routing, no hydration, just the platform.


Key Takeaways

  • Speculation Rules let the browser load the next page before the user clicks, shifting optimization from post-click to pre-click
  • Use prefetch for many potential targets with uncertain intent, prerender for high-confidence single targets
  • moderate eagerness (hover-triggered) is the best default for most Shopify product grids
  • The JSON format supports document rules with URL patterns, CSS selectors, and logical combinators for precise targeting
  • Use {{ routes.root_url }} in Liquid themes to ensure locale-aware URL matching
  • Exclude URLs with side effects, cart endpoints, checkout, API routes
  • Progressive enhancement by design: unsupported browsers silently ignore the rules with zero cost
  • Defer analytics and re-fetch cart state on activation to handle prerender edge cases
  • Pairs naturally with the View Transition API for instant, animated page navigations

If your Shopify store needs near-instant page transitions with browser-native prefetching and prerendering, I can help you architect and implement the right speculation strategy for your traffic patterns. Let's talk about what your commerce model actually needs.

Tailwind v4 + Vite Shopify Theme Setup