# Debugging service workers

> How to inspect, force-update, and diagnose service workers using Chrome DevTools, Firefox DevTools, and Safari Web Inspector — covering registration state, cache contents, fetch interception, and update flow.

**In one line:** The Application panel in Chrome DevTools (and equivalent panels in Firefox and Safari) lets you inspect the registration state, force updates, test offline, clear caches, and observe `fetch` event interception — all without deploying a change.

## Chrome DevTools

### Application → Service Workers

The primary debugging surface. Open DevTools → Application → Service Workers (left sidebar).

| Control | What it does |
|---|---|
| **Update on reload** | Forces a byte-comparison check and installs a new worker every navigation |
| **Bypass for network** | Disables the service worker for this tab — all `fetch` events pass through |
| **Offline** | Simulates no network for requests going through the service worker |
| **Update** | Triggers `registration.update()` manually |
| **Unregister** | Removes the registration entirely |

The panel also shows the current state: *installing*, *waiting*, or *activated* — plus the script URL and scope.

### Forcing a worker update

The "Update on reload" checkbox is the fastest way to test worker changes in development. Without it, Chrome serves the cached worker script for up to 24 hours even if the file changes, and the browser only installs a new worker when it detects a byte difference.

If a new worker is stuck in *waiting*, the panel shows a "skipWaiting" link that calls `skipWaiting()` immediately for the pending worker — useful for testing without modifying the worker code.

### Cache Storage

DevTools → Application → Cache Storage lists all named caches and their entries. You can inspect request/response headers, preview response bodies, and delete individual entries or entire caches.

### Inspecting fetch events

Open the Network panel and enable the **Service Worker** column (right-click on column headers). Each request shows whether it was served from the service worker, from cache, or from the network. The `(ServiceWorker)` label in the "Size" column confirms the worker intercepted the request.

### Console in the worker context

Switch the DevTools console's JavaScript context (the dropdown next to the filter bar) from "top" to the service worker URL. `console.log` calls inside the worker appear in this context.

You can also evaluate expressions against the worker's global scope, including inspecting `self.registration`, `caches.keys()`, and `self.clients.matchAll()`.

## Firefox DevTools

Open **about:debugging#/runtime/this-firefox** → "This Firefox" → "Service Workers". Firefox lists every registered worker with its scope, state, and a **Inspect** link that opens a dedicated console for that worker.

Firefox does not have a built-in "Update on reload" checkbox. To force a re-install during development, unregister the worker and reload, or call `registration.update()` in the page console.

## Safari Web Inspector

In Safari (iOS or macOS), enable the Develop menu (Preferences → Advanced → Show Develop menu). Open Web Inspector → Storage → Service Workers. Safari lists registered workers, their scopes, and the script URL.

Safari Web Inspector has more limited debugging surfaces than Chrome or Firefox: there is no dedicated cache viewer or "force update" checkbox. Use the console in the worker context for `caches.keys()` inspection.

## Diagnosing common problems

| Symptom | Likely cause | Fix |
|---|---|---|
| Worker stuck in *waiting* | Old tabs still open and no `skipWaiting()` | Close all tabs, or use DevTools "skipWaiting" link |
| New code not running after deploy | HTTP cache serving the old worker script | Use `updateViaCache: 'none'` or set `Cache-Control: no-cache` on the worker URL |
| Requests not intercepted | Worker not yet activated (still *installing*) or scope mismatch | Check scope in DevTools; reload after activation |
| Cache not populated | `install` failed or `event.waitUntil()` was not called | Check the console in the worker context for errors |
| Stale content served | `CacheFirst` strategy with no expiration | Add `ExpirationPlugin` or version your cache name |
| Offline fallback not shown | Fallback not pre-cached in `install`, or wrong `fetch` event guard | Check Cache Storage for the fallback URL; add logging |

## Workbox logging

Workbox emits verbose logs in development builds. When using Workbox, switch to the development build during debugging:

```js
import { setCacheNameDetails } from 'workbox-core';
// Development builds log strategy decisions to the console
```

Workbox's development build is automatically selected when `process.env.NODE_ENV !== 'production'`.

## Practical checklist

- [ ] Enable "Update on reload" in DevTools during development to avoid cached-worker confusion.
- [ ] Open the worker console context to see worker-side `console.log` output.
- [ ] Use "Bypass for network" when you want to test behavior without the service worker temporarily.
- [ ] After a deploy, verify Cache Storage contains only the new cache version and old caches are deleted.
- [ ] Test the offline fallback by checking "Offline" in DevTools Network and navigating to an uncached URL.

## Cross-references

- [The update flow and skipWaiting](/reference/service-worker/update-skipwaiting/) — understanding why workers get stuck in waiting
- [Caching strategies](/reference/service-worker/caching-strategies/) — the strategies visible in Cache Storage
- [Registration and scope](/reference/service-worker/registration-scope/) — scope issues visible in the Service Workers panel