Real-Time Updates in Chrome Extensions: Web Push, GCM, and WebSockets (2026)
Real-Time Updates for Chrome Extensions
Modern extensions need real-time capabilities — live notifications, server-pushed state updates, or bidirectional data streams. Chrome offers three approaches, each with different tradeoffs around battery life, complexity, and capability.
Comparing the Three Approaches
| Feature | Web Push (Push API) | chrome.gcm | WebSockets |
|---|---|---|---|
| Direction | Server → Client | Server → Client | Bidirectional |
| Wakes suspended extension | Yes | Yes | No |
| Battery impact | Low | Low | Higher |
| Chrome version | 121+ | All versions | 116+ |
| Standards-based | Yes | No (legacy) | Yes |
| Best for | Notifications, state updates | Legacy broad messaging | Live data, chat |
Option 1: Web Push (Recommended)
The modern, standards-based approach. Web Push wakes your extension’s service worker when a message arrives — no keepalive needed.
Setup
{
"manifest_version": 3,
"permissions": ["notifications"],
"background": {
"service_worker": "service-worker.js"
}
}Subscribe to Push
// service-worker.js
async function subscribeToPush() {
const registration = await self.registration;
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(
'YOUR_VAPID_PUBLIC_KEY'
)
});
// Send subscription to your server
await fetch('https://your-server.com/api/push/subscribe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(subscription)
});
return subscription;
}
function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
const rawData = atob(base64);
return new Uint8Array([...rawData].map(c => c.charCodeAt(0)));
}Handle Push Events
self.addEventListener('push', (event) => {
const data = event.data?.json() ?? {};
event.waitUntil(
self.registration.showNotification(data.title || 'Update', {
body: data.body || 'You have a new update.',
icon: 'icons/icon-128.png',
badge: 'icons/badge-72.png',
data: { url: data.url },
actions: [
{ action: 'open', title: 'View' },
{ action: 'dismiss', title: 'Dismiss' }
]
})
);
});
self.addEventListener('notificationclick', (event) => {
event.notification.close();
if (event.action === 'open' || !event.action) {
event.waitUntil(
clients.openWindow(event.notification.data?.url || 'https://extensionbooster.com')
);
}
});Server-Side (Node.js)
const webpush = require('web-push');
webpush.setVapidDetails(
'mailto:your@email.com',
'YOUR_VAPID_PUBLIC_KEY',
'YOUR_VAPID_PRIVATE_KEY'
);
async function sendPush(subscription, payload) {
await webpush.sendNotification(
subscription,
JSON.stringify(payload)
);
}
// Send to a subscriber
sendPush(subscription, {
title: 'Price Drop Alert',
body: 'MacBook Pro is now $200 off!',
url: 'https://example.com/deal'
});Option 2: chrome.gcm (Legacy)
Built on deprecated Firebase Cloud Messaging HTTP protocol. Still works indefinitely for extensions but lacks modern features.
// Register for GCM
chrome.gcm.register(['YOUR_SENDER_ID'], (registrationId) => {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
return;
}
// Send registrationId to your server
sendToServer(registrationId);
});
// Listen for messages
chrome.gcm.onMessage.addListener((message) => {
chrome.notifications.create({
type: 'basic',
iconUrl: 'icons/icon-128.png',
title: message.data.title,
message: message.data.body
});
});When to use: Only if you need to support Chrome versions before 121, or have existing GCM infrastructure.
Option 3: WebSockets
Best for frequent, bidirectional communication (chat, collaboration, live data). Requires keepalive to prevent service worker termination.
let ws = null;
function connect() {
ws = new WebSocket('wss://your-server.com/ws');
ws.onopen = () => {
startKeepAlive();
ws.send(JSON.stringify({ type: 'auth', token: 'user-token' }));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
handleRealtimeUpdate(data);
};
ws.onclose = () => {
ws = null;
stopKeepAlive();
setTimeout(connect, 5000); // Reconnect
};
}
function startKeepAlive() {
setInterval(() => {
if (ws?.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: 'ping' }));
}
}, 20000);
}Key limitation: WebSockets cannot wake a suspended extension. Chrome has no awareness of connections initiated outside the extension, so if the service worker terminates, the connection is lost until something else wakes the worker.
Decision Framework
Use Web Push when:
- You need to wake the extension from outside
- Updates are infrequent (minutes to hours apart)
- Battery life matters (mobile, laptops)
- You want the simplest server-side implementation
Use WebSockets when:
- You need bidirectional communication
- Updates are frequent (seconds apart)
- The extension is actively being used
- You need low latency
Use chrome.gcm when:
- You must support Chrome < 121
- You have existing GCM/FCM infrastructure
What’s Next
Real-time capabilities transform your extension from a passive tool into an active assistant. Start with Web Push for notifications, add WebSockets when you need bidirectional communication, and always consider battery impact.
Discover more extension development strategies at ExtensionBooster.
Share this article
Build better extensions with free tools
Icon generator, MV3 converter, review exporter, and more — no signup needed.
Related Articles
I Built the Same Chrome Extension With 5 Different Frameworks. Here's What Actually Happened.
WXT vs Plasmo vs CRXJS vs Extension.js vs Bedframe. Real benchmarks, honest opinions, and the framework with 12K stars that's quietly dying.
5 Best Email Marketing Services to Grow Your Chrome Extension (2026)
Compare the top email marketing platforms for SaaS and Chrome extension developers. MailerLite, Mailchimp, Brevo, ActiveCampaign, and Drip reviewed.
15 Best Practices to Build a Browser Extension That Users Love (2026 Guide)
Master browser extension development in 2026. Manifest V3, security, performance, and UX best practices to build extensions users love.