How Clients.claim() Works in Service Workers

This article explains how the Clients.claim() method allows an activated JavaScript service worker to immediately control existing open pages within its scope. By default, a newly activated service worker does not control open tabs until they are reloaded; Clients.claim() overrides this behavior, enabling instant interception of network requests and immediate client management.


The Default Service Worker Lifecycle

When a service worker is registered and activated, it does not immediately take control of the page that loaded it or other tabs that are already open. Under standard lifecycle rules:

  1. A page must be refreshed or a new tab must be navigated to the worker’s scope before the new service worker begins controlling it.
  2. If an older service worker is running, it continues to handle requests for open tabs until those tabs are completely closed or reloaded.

This default design ensures consistent behavior across a browsing session, preventing pages from suddenly receiving different responses from a newly updated service worker mid-session.

How Clients.claim() Changes Control

The self.clients.claim() method is called from within the service worker context—typically during the activate event. When invoked, it queries all open browser contexts (tabs, windows, iframes) that match the service worker’s scope and assigns the active service worker as their controller.

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

When this execution occurs:

// In the client page script
navigator.serviceWorker.addEventListener('controllerchange', () => {
  console.log('The controlling service worker has changed.');
});

Combining skipWaiting() and clients.claim()

Clients.claim() is frequently paired with self.skipWaiting() to achieve rapid deployment of new service worker logic across an application:

  1. self.skipWaiting() runs in the install phase, forcing the new service worker to bypass the waiting state and activate immediately.
  2. self.clients.claim() runs in the activate phase, forcing the newly active worker to immediately seize control of all active clients.

Together, these methods allow progressive web apps (PWAs) to apply critical updates, establish offline handling on initial site visits, and push functional changes to users instantly.