webpushkit
v0.1.14
Published
A library for setting up web push notifications in frontend web clients.
Readme
webpushkit
Client Setup Guide for Push Notifications
This guide explains how to integrate push notifications into your web application using the Push Notification Service.
Table of Contents
- Overview
- Prerequisites
- Getting Started
- Step-by-Step Setup
- API Reference
- Example Implementation
- Error Handling
- Best Practices
Overview
The Push Notification Service uses the Web Push Protocol (W3C Push API) to send notifications to users' browsers. The service requires:
- A Service Worker to handle incoming push notifications
- A unique device_id to identify each subscription
Note: VAPID keys and service endpoints are pre-configured in this package.
Prerequisites
- HTTPS: Push notifications require a secure context (HTTPS or localhost)
- Service Worker Support: The browser must support Service Workers
- Push API Support: The browser must support the Push API
- Whitelisted Origin: Your origin must be whitelisted on the push notification service (if required)
Getting Started
1. Install the Package
npm install webpushkit2. Initialize the Service Worker
After installation, run the setup command to initialize the service worker:
npx webpushkit initThis will:
- Create a
publicdirectory if it doesn't exist - Copy the service worker file as
sw.jsto your project'spublicdirectory (default path) - Also copy it as
worker.jsfor backward compatibility
3. Configure Options (Optional)
The package comes pre-configured with the push notification service. Configure it based on your needs:
// For whitelisted apps (no API key needed)
const pushManager = new PushNotificationManager();
// For apps that need an API key
const pushManager = new PushNotificationManager({
apiKey: 'your-api-key-here' // optional, only needed if your app is not whitelisted
});
// For development environment
const pushManager = new PushNotificationManager({
environment: 'dev' // uses http://localhost:3000/pusher
});
// For custom base URL
const pushManager = new PushNotificationManager({
baseURL: 'https://your-custom-url.com/pusher'
});
// Custom service worker path (defaults to /sw.js)
const pushManager = new PushNotificationManager({
serviceWorkerPath: '/custom-sw.js'
});Step-by-Step Setup
Step 1: Register a Service Worker and Request Permission
The service worker file (sw.js) is automatically copied to your public directory when you run npx webpushkit init. The service worker handles incoming push notifications and notification clicks.
Note: The initialize() method automatically registers the service worker and requests notification permission. You don't need to handle these steps manually.
Step 2: Subscribe to Push Notifications
Subscribe to push notifications using the PushNotificationManager:
import { PushNotificationManager } from 'webpushkit';
// For whitelisted apps (no API key needed)
const pushManager = new PushNotificationManager();
// For apps that need an API key
// const pushManager = new PushNotificationManager({
// apiKey: 'your-api-key-here'
// });
// For development environment
// const pushManager = new PushNotificationManager({
// environment: 'dev'
// });
// Initialize and subscribe
await pushManager.initialize();
await pushManager.subscribe();Note: The PushNotificationManager automatically generates and stores a unique device ID in localStorage when needed. You don't need to handle this manually.
Step 3: Unsubscribe from Push Notifications
To unsubscribe, call the unsubscribe method:
await pushManager.unsubscribe();API Reference
PushNotificationManager
The main class for managing push notifications.
Constructor
new PushNotificationManager(config?: PushNotificationConfig)Config Options:
serviceWorkerPath(string, optional): Path to service worker file (defaults to/sw.js)apiKey(string, optional): API key for authentication. Only required if your app is not whitelisted.environment("dev" | "prod", optional): Sets the base URL automatically. If"dev", useshttp://localhost:3000/pusher. If"prod"or not specified, useshttps://the-monolith.onrender.com/pusher.baseURL(string, optional): Custom base URL for the push service. If provided, overrides theenvironmentsetting. Should include the/pusherpath.
Note: VAPID public key is pre-configured. Base URL defaults to production (https://the-monolith.onrender.com/pusher) unless environment: "dev" or a custom baseURL is provided. API key is optional - whitelisted apps don't need it.
Methods
initialize(): Promise<boolean>
Registers the service worker and requests notification permission. Returns true if successful, false otherwise.
isSupported(): boolean
Checks if push notifications are supported in the current browser.
registerServiceWorker(): Promise<ServiceWorkerRegistration>
Registers the service worker. Called automatically by initialize().
requestPermission(): Promise<boolean>
Requests notification permission from the user. Returns true if granted, false otherwise.
subscribe(): Promise<SubscribeResponse>
Subscribes to push notifications and sends the subscription to the server.
Returns:
{
status_code: number;
message: string;
data: {
endpoint: string;
device_id: string;
};
}unsubscribe(deviceIds?: string[]): Promise<UnsubscribeResponse>
Unsubscribes from push notifications. If no device IDs are provided, unsubscribes the current device. When unsubscribing the current device (or if the current device ID is included in the provided array), this method also:
- Unsubscribes from the browser's PushManager
- Removes the device ID from localStorage
Returns:
{
status_code: number;
message: string;
data: {
device_ids: string[];
removed_count: number;
removed_subscriptions: any[];
};
}isSubscribed(): Promise<boolean>
Checks if currently subscribed to push notifications.
getOrCreateDeviceId(): string
Gets or creates a unique device ID stored in localStorage. Returns the existing device ID if present, otherwise generates and stores a new one.
generateUUID(): string
Generates a UUID v4 string. Uses crypto.randomUUID() if available, otherwise falls back to a polyfill.
notify(deviceIds: string[], payload: PushNotificationPayload): Promise<{success: boolean; error?: string}>
Sends push notifications to one or more devices. Typically called from your backend, but provided for convenience.
Exported Functions
The package also exports standalone utility functions:
getOrCreateDeviceId(): string
Gets or creates a unique device ID stored in localStorage. Can be imported and used independently:
import { getOrCreateDeviceId } from 'webpushkit';
const deviceId = getOrCreateDeviceId();generateUUID(): string
Generates a UUID v4 string. Can be imported and used independently:
import { generateUUID } from 'webpushkit';
const uuid = generateUUID();Subscribe Endpoint
POST {baseURL}/subscribe
Where baseURL defaults to https://the-monolith.onrender.com/pusher (production) or http://localhost:3000/pusher (development), or can be customized via config.
Subscribe a device to push notifications.
Headers:
Content-Type: application/jsonx-api-key: <your-api-key>(optional, only if app is not whitelisted)
Request Body:
{
"subscription": {
"endpoint": "https://fcm.googleapis.com/fcm/send/...",
"keys": {
"p256dh": "base64-encoded-key",
"auth": "base64-encoded-key"
},
"expiration_time": "2024-12-31T23:59:59.000Z",
"metadata": {
"userAgent": "...",
"timestamp": "..."
}
},
"device_id": "unique-device-id"
}Response:
{
"status_code": 201,
"message": "Subscribed successfully",
"data": {
"endpoint": "https://fcm.googleapis.com/fcm/send/...",
"device_id": "unique-device-id"
}
}Unsubscribe Endpoint
POST {baseURL}/unsubscribe
Where baseURL defaults to https://the-monolith.onrender.com/pusher (production) or http://localhost:3000/pusher (development), or can be customized via config.
Unsubscribe one or more devices from push notifications.
Headers:
Content-Type: application/jsonx-api-key: <your-api-key>(optional, only if app is not whitelisted)
Request Body:
{
"device_ids": ["device-id-1", "device-id-2"]
}Response:
{
"status_code": 200,
"message": "Successfully unsubscribed 2 devices",
"data": {
"device_ids": ["device-id-1", "device-id-2"],
"removed_count": 2,
"removed_subscriptions": [...]
}
}Notify Endpoint
POST {baseURL}/notify
Where baseURL defaults to https://the-monolith.onrender.com/pusher (production) or http://localhost:3000/pusher (development), or can be customized via config.
Send push notifications to one or more devices (typically called from your backend).
Headers:
Content-Type: application/jsonx-api-key: <your-api-key>(optional, only if app is not whitelisted)
Request Body:
{
"device_ids": ["device-id-1", "device-id-2"],
"payload": {
"title": "Notification Title",
"body": "Notification body text",
"icon": "/icon-192x192.png",
"badge": "/badge-72x72.png",
"image": "/large-image.png",
"tag": "notification-tag",
"requireInteraction": false,
"silent": false,
"renotify": false,
"timestamp": 1234567890,
"vibrate": [200, 100, 200],
"lang": "en",
"dir": "auto",
"data": {
"url": "/path/to/open",
"spaceId": "space-123"
},
"actions": [
{
"action": "view",
"title": "View",
"icon": "/view-icon.png"
}
]
}
}Example Implementation
Here's a complete example of integrating push notifications:
import { PushNotificationManager } from 'webpushkit';
// Configure for your environment
const pushManager = new PushNotificationManager({
// apiKey: 'your-api-key-here', // optional
// environment: 'dev', // optional, for development
});
// Initialize and subscribe
pushManager.initialize()
.then(async (initialized) => {
if (initialized) {
const isSubscribed = await pushManager.isSubscribed();
if (!isSubscribed) {
await pushManager.subscribe();
}
}
})
.catch(error => {
console.error('Failed to initialize push notifications:', error);
});
// Export for use in other modules
export default pushManager;Error Handling
Common Errors
403 Forbidden: Origin not allowed
- Solution: Ensure your origin is whitelisted on the push notification service
400 Bad Request: Invalid subscription data
- Solution: Ensure subscription object contains valid
endpointandkeys
- Solution: Ensure subscription object contains valid
404 Not Found: Device ID not found (for unsubscribe)
- Solution: Verify the device ID exists
500 Internal Server Error: Server-side error
- Solution: Check server logs and contact support
Handling Subscription Errors
try {
await pushManager.subscribe();
} catch (error) {
if (error.message.includes('403')) {
console.error('Access denied. Check if your origin is whitelisted.');
} else if (error.message.includes('400')) {
console.error('Invalid subscription data.');
} else {
console.error('Subscription failed:', error);
}
}Best Practices
Request Permission at the Right Time: Don't request notification permission immediately on page load. Wait for user interaction or a meaningful moment.
Handle Permission States: Check
Notification.permissionbefore requesting permission.Persist Device ID: The library automatically stores the device ID in localStorage to maintain consistency across sessions.
Handle Service Worker Updates: Listen for service worker updates and handle them appropriately.
Test on HTTPS: Always test push notifications over HTTPS (or localhost for development).
Handle Subscription Expiration: Monitor subscription expiration and re-subscribe when needed.
Error Recovery: Implement retry logic for failed subscription attempts.
User Experience: Provide clear UI feedback about subscription status and allow users to easily unsubscribe.
Privacy: Only request push notification permission when it adds value to the user experience.
Cross-Browser Testing: Test your implementation across different browsers as push notification support varies.
Troubleshooting
Service Worker Not Registering
- Ensure the service worker file is accessible at the root path
- Check browser console for errors
- Verify HTTPS is enabled (or using localhost)
Subscription Fails
- Ensure request body matches expected format
- Check network tab for detailed error messages
- Verify your origin is whitelisted on the push notification service
Notifications Not Appearing
- Verify service worker is active
- Check browser notification settings
- Ensure notification permission is granted
- Verify payload format matches expected structure
Subscription Expired
- Monitor
expirationTimein subscription object - Re-subscribe before expiration
- Handle expiration gracefully in your UI
Production Considerations with PWAs and Netlify
When using this package in a PWA project (e.g., with vite-plugin-pwa) and deploying to Netlify, there are a few important considerations:
Custom Service Worker with PWA Plugin
- Some PWA plugins (like VitePWA) generate their own service worker by default.
- To ensure your push notification code remains in the service worker, use the
injectManifeststrategy. - Your service worker (
sw.js) should includeprecacheAndRoute(self.__WB_MANIFEST || [])so the plugin can inject asset precaching without overwriting your push logic.
Netlify Rewrites
Netlify’s SPA redirect rules can rewrite
/sw.jsrequests toindex.html.To prevent this, include a
_redirectsfile inpublic/:/sw.js /sw.js 200This ensures the service worker is served correctly and push notifications work in production.
Verification
- After deployment, confirm that visiting
/sw.jsshows your service worker code (not HTML). - Unregister old service workers in DevTools and refresh to ensure the new one with push logic is active.
- After deployment, confirm that visiting
Following these steps ensures that push notifications function correctly in a PWA deployed to Netlify while retaining offline caching and manifest features.
