A Service Worker is an event-driven programmable client-side network proxy running in the browser background to enable offline caching, push notifications, and background sync.
A Service Worker is an event-driven, programmable client-side network proxy that runs on a separate background thread in modern web browsers. Standardized by the World Wide Web Consortium (W3C), service workers intercept outgoing HTTP requests, programmatically manage the browser's Cache Storage API and IndexedDB instances, process push notifications, and execute background synchronization—even when the corresponding web application tab is closed.
Audit your website's service worker implementation, lifecycle listeners, and caching strategies with our client-side PWA Audit tool.
| Specification | Details |
|---|---|
| Standard Bodies | W3C Web Applications Working Group & WHATWG |
| Relevant Specifications | Service Workers Nightly (W3C), Cache Storage API Standard |
| Execution Environment | Isolated background JavaScript worker thread (no DOM access) |
| Security Requirement | Mandatory HTTPS transport (or localhost for local debugging) |
| Core Storage APIs | CacheStorage (caches.open, caches.match), IndexedDB |
| Primary Events | install, activate, fetch, push, sync, message |
| Browser Support | Chrome, Edge, Safari (11.1+), Firefox, Opera, Android WebView |
Unlike standard webpage scripts that execute on page load and terminate on navigation, service workers follow a strictly defined asynchronous lifecycle independent of the document:
┌────────────────────────────────────────────────────────────┐
│ Service Worker Lifecycle │
├────────────────────────────────────────────────────────────┤
│ │
│ Registration ──► Installing ──► Installed / Waiting │
│ (navigator.sw) (Precache) (skipWaiting?) │
│ │ │ │
│ ▼ (Error) ▼ │
│ Redundant Activating │
│ (Cleanup Caches) │
│ │ │
│ ▼ │
│ Activated │
│ (Intercept Fetch) │
│ │
└────────────────────────────────────────────────────────────┘
self.skipWaiting() bypasses this waiting phase.clients.claim() allows the worker to control uncontrolled client pages immediately.fetch network requests, handles push alerts, and processes background sync tasks.| Strategy | Network vs. Cache Behavior | Optimal Use Case |
|---|---|---|
| Cache First (Falling Back to Network) | Serves from Cache Storage immediately. Fetches from network only on cache miss. | Versioned/hashed static assets (fonts, webpack bundles, CSS, icons). |
| Network First (Falling Back to Cache) | Attempts live HTTP request first. Falls back to cached response if offline or timed out. | Frequently changing API endpoints, news feeds, current user profile. |
| Stale-While-Revalidate | Returns cached version instantly for near-instant rendering while revalidating and updating cache in background. | Avatars, article listings, non-critical telemetry, documentation. |
| Network Only | Always bypasses cache and strictly requires network connectivity. | Payment checkouts, login authentication, sensitive mutations. |
| Cache Only | Strictly queries local cache; never initiates a network request. | Pure offline mode packages, pre-bundled static help documents. |
const CACHE_NAME = 'devflow-static-v2';
const PRECACHE_URLS = [
'/',
'/manifest.json',
'/styles/global.css',
'/scripts/app.js',
'/offline.html',
'/icon-192.png',
'/icon-512.png',
];
// 1. Install: Precache critical application shell
self.addEventListener('install', (event: ExtendableEvent) => {
event.waitUntil(
caches
.open(CACHE_NAME)
.then((cache) => cache.addAll(PRECACHE_URLS))
.then(() => self.skipWaiting())
);
});
// 2. Activate: Purge previous version caches & claim active clients
self.addEventListener('activate', (event: ExtendableEvent) => {
event.waitUntil(
caches
.keys()
.then((cacheNames) =>
Promise.all(
cacheNames
.filter((name) => name !== CACHE_NAME)
.map((name) => caches.delete(name))
)
)
.then(() => self.clients.claim())
);
});
// 3. Fetch: Stale-While-Revalidate with Navigation Offline Fallback
self.addEventListener('fetch', (event: FetchEvent) => {
// Only cache GET requests
if (event.request.method !== 'GET') return;
// Handle HTML document navigations with offline fallback
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request).catch(async () => {
const cache = await caches.open(CACHE_NAME);
return (await cache.match('/offline.html')) || Response.error();
})
);
return;
}
// Handle static assets with Stale-While-Revalidate
event.respondWith(
caches.open(CACHE_NAME).then(async (cache) => {
const cachedResponse = await cache.match(event.request);
const fetchPromise = fetch(event.request).then((networkResponse) => {
if (networkResponse.status === 200) {
cache.put(event.request, networkResponse.clone());
}
return networkResponse;
}).catch(() => cachedResponse);
return cachedResponse || fetchPromise;
})
);
});
cache.put() on POST, PUT, or DELETE requests fails or causes mutations to replay unintentionally.event.waitUntil(): Terminating asynchronous caching promises early before the browser completes the install or activate step.const CACHE = 'my-cache' causes users to remain permanently stuck on stale CSS and JavaScript assets following production releases.Free, browser-based utilities to test, generate, and inspect Service Worker (PWA Background Worker & Offline Caching) payloads directly.
Validate manifest.json, inspect service worker config, and flag installability issues.
Generate multi-size ICO, SVG, Apple Touch, and PWA favicons from images, text, or emojis.
Preview web pages across multiple device viewports instantly.
Analyze HTTP response headers for security, caching, and compliance issues.