Concept in Service Worker
Service-Worker-Allowed header
Published Updated
The Service-Worker-Allowed HTTP response header lets a service worker registration
request a scope beyond the script’s directory. Return it with the script to set the
maximum allowed scope path.
Browser and platform support
Section titled “Browser and platform support”Service worker registration requires a secure context, as specified by Service Workers.
How it works
Section titled “How it works”Without the header, the Service Workers specification derives the maximum allowed scope from the
script URL’s directory. A script at /product/sw.js therefore has /product/ as its default
maximum. Returning Service-Worker-Allowed: / with that script lets a registration request /.
The header value is a URL parsed relative to the script URL. The specification compares the
requested scope path with that maximum path. A requested scope path that does not start with the
maximum allowed path, or a header URL whose origin differs from the script URL, causes the
registration job to reject with a SecurityError. If parsing the header value as a URL fails, the
fetch completes with a network error; the update algorithm later rejects the job with a TypeError
unless a SecurityError was already invoked.
Examples
Section titled “Examples”The server must attach the header to the service worker script response, not to the page that calls
register(). The client can then request the matching wider scope.
Serve the script with a root maximum scope
Section titled “Serve the script with a root maximum scope”This Node HTTP handler returns the header with /product/sw.js. The service worker body is valid
JavaScript and installs without adding cache entries.
import { createServer } from 'node:http';
createServer((request, response) => { if (request.url === '/product/sw.js') { response.writeHead(200, { 'content-type': 'text/javascript', 'service-worker-allowed': '/', }); response.end("self.addEventListener('install', () => {});"); return; }
response.writeHead(404); response.end('Not found');}).listen(8080);With this response, the specification permits /product/sw.js to request / as its registration
scope.
Register the wider scope with a fallback
Section titled “Register the wider scope with a fallback”Check for service worker support before registering. If registration rejects, keep the page online-only and report the deployment error without assuming that the worker controls the page.
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/product/sw.js', { scope: '/' }) .then((registration) => { console.log('Registered scope:', registration.scope); }) .catch((error) => { console.error('Service worker registration failed:', error); document.documentElement.dataset.offline = 'unavailable'; });} else { document.documentElement.dataset.offline = 'unsupported';}The requested scope must stay within the maximum named by the header. For example,
Service-Worker-Allowed: /product/ does not permit { scope: '/' }.
See also
Section titled “See also”- Service worker registration and scope
- Service worker lifecycle
- Debugging service workers
- Service Workers: Service-Worker-Allowed (w3c.github.io)
- Service-Worker-Allowed header (MDN)
Specifications
| Specification | Status |
|---|---|
| Service Workers | W3C draft |
| Service Workers: Service-Worker-Allowed | W3C draft |
- Legend
- Yes
- Partial
- Flag
- No
- Unknown
| Browser / Platform | Support | Versions | Confidence | Source | Notes |
|---|---|---|---|---|---|
| Chrome (Desktop)# | Yes | 40 | high | source | — |
| Chrome (Android)# | Yes | 40 | high | source | 1 |
| Edge (Desktop)# | Yes | 17 | high | source | — |
| Firefox (Desktop)# | Yes | 44 | high | source | — |
| Firefox (Android)# | Yes | 44 | high | source | 2 |
| Safari (macOS)# | Yes | 11.1 | high | source | — |
| Safari (iOS)# | Yes | 11.3 | high | source | 3 |
| Samsung Internet# | Yes | 4.0 | high | source | 4 |
| WebView (Android)# | Yes | 40 | high | source | 5 |
- Derived by browser-compat-data mirroring from Chrome.
- Derived by browser-compat-data mirroring from Firefox.
- Derived by browser-compat-data mirroring from Safari.
- Derived by browser-compat-data mirroring from Chrome Android.
- Derived by browser-compat-data mirroring from Chrome Android.