In our previous article, we explored the backend implementation of a push notification system using Node.js. We covered how to set up a server to handle push notifications, manage user subscriptions, and ensure a production-grade environment. If you missed that, you can catch up on the details of backend setup and best practices in our first article.
In this second part, we shift our focus to the frontend implementation. Here, you'll learn how to integrate the push notification system with your web application's frontend. This involves requesting user permissions, registering a service worker, subscribing users to push notifications, and sending subscription data to your backend. By connecting the frontend and backend components, you'll create a complete push notification system that enhances user engagement even when your web application is not actively open.
Frontend Integration for Push Notifications
Integrating push notifications into the frontend involves several steps to ensure that users can subscribe to notifications and receive them even when the web application is not actively open. Here’s a step-by-step guide:
1. Request User Permission
Code:
// public/main.js
// Check if the browser supports service workers and notifications
if ('serviceWorker' in navigator && 'PushManager' in window) {
// Register the service worker
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
// Request permission for notifications
return Notification.requestPermission()
.then(permission => {
if (permission === 'granted') {
console.log('Notification permission granted.');
} else {
console.error('Notification permission denied.');
}
});
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
}
Explanation:
- Service Worker and PushManager Support Check: We first check if the browser supports Service Workers and the PushManager API. Service Workers are a core technology for push notifications, allowing background scripts to handle push events.
-
Service Worker Registration: The
navigator.serviceWorker.register('/service-worker.js')
line registers a service worker from theservice-worker.js
file. This is crucial because the service worker is responsible for receiving push messages and displaying notifications. -
Notification Permission Request:
Notification.requestPermission()
prompts the user to allow or deny notifications. This is a required step before you can send notifications to the user. Handling the user's response ensures that notifications are only sent if the user has granted permission.
2. Register a Service Worker
Code:
// public/service-worker.js
self.addEventListener('push', event => {
const data = event.data.json();
self.registration.showNotification(data.title, {
body: data.body,
icon: '/images/icon.png'
});
});
Explanation:
-
Service Worker Setup: The
service-worker.js
file contains the script that runs in the background of the user's browser. -
Push Event Listener:
self.addEventListener('push', event => {...})
listens for push events sent by the server. When a push message is received, this event triggers. -
Displaying Notifications:
self.registration.showNotification(data.title, {...})
shows a notification with the specified title and body. This is how the notification appears to the user. Theicon
can be customized to show a relevant image.
3. Subscribe to Push Notifications
Code:
// public/main.js
navigator.serviceWorker.ready
.then(registration => {
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array('<YOUR_PUBLIC_VAPID_KEY>')
});
})
.then(subscription => {
// Send the subscription object to your backend
return fetch('/api/subscribe', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(subscription)
});
})
.catch(error => {
console.error('Failed to subscribe:', error);
});
// Helper function to convert base64 VAPID key to Uint8Array
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;
}
Explanation:
-
Service Worker Ready:
navigator.serviceWorker.ready
ensures that the service worker is fully installed and ready to handle push events. -
Subscription:
registration.pushManager.subscribe({...})
creates a subscription to the push service using theapplicationServerKey
, which is your public VAPID key. This key is required for sending notifications to this subscription. - Send Subscription to Backend: The subscription object is sent to your server, where it can be stored for future use. This allows your server to send notifications to the client.
-
Convert VAPID Key:
urlBase64ToUint8Array
converts the base64-encoded VAPID key to a Uint8Array. This conversion is necessary because thepushManager.subscribe
method requires the key in this format.
4. Handle Subscription on the Backend
Code:
// /controllers/notificationController.js
const User = require('../models/user');
exports.saveSubscription = async (req, res, next) => {
try {
const { userId, subscription } = req.body;
const user = await User.findById(userId);
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
user.subscriptions.push(subscription);
await user.save();
res.status(200).json({ message: 'Subscription saved' });
} catch (error) {
next(error);
}
};
Explanation:
-
Save Subscription: The
saveSubscription
function takes the subscription object from the frontend and saves it to the database associated with a user. This allows your backend to keep track of which users want to receive notifications and where to send them.
5. Update Routes
Code:
// /routes/notificationRoutes.js
router.post('/subscribe', notificationController.saveSubscription);
Explanation:
-
Subscription Route: Adds a new endpoint to handle subscription requests. When the frontend sends subscription data, this route calls the
saveSubscription
controller function to process and store the subscription.
Summary
Integrating push notifications into the frontend involves:
- Requesting Permission: Asking users to allow notifications.
- Registering a Service Worker: Setting up the background script to handle push messages and display notifications.
- Subscribing to Push Notifications: Creating a subscription and sending it to the backend.
- Handling Subscription Data on Backend: Storing subscription information in the database.
- Updating Routes: Adding endpoints to manage subscription data.
These steps ensure that your users can receive timely push notifications and that your application is set up to handle them correctly. Each step is crucial for creating a seamless experience for users while maintaining a robust backend system.
With the frontend integration now complete, you’ve successfully connected your web application to a fully functional push notification system. By following the steps outlined, you've learned how to request user permissions, register service workers, handle push events, and manage user subscriptions. This integration ensures that users receive timely updates and notifications, even when they're not actively interacting with your site.
If you haven’t yet explored the backend setup, be sure to review our first article for a comprehensive guide on the server-side implementation. Together, these articles provide a complete picture of how to build and deploy a robust push notification system in a production environment.
Feel free to revisit both parts of this series as you implement push notifications in your projects, and don’t hesitate to reach out if you have any questions or need further assistance.
Top comments (0)