DEV Community

Shanu
Shanu

Posted on

How to make custom push notification? How does the entire process work?

This guide walks you through the process of creating a custom push notification system, from the moment a user visits your site to when they receive a push notification. We'll cover the flow of events, data handling, and the interactions between the client (browser) and server.

The Process: Step by Step

1. User Visits Your Website

When a user first visits your website, two main steps occur:

  1. Service Worker Registration: Your JavaScript checks if the browser supports service workers and registers one if supported. This is done using the following code:
if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js')
    .then(function(registration) {
        console.log('Service Worker registered with scope:', registration.scope);
    }).catch(function(error) {
        console.error('Service Worker registration failed:', error);
    });
}
Enter fullscreen mode Exit fullscreen mode
  1. User Permission Request: The site prompts the user to allow push notifications. This is done using the Notification.requestPermission() method:
Notification.requestPermission().then(function(permission) {
    if (permission === 'granted') {
        console.log('Notification permission granted.');
        // Proceed to subscribe the user to push notifications
    } else {
        console.log('Notification permission denied.');
    }
});
Enter fullscreen mode Exit fullscreen mode

2. User Subscribes to Push Notifications

If the user grants permission, the following steps occur:

  1. Create Push Subscription: The service worker's PushManager subscribes the user to push notifications. This is done using the following function:
function subscribeUser() {
    navigator.serviceWorker.ready.then(function(registration) {
        const publicKey = 'Your Public VAPID Key Here';
        registration.pushManager.subscribe({
            userVisibleOnly: true,
            applicationServerKey: urlBase64ToUint8Array(publicKey)
        }).then(function(subscription) {
            console.log('User is subscribed:', subscription);
            // Send the subscription to your server
            sendSubscriptionToServer(subscription);
        }).catch(function(error) {
            console.error('Failed to subscribe the user:', error);
        });
    });
}
Enter fullscreen mode Exit fullscreen mode
  1. Send Subscription to Server: The subscription object is sent to your server via an AJAX request. You can use a function like this:
function sendSubscriptionToServer(subscription) {
    return fetch('/save-subscription', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(subscription)
    }).then(function(response) {
        if (!response.ok) {
            throw new Error('Failed to save subscription on server');
        }
        return response.json();
    }).then(function(data) {
        console.log('Subscription saved on server:', data);
    }).catch(function(error) {
        console.error('Error saving subscription on server:', error);
    });
}
Enter fullscreen mode Exit fullscreen mode
  1. Server Saves Subscription: Your server receives the subscription object and stores it in a database. A simple database schema might look like this:
CREATE TABLE push_subscriptions (
    id SERIAL PRIMARY KEY,
    endpoint TEXT NOT NULL,
    auth_key TEXT NOT NULL,
    p256dh_key TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Enter fullscreen mode Exit fullscreen mode

3. Sending a Push Notification

When you want to send a notification:

  1. Prepare Notification Payload: Create a payload for the notification on your server. This could be a JSON object containing title, body, icon, and other relevant data:
const payload = JSON.stringify({
    title: 'Hello!',
    body: 'You have a new notification.',
    icon: '/icon.png',
    badge: '/badge.png'
});
Enter fullscreen mode Exit fullscreen mode
  1. Send Push Notification: Use a library like web-push to send the notification to subscribed users. Here's an example of how to do this:
const webpush = require('web-push');

const vapidKeys = {
    publicKey: 'Your Public VAPID Key Here',
    privateKey: 'Your Private VAPID Key Here'
};

webpush.setVapidDetails(
    'mailto:your-email@example.com',
    vapidKeys.publicKey,
    vapidKeys.privateKey
);

// Retrieve subscriptions from the database
const subscriptions = getSubscriptionsFromDatabase();

subscriptions.forEach(subscription => {
    webpush.sendNotification(subscription, payload)
    .then(response => console.log('Notification sent:', response))
    .catch(error => console.error('Error sending notification:', error));
});
Enter fullscreen mode Exit fullscreen mode
  1. Handle Push Event in Service Worker: The service worker displays the notification when it reaches the user's browser. This is done by adding an event listener in your service worker file:
// service-worker.js
self.addEventListener('push', function(event) {
    const data = event.data.json();
    const options = {
        body: data.body,
        icon: data.icon,
        badge: data.badge
    };
    event.waitUntil(
        self.registration.showNotification(data.title, options)
    );
});
Enter fullscreen mode Exit fullscreen mode

4. Handling User Interaction with Notifications

When a user interacts with a notification, the service worker listens for the notificationclick event. You can handle this event in your service worker like this:

// service-worker.js
self.addEventListener('notificationclick', function(event) {
    event.notification.close();
    event.waitUntil(
        clients.openWindow('https://yourwebsite.com')
    );
});
Enter fullscreen mode Exit fullscreen mode

If you define custom actions within the notification, you can handle these too:

self.addEventListener('notificationclick', function(event) {
    const action = event.action;
    if (action === 'view') {
        clients.openWindow('/specific-page');
    } else {
        clients.openWindow('/');
    }
    event.notification.close();
});
Enter fullscreen mode Exit fullscreen mode

Error Handling and Maintenance

To handle failed notifications and clean up your database, you can use error handling in your notification sending code:

webpush.sendNotification(subscription, payload)
.catch(error => {
    if (error.statusCode === 410 || error.statusCode === 404) {
        console.log('Subscription has expired or is no longer valid:', subscription.endpoint);
        // Remove subscription from database
        deleteSubscriptionFromDatabase(subscription.endpoint);
    } else {
        console.error('Error sending notification:', error);
    }
});
Enter fullscreen mode Exit fullscreen mode

Regularly check and clean up your database by removing subscriptions that are no longer valid.

Tech Stack

To implement this system, you'll need:

  • Client-Side: HTML/CSS/JavaScript, Service Worker, Push API, Notifications API
  • Server-Side: Node.js, Express.js, Web-Push Library, Database (e.g., PostgreSQL, MySQL)
  • General Tools: Web Server (e.g., Nginx), SSL Certificate, Git, NPM or Yarn
  • Optional: Monitoring Tools, Automated Deployment Tools, Database Backup Solutions

Summary

This guide provides a robust, self-hosted push notification system, ensuring full control and customization. The process involves setting up a service worker, managing user permissions, handling subscriptions, sending notifications, and maintaining the system. With this setup, you have complete control over your notification system, allowing for customization and optimization according to your specific needs.

Top comments (0)