Progressive Web Apps (PWA)
Push Notifications
Push Notifications in PWAs
Push notifications allow your PWA to send messages to users even when the app is not open. This powerful feature can significantly improve user engagement by delivering timely updates, alerts, and personalized content.
Push API Overview
The Push API enables web applications to receive messages pushed from a server, regardless of whether the app is active. It works in conjunction with Service Workers to display notifications.
Key Components:
- Push Service: Browser-managed service that handles message delivery
- Push Subscription: Unique endpoint for each user device
- Notifications API: Displays visual notifications to users
- Service Worker: Receives push events in the background
- Application Server: Your backend that sends push messages
Requesting Notification Permission
Before sending notifications, you must request permission from the user:
// Check if notifications are supported
if ('Notification' in window) {
console.log('Notifications are supported');
} else {
console.log('Notifications are not supported');
}
// Request permission
async function requestNotificationPermission() {
const permission = await Notification.requestPermission();
if (permission === 'granted') {
console.log('Notification permission granted');
return true;
} else if (permission === 'denied') {
console.log('Notification permission denied');
return false;
} else {
console.log('Notification permission dismissed');
return false;
}
}
// Usage with user interaction
document.getElementById('enable-notifications').addEventListener('click', async () => {
const granted = await requestNotificationPermission();
if (granted) {
await subscribeToPushNotifications();
}
});
Important: Notification permission requests must be triggered by a user interaction (like clicking a button). Requesting permission on page load is considered bad UX and may be blocked by browsers.
Creating a Push Subscription
Subscribe the user to push notifications using the PushManager API:
// Generate VAPID keys first (server-side):
// npm install web-push
// npx web-push generate-vapid-keys
const publicVapidKey = 'YOUR_PUBLIC_VAPID_KEY';
async function subscribeToPushNotifications() {
try {
const registration = await navigator.serviceWorker.register('/sw.js');
await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(publicVapidKey)
});
console.log('Push subscription:', JSON.stringify(subscription));
// Send subscription to your server
await fetch('/api/push-subscribe', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(subscription)
});
console.log('Subscription saved to server');
return subscription;
} catch (error) {
console.error('Failed to subscribe:', error);
}
}
function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding).replace(/\-/g, '+').replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
Handling Push Events in Service Worker
Listen for push events in your service worker and display notifications:
// In sw.js
self.addEventListener('push', (event) => {
let notificationData = {
title: 'New Notification',
body: 'You have a new message',
icon: '/images/icon-192x192.png',
badge: '/images/badge-72x72.png',
tag: 'notification-1',
data: { url: '/messages' }
};
if (event.data) {
const payload = event.data.json();
notificationData = { ...notificationData, ...payload };
}
event.waitUntil(
self.registration.showNotification(notificationData.title, {
body: notificationData.body,
icon: notificationData.icon,
badge: notificationData.badge,
tag: notificationData.tag,
data: notificationData.data,
vibrate: [200, 100, 200],
actions: [
{ action: 'open', title: 'Open' },
{ action: 'close', title: 'Close' }
]
})
);
});
Exercise:
- Implement a notification permission request UI with clear explanation
- Create a push subscription and send it to your server
- Set up a Node.js server with web-push to send test notifications
- Handle notification clicks to navigate to specific pages
- Add notification action buttons and handle their clicks