Service Worker Events Reference

All service worker lifecycle and functional event types with timing and scope.

Searchable reference for Service Worker events — install, activate, fetch, message, push, sync, periodicsync and notification events — with their interfaces, timing and waitUntil semantics. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

What is the difference between lifecycle and functional events?

Lifecycle events — install and activate — fire once per worker version as it is set up and takes control. Functional events such as fetch, push and sync fire repeatedly while the worker is active to do its ongoing work.

Events that drive a service worker

A service worker is event-driven: it has no persistent state and wakes only to handle events, then may be terminated. Knowing which events exist, when they fire, and how to extend their lifetime is the core of building reliable offline-capable and push-enabled web apps. This searchable reference lists the lifecycle and functional events with their interfaces and timing.

How it works

Service worker events fall into two groups. Lifecycle events run once per worker version:

self.addEventListener("install", (event) => {
  event.waitUntil(caches.open("v1").then((c) => c.addAll(ASSETS)));
});

self.addEventListener("activate", (event) => {
  event.waitUntil(clients.claim());
});

Functional events fire repeatedly. The fetch event uses event.respondWith() to return a response synchronously, while push, sync, message and the notification events use event.waitUntil() to keep the worker alive while a promise resolves. Without one of these calls the browser may kill the worker before your asynchronous work finishes.

The install → activate lifecycle in detail

When you deploy a new service worker, the browser runs the install handler of the new version while the old version is still controlling open pages. The new worker enters a “waiting” state until all pages using the old version are closed or the old worker is explicitly skipped with self.skipWaiting().

activate then fires once the new worker takes control. This is the right place to clean up caches from the previous version — compare the current cache name against a known list and delete anything obsolete:

self.addEventListener("activate", (event) => {
  const currentCaches = ["v2"];
  event.waitUntil(
    caches.keys().then((cacheNames) =>
      Promise.all(
        cacheNames
          .filter((name) => !currentCaches.includes(name))
          .map((name) => caches.delete(name))
      )
    ).then(() => clients.claim())
  );
});

Fetch caching strategies

The fetch event is where most service worker logic lives. Common strategies:

Cache-first (for static assets): check the cache first; fall back to network and cache the response. Use this for images, fonts, and versioned JS/CSS bundles.

Network-first (for API calls): try the network; fall back to cache if offline. Use for data that changes but should degrade gracefully.

Stale-while-revalidate: serve from cache immediately (for speed), then fetch fresh content in the background and update the cache for next time.

self.addEventListener("fetch", (event) => {
  event.respondWith(
    caches.match(event.request).then((cached) => {
      const networkFetch = fetch(event.request).then((response) => {
        const clone = response.clone();
        caches.open("v2").then((cache) => cache.put(event.request, clone));
        return response;
      });
      return cached || networkFetch;
    })
  );
});

Push and notification events

The push event fires when the browser’s push service delivers a message, even when no page is open. Your handler has a short time limit (typically a few seconds) and must show a notification inside waitUntil(). If it resolves without showing one, the browser shows a generic notification and may penalise your origin:

self.addEventListener("push", (event) => {
  const data = event.data?.json() ?? { title: "New message" };
  event.waitUntil(
    self.registration.showNotification(data.title, {
      body: data.body,
      icon: "/icon.png",
    })
  );
});

notificationclick fires when a user taps the notification — use it to open or focus the relevant page.

Tips and notes

  • Precache in install; purge old caches in activate. Call clients.claim() to take control of already-open pages immediately.
  • fetch is the only event that uses respondWith() — everything else uses waitUntil().
  • A push handler must show a notification or the browser may flag your origin for silent pushes.
  • sync retries on a backoff if your promise rejects; periodicsync is throttled by engagement scores and battery state and has limited browser support.
  • Test service workers in a private window to avoid unexpected caching from a previous registered worker.