Push Notifications
Trigger native push notifications from MQTT messages using service workers.
Push notifications reach users even when your application is not in the foreground. By combining MQTT subscriptions with the Web Push API and service workers, you can convert incoming MQTT messages into native browser notifications.
Architecture
A service worker runs in the background and maintains an MQTT connection. When a message arrives on a notification topic, the service worker triggers the browser's Push API to display a native notification.
CloudSignal ──MQTT message──▶ Service Worker ──Push API──▶ Native Notification
│
└── Runs even when tab is inactivePush notifications require HTTPS and explicit user permission. Always request permission in response to a user action, not on page load.
How It Works
- User grants permission for notifications in the browser
- Service worker registers and establishes an MQTT connection
- MQTT message arrives on the user's notification topic
- Service worker creates a native push notification using the Notification API
- User clicks the notification to open the relevant page
Implementation
Register the Service Worker
// main.js
async function setupPushNotifications() {
// Request notification permission
const permission = await Notification.requestPermission()
if (permission !== 'granted') return
// Register service worker
const registration = await navigator.serviceWorker.register(
'/notification-worker.js'
)
// Send MQTT credentials to the service worker
registration.active.postMessage({
type: 'INIT_MQTT',
config: {
host: 'wss://connect.cloudsignal.app:18885/',
username: 'user-alice',
token: 'your-token',
topic: 'notify/alice'
}
})
}Service Worker with MQTT
// notification-worker.js
importScripts('https://cdn.cloudsignal.com/mqtt-worker.min.js')
let mqttClient = null
self.addEventListener('message', (event) => {
if (event.data.type === 'INIT_MQTT') {
const { host, username, token, topic } = event.data.config
mqttClient = CloudSignalMQTT.connect({
host,
username,
password: token
})
mqttClient.subscribe(topic, { qos: 1 })
mqttClient.on('message', (topic, payload) => {
const data = JSON.parse(payload.toString())
showNotification(data)
})
}
})
function showNotification(data) {
self.registration.showNotification(data.title, {
body: data.body,
icon: '/icons/notification-icon.png',
badge: '/icons/badge-icon.png',
data: { url: data.action?.url || '/' },
tag: data.id // Prevents duplicate notifications
})
}
// Handle notification click
self.addEventListener('notificationclick', (event) => {
event.notification.close()
event.waitUntil(
clients.openWindow(event.notification.data.url)
)
})Trigger from Server
Use the same server-side publish pattern as in-app notifications:
await fetch('https://api.cloudsignal.com/v2/publish', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_your_secret_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
topic: 'notify/alice',
payload: JSON.stringify({
id: 'notif-001',
title: 'New order received',
body: 'Order #4521 needs review',
action: { url: '/orders/4521' }
}),
qos: 1
})
})Combining In-App and Push
A common pattern is to use the same notification topic for both in-app and push notifications. The in-app handler displays a toast when the app is visible, and the service worker shows a native notification when it is not.
// In your app code
client.on('message', (topic, payload) => {
if (document.visibilityState === 'visible') {
showToast(JSON.parse(payload.toString()))
}
// Service worker handles push when tab is not visible
})Next Steps
- PWA Extension reference - full setup for progressive web app integration
- App Notifications - in-app notification patterns
- Offline Caching - ensure messages are not lost during disconnection