
SmartPrefetch is a lightweight prefetching library that makes website navigation feel instant by intelligently loading pages before users click.
It uses the modern Speculation Rules API as its primary mechanism and automatically falls back to traditional link prefetch for older browsers.
Features:
- Zero Configuration: Start prefetching with a single function call.
- Speculation Rules API: Uses Chrome 109+ and Edge 109+ native prerendering capabilities for maximum performance.
- Automatic Browser Fallback: Detects browser capabilities and falls back to
<link rel="prefetch">for Firefox and Safari. - Service Worker Detection: Automatically switches to link prefetch when service workers are active to prevent navigation errors.
- Smart Hover Detection: 65ms delay prevents unnecessary prefetches from cursor flyovers while remaining responsive.
- Touch Device Optimization: 2500ms disambiguation window prevents double prefetches on hybrid devices.
- Network Awareness: Respects Save Data mode and automatically disables prefetching on 2G connections.
- Viewport-Based Prefetching: Optional IntersectionObserver integration for prefetching visible links.
- Configurable Ignore Patterns: Filter URLs using RegExp, functions, or string matching.
- Statistics Tracking: Built-in performance monitoring shows prefetch hits and cache effectiveness.
Use Cases:
- E-commerce Product Pages: Prefetch product detail pages as users hover over thumbnails in category listings.
- Documentation Sites: Load the next page in a tutorial series when users scroll near the bottom.
- News and Blog Platforms: Prefetch article pages when headlines appear in the viewport.
- Single Page Application Navigation: Prefetch route components before route transitions in React, Vue, or Angular applications.
Basic Usage:
1. Load the SmartPrefetch library into your document.
<!-- From a CDN --> <script src="https://cdn.jsdelivr.net/gh/lazaroagomez/SmartPrefetch@latest/smartprefetch.prod.min.js"></script> <!-- For self-hosted installations --> <script src="/path/to/smartprefetch.min.js"></script>
2. The simplest implementation requires no configuration. The library starts prefetching immediately with sensible defaults:
// Initialize with default settings // - 65ms hover delay // - 10 max prefetches // - Respects Save Data and slow networks SmartPrefetch.listen();
3. Customize prefetch behavior with the following options.
hoverDelay(number): Milliseconds to wait before prefetching on hover. Default is65.enableHover(boolean): Enables hover-triggered prefetch. Default istrue.enableTouch(boolean): Enables touch-triggered prefetch. Default istrue.enableViewport(boolean): Enables viewport-triggered prefetch using IntersectionObserver. Default isfalse.viewportThreshold(number): The IntersectionObserver threshold (0-1). Default is0.viewportMargin(string): The IntersectionObserver rootMargin. Default is'0px'.maxPrefetches(number): The maximum number of URLs to prefetch per session. Default is10.maxPrerenders(number): The maximum number of URLs to prerender. Default is1.ignores(array): A list of patterns to ignore (RegExp, function, or string). Default is[].allowQueryString(boolean): Allows prefetching URLs that contain query strings. Default isfalse.allowExternalLinks(boolean): Allows prefetching links pointing to other domains. Default isfalse.speculationMode(string): The default mode. Options are'prefetch'or'prerender'. Default is'prefetch'.useSpeculationRules(string/boolean): Controls API usage. Options aretrue,false, or'auto'. Default is'auto'.eagerness(string): The Speculation Rules eagerness setting. Default is'moderate'.respectSaveData(boolean): Skips prefetching if the user has Data Saver enabled. Default istrue.respectSlowNetwork(boolean): Skips prefetching on 2G/slow-2g connections. Default istrue.respectVisibility(boolean): Skips prefetching when the page is hidden. Default istrue.fetchPriority(string): The priority for viewport or manual prefetch. Default is'low'.hoverPriority(string): The priority for hover or touch prefetch. Default is'high'.debug(boolean): Logs debug messages to the console. Default isfalse.trackStats(boolean): Tracks navigation hits for statistics. Default istrue.lazyImages(boolean): Enables lazy loading for images. Default isfalse.lazyImagesSelector(string): The selector for lazy images. Default is'img[data-src]'.lazyImagesRootMargin(string): The IntersectionObserver margin for lazy images. Default is'200px'.contentVisibility(boolean): Enables content-visibility optimization. Default isfalse.contentVisibilitySelector(string): The selector for elements to apply content-visibility to. Default is'section, article, .card'.contentVisibilitySize(string): Thecontain-intrinsic-sizevalue. Default is'500px'.
SmartPrefetch.listen({
// Hover/Touch
hoverDelay: 65,
enableHover: true,
enableTouch: true,
// Viewport (OFF by default - can be expensive)
enableViewport: false,
viewportThreshold: 0,
viewportMargin: '0px',
// Limits
maxPrefetches: 10,
maxPrerenders: 1,
// URL filtering
ignores: [],
allowQueryString: false,
allowExternalLinks: false,
// Speculation Rules
speculationMode: 'prefetch', // 'prefetch' | 'prerender'
eagerness: 'moderate',
useSpeculationRules: 'auto', // true | false | 'auto' (auto disables when service worker is active)
// Network
respectSaveData: true,
respectSlowNetwork: true,
respectVisibility: true,
// Priority
fetchPriority: 'low',
hoverPriority: 'high',
// Debug
debug: false,
trackStats: true,
// Callbacks
onPrefetch: null,
onError: null,
onHit: null,
// Lazy Images (opt-in)
lazyImages: false,
lazyImagesSelector: 'img[data-src]',
lazyImagesRootMargin: '200px',
// Content Visibility (opt-in)
contentVisibility: false,
contentVisibilitySelector: 'section, article, .card',
contentVisibilitySize: '500px'
});4. Trigger prefetching programmatically for specific URLs:
// Prefetch a single URL
// Returns a Promise that resolves when prefetch completes
SmartPrefetch.prefetch('/important-page.html').then(() => {
console.log('Prefetch complete');
});
// Prefetch multiple URLs at once
// Useful for prefetching a series of related pages
SmartPrefetch.prefetch([
'/page1.html',
'/page2.html',
'/page3.html'
]);
// Prerender a page (Chrome/Edge only)
// This fully renders the page in background for instant display
SmartPrefetch.prerender('/critical-landing-page.html');
// Prerender only works for same-origin URLs
// and requires Speculation Rules API support5. Stop all prefetching and clean up resources:
// Stop listening for hover/touch/viewport events
// Removes all event listeners and observers
// Clears any pending prefetch timers
SmartPrefetch.stop();
// Restart with new configuration
SmartPrefetch.listen({ hoverDelay: 50 });6. Access detailed statistics about prefetch effectiveness:
// Get current statistics object
const stats = SmartPrefetch.getStats();
console.log(stats);
// Output structure:
// {
// prefetched: 12, // Total URLs prefetched
// prerendered: 1, // Total URLs prerendered
// hits: 7, // Number of prefetched URLs that were navigated to
// errors: 0, // Number of failed prefetch attempts
// skipped: {
// duplicate: 3, // Skipped because URL was already prefetched
// network: 2, // Skipped due to Save Data or slow connection
// limit: 1, // Skipped because max limit was reached
// ignored: 4, // Skipped due to ignore patterns
// invalid: 0 // Skipped because URL was invalid
// },
// lazyLoaded: 5, // Images lazy loaded (if feature enabled)
// contentVisibilityApplied: 8, // Elements optimized with content-visibility
// prefetchedUrls: [ // Array of all prefetched URLs
// 'https://example.com/page1.html',
// 'https://example.com/page2.html'
// ],
// prerenderedUrls: [ // Array of all prerendered URLs
// 'https://example.com/landing.html'
// ],
// support: { // Browser feature detection
// speculationRules: true,
// linkPrefetch: true,
// intersectionObserver: true,
// nativeLazyLoading: true,
// contentVisibility: true,
// serviceWorker: false
// },
// isListening: true // Whether SmartPrefetch is currently active
// }Advance Usages:
Lazy Image Loading
SmartPrefetch.listen({
lazyImages: true, // Enable lazy loading feature
lazyImagesSelector: 'img[data-src]', // CSS selector for images to lazy load
lazyImagesRootMargin: '200px' // Start loading 200px before viewport
});<!-- Image loads when it enters viewport (plus margin) --> <img data-src="/images/product-1.jpg" alt="Product image"> <!-- Combine with native lazy loading for best browser support --> <img data-src="/images/product-2.jpg" loading="lazy" alt="Product image">
Content Visibility Optimization
Apply content-visibility CSS property to below-fold elements for faster initial page render:
SmartPrefetch.listen({
contentVisibility: true, // Enable optimization
contentVisibilitySelector: 'section, article', // Target elements
contentVisibilitySize: '500px' // Estimated element height
});This optimization applies content-visibility: auto to elements below 1.5x the viewport height. The browser skips rendering work for these elements until they’re needed.
Alternatives:
- instant.page: The original hover prefetch library. SmartPrefetch builds on instant.page’s concept but adds Speculation Rules API support, service worker detection, and viewport-based prefetching. instant.page is lighter (1KB) but offers less flexibility.
- quicklink: Google’s viewport-based prefetch solution. quicklink focuses on IntersectionObserver prefetching rather than hover detection. SmartPrefetch supports both approaches in a single library.
FAQs:
Q: Why am I getting 503 errors after implementing SmartPrefetch?
A: This happens when your site uses a service worker that intercepts navigation requests. The Speculation Rules API can conflict with certain service worker configurations. Set useSpeculationRules: false to force link prefetch mode, or use the default ‘auto’ setting which detects service workers automatically.
Q: Can I prefetch API endpoints or data files instead of HTML pages?
A: SmartPrefetch is designed for document prefetching. For API or data prefetching, use the fetch() API directly with appropriate cache headers. You can still use SmartPrefetch’s ignore patterns to prevent it from prefetching API URLs.
Q: How do I prevent prefetching on specific links without removing them from the DOM?
A: Use the ignores configuration with a function: ignores: [(url, el) => el.hasAttribute('data-no-prefetch')]. Then add data-no-prefetch attribute to any anchor you want to exclude.
Q: What’s the difference between prefetch and prerender in SmartPrefetch?
A: Prefetch downloads the HTML document only. Prerender fully loads and renders the page in background, including executing JavaScript and loading all resources. Prerender provides instant navigation but uses significantly more memory and CPU. Use prerender sparingly for critical landing pages only.







