Skip to content

Registering a Service Worker

Before a service worker can intercept any requests, the page must register it. Registration tells the browser where to find the service worker file and which URLs it should control.

if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/sw.js')
.then((registration) => {
console.log('SW registered, scope:', registration.scope);
})
.catch((error) => {
console.error('SW registration failed:', error);
});
}

navigator.serviceWorker.register() returns a Promise that resolves to a ServiceWorkerRegistration object. The most important property on that object is scope.

Always guard the call with 'serviceWorker' in navigator. Browsers that do not support service workers (some very old browsers, or pages served over plain HTTP) will simply skip the block. Never let a missing API crash your page.

The scope determines which pages and sub-paths the service worker controls. By default it is the directory that contains the service worker file:

SW file locationDefault scopePages controlled
/sw.js/The entire origin
/app/sw.js/app/Only /app/ and below
/shop/sw.js/shop/Only /shop/ and below

You can narrow the scope (but never widen it beyond the SW file’s directory) by passing a scope option:

navigator.serviceWorker.register('/sw.js', { scope: '/shop/' });

Service workers only run on secure origins:

  • https:// — any HTTPS page in production.
  • http://localhost and http://127.0.0.1 — explicitly exempted for local development.

Attempting to register on plain http:// (other than localhost) will silently fail or throw a SecurityError. Always deploy your PWA over HTTPS.

The demo below registers a minimal service worker. Open the StackBlitz project and check the browser console — you will see the registration log and the SW’s scope.

Runs a real service worker + manifest in your browser.
OptionBenefitCost
Register the service worker at page loadCache and offline support are ready as fast as possibleAdds work on the main thread during the very first load, while the user is waiting for critical content
Register after the load event (deferred)Does not compete with the critical rendering path on first loadA user who closes the tab too quickly may never get registered at all
  • Registering the service worker at the wrong path for the desired scope, so it ends up controlling only part of the site instead of the whole thing.
  • Not checking if ('serviceWorker' in navigator) before registering, so older unsupported browsers throw an error mid-page.
  • Registering repeatedly without guarding against it, producing multiple service worker versions racing to handle fetch events.

web.dev’s own PWA checklist recommends registering the service worker after the load event so it does not compete for bandwidth with critical resources on first paint. Twitter’s PWA case study describes a similar incremental, deferred rollout strategy for its service worker (web.dev/twitter).

What does navigator.serviceWorker.register() return?
On which origins can a service worker be registered?
You place sw.js at /admin/sw.js. What is its default scope?
Why should you wrap the register call with "serviceWorker" in navigator?