Speculation Rules for Faster Page Loads

Show QR code Hide QR code
QR code linking to https://navendu.me/tils/17-8-25-speculation-rules-for-faster-page-loads/

The Speculation Rules API allows you to improve page navigation on your websites by prefetching and prerendering web pages proactively with just a few lines of code.

In practice, this means that when a user hovers over a link (to click it), the next web page is already loaded and rendered, providing a faster, SPA-like loading experience.

I added it to my website today. You can see it in action by opening the network tab and hovering over a link in this website without clicking it.

This website uses Hugo, so I added it to my head.html partial template:

layout/partials/head.html
<!-- Speculation Rules for instant navigation --> {{- /* Only enable this in production */}} {{- if hugo.IsProduction | or (eq site.Params.env "production") }} <script type="speculationrules"> { // Prefetch and prerender all internal pages but wait 200ms (moderate eagerness) after hover "prerender": [{ "where": { "href_matches": "/*" }, "eagerness": "moderate" }], "prefetch": [{ "where": { "href_matches": "/*" }, "eagerness": "moderate" }] } </script> <script> // Fallback for browsers that don't support the Speculation Rules API if (!HTMLScriptElement.supports || !HTMLScriptElement.supports('speculationrules')) { // Track preloaded URLs to avoid duplicate requests const preloadedUrls = {}; function pointerenterHandler() { if (!this.href) return; // Skip if no href if (!this.href.startsWith(location.origin)) return; // Skip external links if (preloadedUrls[this.href]) return; // Skip duplicates preloadedUrls[this.href] = true; // Mark as preloaded const prefetcher = document.createElement('link'); const supportsPrefetch = prefetcher.relList && prefetcher.relList.supports && prefetcher.relList.supports('prefetch'); // Check if browser supports prefetch prefetcher.as = supportsPrefetch ? 'document' : 'fetch'; // Set as document or fetch (older browsers) prefetcher.rel = supportsPrefetch ? 'prefetch' : 'preload'; // Set as prefetch or preload (older browsers) prefetcher.href = this.href; document.head.appendChild(prefetcher); // Add to head } document.addEventListener('DOMContentLoaded', function () { const conn = navigator.connection || navigator.mozConnection || navigator.webkitConnection; const saveData = conn && conn.saveData; const isVerySlow = conn && /(^|-)2g($|-)/.test(String(conn.effectiveType || '')); if (saveData || isVerySlow) return; // Skip for data saver and slow connections document.querySelectorAll('a[href^="/"]').forEach(function (item) { item.addEventListener('pointerenter', pointerenterHandler, { passive: true }); // Add event listener when pointer enters link area }); }); } </script> {{- end }}

DocuSeal has an excellent blog post that covers this API. The code I shared above just tweaks it a little bit.

Webmentions • Last updated at 9:53 AM, 10th November 2025

Have you written a response to this? Send me a webmention by entering the URL.