keyboard_backspace wifi_off

Diagnostics

This page shows PWA diagnostics like service worker state, the number of clients served, cache statistics and permissions.

Service Worker

The table below shows service workers in the active, waiting, and installing states.

Click the button "Check for updates" to check if there is a new service worker available. If there is, the new service worker will be installed and will go through the installing and waiting states in the table below. Reloading the page should move it to the active state. When there is no active service worker, the new service worker will go from installing straight to the active state.

State Version
active
waiting
installing

When a new service worker is discovered, it will first be in the installing state, and after that it will proceed to the waiting state. Once the service worker is in the waiting state, it will wait until the current service worker no longer controls any clients before it can take over. This typically happens when all controlled pages are closed or navigated away from.

Calling skipWaiting() allows the new service worker to activate immediately, even while the previous service worker still controls clients, but this should be done with caution as this can break the application.

The service worker of this app calls skipWaiting() when the active service worker controls only one client and takes care not to break the application. A basic version of this service worker that you can use in your own PWAs can be found on GitHub.

Service worker clients

Below you can see the number of clients (PWAs, tabs, windows) served by the currently active service worker. When you open more clients or close open ones, the number will change.

Clients served: none

Cached files

Below you can see the caches in use and the total size of all caches.

Total cache size: none

Cache nameFiles
none

Permissions

Below you find the current status of the API permissions for this app.

PermissionState
Checking permissions...

Code examples

These examples show the APIs behind the diagnostics above. The service worker version is an app-defined value sent to the page in a message. The Permissions API checks names you provide; it cannot list every permission itself.

// In the page: read the active, waiting and installing workers. const registration = await navigator.serviceWorker.getRegistration(); const getWorkerInfo = async registration => { const entries = await Promise.all(['active', 'waiting', 'installing'] .map(async state => { const worker = registration?.[state]; if(!worker) return [state, null]; const info = await new Promise(resolve => { const channel = new MessageChannel(); channel.port1.onmessage = event => { resolve(event.data); channel.port1.close(); }; worker.postMessage('get-diagnostics', [channel.port2]); }); return [state, info]; })); return Object.fromEntries(entries); }; console.log(await getWorkerInfo(registration)); // Check for a service worker update. await registration?.update(); // In the service worker: send its version and controlled client count. const SW_VERSION = 1; self.addEventListener('message', event => { if(event.data !== 'get-diagnostics') return; event.waitUntil(self.clients.matchAll({type: 'window'}).then(clients => { event.ports[0].postMessage({version: SW_VERSION, clients: clients.length}); })); }); // In the page: list each cache and count its files. const cacheStats = await Promise.all((await caches.keys()).map(async name => { const cache = await caches.open(name); const files = (await cache.keys()).filter(request => new URL(request.url).pathname !== '/__sw-precache-manifest__').length; return {name, files}; })); console.table(cacheStats); // estimate() reports storage for the whole origin, including caches. const {usage} = await navigator.storage.estimate(); console.log('Storage used (bytes):', usage); // Query known permission names and watch for changes. await Promise.all(['camera', 'microphone', 'geolocation'].map(async name => { try { const status = await navigator.permissions.query({name}); console.log(name, status.state); status.addEventListener('change', () => console.log(name, status.state)); } catch(error) { console.log(name, error instanceof TypeError ? 'unsupported' : 'unavailable'); } }));

What PWA Can Do Today A showcase of what is possible with Progressive Web Apps today

You are offline, external links cannot be opened.