How to Configure Service Worker Navigation Preload in Google Chrome

Progressive Web Applications (PWAs) utilize Service Workers to intercept network requests, serve cached assets offline, and manage client-side state. However, on mobile devices or cold browser boots, awakening an idle Service Worker thread introduces a startup delay—often lasting between 50 and 300 milliseconds—before the worker can execute its fetch event handler. Without mitigation, this boot latency directly delays the initial HTML document request, impairing Core Web Vitals metrics such as Largest Contentful Paint (LCP). Navigation Preload solves this bottleneck in Google Chrome by dispatching the network document fetch in parallel with Service Worker thread boot.

Understanding Navigation Preload Mechanics

When Navigation Preload is activated:

  • As soon as the user initiates a page navigation, Chrome’s network stack immediately fires the HTTP request to the origin server.
  • Concurrently, Chrome launches the Service Worker JavaScript runtime.
  • The outgoing network request includes a specialized HTTP header: Service-Worker-Navigation-Preload: true (or custom payload tokens).
  • Inside the Service Worker’s fetch event handler, the preloaded response is exposed via the event.preloadResponse promise, allowing the worker to stream or serve the network response without waiting for boot cycles.

Enabling Navigation Preload in Service Worker Code

Enable and configure Navigation Preload during the Service Worker activate lifecycle event:

// service-worker.js
self.addEventListener('activate', (event) => {
    event.waitUntil((async () => {
        if (self.registration.navigationPreload) {
            // Enable navigation preload
            await self.registration.navigationPreload.enable();
            
            // Set custom header state for server-side routing
            await self.registration.navigationPreload.setHeaderValue('preload-active');
        }
    })());
});

self.addEventListener('fetch', (event) => {
    if (event.request.mode === 'navigate') {
        event.respondWith((async () => {
            try {
                // 1. Check for preloaded network response
                const preloadResponse = await event.preloadResponse;
                if (preloadResponse) {
                    return preloadResponse;
                }

                // 2. Fall back to standard network fetch
                return await fetch(event.request);
            } catch (err) {
                // 3. Serve offline fallback page from cache if network fails
                const cache = await caches.open('offline-shell-v1');
                return await cache.match('/offline.html');
            }
        })());
    }
});

Auditing Navigation Preload in Chrome DevTools

To inspect and verify active Navigation Preload operations in Google Chrome:

  1. Open Google Chrome and navigate to the application.
  2. Open Chrome DevTools by pressing Ctrl + Shift + I (or Option + Command + I on macOS).
  3. Switch to the Application tab and select Service workers from the left sidebar.
  4. Verify that the active worker reports Navigation Preload: enabled.
  5. Switch to the Network tab and refresh the page. Look for the navigation row: Chrome displays a gear icon next to the network request, indicating that the response was fulfilled via Service Worker Navigation Preload.
  6. Examine the Timing panel to confirm that document fetching occurred in parallel with worker awakening.

Optimising Server-Side Responses for Preload Requests

When the origin server detects the Service-Worker-Navigation-Preload header, it can optimize response generation—such as omitting full HTML boilerplate and returning pure JSON fragments if the worker handles client-side template rehydration.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.