v149 · Web APIs · Service Worker Integration
Service Worker Integration
Using Request.isReloadNavigation in a service worker to implement a bypass-cache-on-reload strategy — the same behaviour browsers apply to HTTP caches when the user presses reload.
When a user presses reload, browsers send a conditional request to the network for the main document even if it's in the HTTP cache. Service workers previously couldn't detect this and would often serve stale cached content on reload.
isReloadNavigation closes this gap.
navigation strategies
Normal navigation (isReloadNavigation: false)
- 1. Fetch event fires
- 2.
isReloadNavigation→false - → Check cache first
- ✓ Cache hit: serve cached response immediately
- ✓ Cache miss: fetch from network, cache result
Reload (isReloadNavigation: true)
- 1. Fetch event fires
- 2.
isReloadNavigation→true - → Skip cache, go to network
- ✓ Network success: serve fresh, update cache
- ✓ Network failure: fall back to cached response
comparison with alternatives
| Signal | Available in SW? | Detects reload? | Notes |
|---|---|---|---|
request.isReloadNavigation |
Yes (Chrome 149+) | Yes | Direct signal — purpose-built for this |
Cache-Control: no-cache on reload |
No | No — headers not exposed to SW | Browser sends this but SW can't see request headers that indicate reload |
PerformanceNavigationTiming.type |
No | Yes (in page only) | Only available in page context, not service worker |
request.headers.get('Cache-Control') |
Yes | Partial | Browser adds max-age=0 on reload but this is unreliable |
complete service worker implementation
// sw.js — network-first-on-reload strategy
const CACHE_NAME = 'pages-v1';
self.addEventListener('fetch', event => {
const req = event.request;
// Only handle navigation requests
if (req.mode !== 'navigate') return;
event.respondWith(handleNavigation(req));
});
async function handleNavigation(req) {
// Chrome 149+: true when user explicitly reloaded
if (req.isReloadNavigation) {
return networkFirstWithFallback(req);
}
return cacheFirstWithNetwork(req);
}
async function networkFirstWithFallback(req) {
try {
const response = await fetch(req);
// Update cache with fresh response
const cache = await caches.open(CACHE_NAME);
cache.put(req, response.clone());
return response;
} catch {
// Offline: fall back to cache
const cached = await caches.match(req);
if (cached) return cached;
throw new Error('Network unavailable and no cache available');
}
}
async function cacheFirstWithNetwork(req) {
const cached = await caches.match(req);
if (cached) return cached;
const response = await fetch(req);
const cache = await caches.open(CACHE_NAME);
cache.put(req, response.clone());
return response;
}
see also
implementation reference
Need the exact API surface, compatibility boundaries, errors, lifecycle, and source links? Read the matching gendn reference ↗