Identify the controlling worker and the stale response before changing an update policy; preserve open-tab compatibility and remove only explicitly owned, obsolete caches.

If a returning visitor sees an old website while a fresh browser sees the new one, check whether a service worker controls the old page. It can answer requests from its own stored resources even after a server or CDN purge. Find the controlling worker, its update state and the response it actually supplies before deleting anything.
This guide concerns a website you maintain or an authorised integration. Its two-release example is fictional. The diagnostic and release plan are researched recommendations, not a claim that a particular installed app or plugin has been tested.
Distinguish the three kinds of old content
An ordinary HTTP cache stores responses according to caching rules. Cache Storage is a separate, script-managed collection of request/response pairs. A service worker can intercept a request and choose a cached response, a network response or another fallback. MDN’s service-worker guide describes that architecture.
A third possibility is simpler: an already-open document still contains the HTML and JavaScript it loaded before deployment. Seeing yesterday’s navigation in that tab does not prove that a new network request returned yesterday’s HTML. Record whether the failure appears on a fresh navigation, a reload or merely returning to an open tab.
If there is no controlling worker, return to the ordinary cache investigation. Do not install a progressive-web-app plugin to solve an unconfirmed worker problem.
Capture the failing version before resetting the browser
Write down the exact origin and path, browser version, installed-app or ordinary-tab mode, and visible release identifier if your application has one. Compare a long-running profile with a fresh test profile. Keep the same public page and harmless task in both cases.
For a fictional event website, release A lists an old workshop time; release B corrects it. The useful observation is not just “A looks old.” Record whether A’s HTML, timetable JSON or JavaScript contains the old time. An updated page shell can still request stale data through another route.
Save unfinished input using the application’s supported method before testing navigation. Do not export a visitor’s cookies, authentication headers or private cached responses into a support ticket. A redacted resource path and release label are usually more useful than an entire browser-storage dump.
Identify scope, registration and the current controller
Use the browser’s service-worker inspection panel for the affected origin. Read the registration’s scope and script URL, then distinguish its installing, waiting and active workers. The registration reference explains those properties.
Also check the current document’s controller. A registered active worker does not establish that this particular page is controlled. A page opened before first activation can remain uncontrolled unless the application’s lifecycle deliberately changes that. Scope matters too: a worker for an app subdirectory need not explain a problem elsewhere.
Look for duplicate or obsolete registrations from previous plugins, but do not unregister them by guesswork. Establish who owns each registration and which paths depend on it. Two applications sharing an origin may also share origin storage without sharing an update policy.
Trace the stale response to its actual source
In Network, reproduce the harmless request and inspect whether the browser identifies service-worker handling. Compare the response content and release label with the expected deployment. The Console and Network workflow helps connect the visible failure to the responsible resource.
Then inspect the application’s named caches and relevant request entries. Cache API entries do not automatically refresh or expire according to HTTP freshness headers. The application’s code must maintain them; browser eviction is a separate storage constraint.
A developer-tool bypass can help compare worker and network paths in a controlled test. It is not evidence that ordinary visitors have received the repair. Note any enabled development override, then turn it off before the acceptance run. Otherwise an update that works only under the bypass can look deceptively complete.
Recognise a normal waiting update
A successfully installed replacement can wait while the old worker still controls clients. As web.dev’s lifecycle explanation shows, a normal refresh may leave overlapping clients and fail to release that waiting worker. Checking for an update is different from activating it.
In the event-site example, two open release-A tabs might keep release B waiting. Closing or navigating away from all relevant clients can demonstrate the normal lifecycle in a test profile. Visitors should not need to discover this by repeatedly refreshing and losing their booking notes.
Build an update notice around the application’s actual lifecycle: explain that a new version is ready and allow the visitor to finish or save work first. Do not announce readiness merely because a deploy job finished; the visitor’s worker installation may still fail.
Choose an activation policy that keeps versions compatible
Calling skipWaiting can advance a replacement without waiting for old clients to disappear. That can leave old page code making subsequent requests through a new worker. It is a compatibility decision, not a universal stale-cache fix.
Before allowing an update action, define which release combinations are supported. Can old JavaScript read new API responses? Are old hashed asset URLs still served? Can the new worker find resources an existing tab still needs? Retaining required old assets for a planned transition can be safer than removing them immediately after deployment.
If the application reloads after a controller change, scope that behaviour and protect unfinished work. Avoid a global controller-change reload loop. Offer a clear failure message when activation or the subsequent page load does not complete, rather than repeating the same action indefinitely.
Maintain only the caches this application owns
Use a stable service-worker script URL with changed contents for successive releases. Changing the URL on every release can strand a cached old page that only knows how to register the previous script. Version the application’s assets and cache names within a deliberate strategy instead.
Give caches an application-specific prefix and an explicit set of retained versions. Cleanup should target only confirmed obsolete caches belonging to that application. Do not copy a sample that deletes every cache on the origin when other tools or subdirectory apps use the same origin.
Keep account pages, authentication responses and payment state outside a generic offline cache unless the application has a deliberately reviewed design for them. A public offline shell does not need to contain private account data. Fixing freshness must not create a cross-session disclosure.
Test the release boundary, not just a clean installation
| Controlled case | What must remain understandable |
|---|---|
| Release A open during release B deployment | Existing work remains usable; update readiness is truthful. |
| Two old tabs and one new navigation | Waiting and activation do not create incompatible resource combinations. |
| Offline after a completed installation | The intended offline task works or clearly reports its limits. |
| Required install resource unavailable | The failed replacement does not pretend to be ready. |
| Return after skipping several releases | Update and storage migration do not assume the immediately previous version. |
Include recovery from a failed update, not only the happy path. On a test profile, a targeted unregister or owned-cache removal may help isolate the fault, but it is a diagnostic intervention. It should not become a customer instruction to clear all website data, sign-ins and saved work.
Accept the repair when the original returning-visitor journey works with development overrides disabled, the update state matches the message, and offline or failed-install cases have an honest recovery route. Keep the response, controller and release evidence together so the next deployment can be compared with the same conditions.
Sources and verification
Editorial review 2026-10-14. Source check dates are recorded separately. Notes describe what each source supports and its limits.
View sources
- MDN: Using Service WorkersChecked Worker interception, installation, activation, registration and controlled-page lifecycle.
Limits: An application chooses its caching and update strategy; installing a worker does not supply a safe strategy automatically. - web.dev: The service worker lifecycleChecked Waiting updates, open-client compatibility, skipWaiting risks, stable script URLs and application-owned cache prefixes.
Limits: The tutorial's demonstrations are not a tested deployment recipe for an arbitrary framework or plugin. - MDN: CacheChecked Named Cache Storage, explicit updates and deletion, independent HTTP-cache semantics and browser storage limits.
Limits: Stored entries can be evicted; their existence does not guarantee offline completeness or privacy. - MDN: ServiceWorkerRegistrationChecked Registration scope, installing/waiting/active workers and the update method.
Limits: A registration's active worker is not proof that the current document is controlled or that every response is fresh.