The Clients API: a service worker's access to client objects
In one line: The Clients interface, accessed as self.clients inside a service worker, provides access to Client objects (windows, workers) matching the query options passed in — with matchAll({ includeUncontrolled: true }), this can include clients that share the same storage key/origin but are not controlled by, or associated with the registration of, this service worker.
This feature is only available in service workers.
Accessing it
Section titled “Accessing it”// Inside a service workerself.clients;Methods
Section titled “Methods”| Method | Returns | Purpose |
|---|---|---|
Clients.get(id) |
Promise<Client | undefined> |
Returns a Client matching a given id, or undefined if no client matches. |
Clients.matchAll(options) |
Promise<Array<Client>> |
Returns an array of Client objects. By default only controlled clients are returned; an options argument allows control over the types of clients returned, including uncontrolled ones. |
Clients.openWindow(url) |
Promise<WindowClient | null> |
Opens a new browser window for a given URL, resolving to null if the platform cannot return a same-origin WindowClient for it. |
Clients.claim() |
Promise<void> |
Allows an active service worker to set itself as the controller for all clients within its scope. |
Example
Section titled “Example”Finding an already-open chat window, focusing it, or opening a new one, then messaging it:
addEventListener("notificationclick", (event) => { event.waitUntil( (async () => { const allClients = await clients.matchAll({ includeUncontrolled: true, });
let chatClient;
// Let's see if we already have a chat window open: for (const client of allClients) { const url = new URL(client.url);
if (url.pathname === "/chat/") { // Excellent, let's use it! client.focus(); chatClient = client; break; } }
// If we didn't find an existing chat window, // open a new one: chatClient ??= await clients.openWindow("/chat/");
// Message the client: chatClient.postMessage("New chat messages!"); })(), );});Browser support
Section titled “Browser support”The Clients interface is Baseline widely available: it is well established and works across many devices and browser versions, and has been available across browsers since April 2018.
Practical checklist
Section titled “Practical checklist”- Use
clients.matchAll()withincludeUncontrolledwhen a service worker needs to find windows it does not yet control — by defaultmatchAll()only returns controlled clients. - Handle
clients.get(id)resolving toundefinedandclients.openWindow(url)resolving tonullwhen no matching client can be returned. - Call
clients.claim()in the service worker’sactivatehandler when it should take control of existing clients immediately, rather than waiting for the next navigation. - Use
clients.openWindow()only in response to a user gesture such as a notification click, matching the pattern shown above.
Cross-references
Section titled “Cross-references”- Navigation preload — another service worker capability exposed via a similarly scoped API