Web Push Notifications
Set up web push notifications with the Tappd Web SDK to send push notifications to users' browsers.
Overview
The Tappd Web SDK supports native web push notifications using the Web Push API. This allows you to send push notifications to users even when they're not actively browsing your website.
Prerequisites
Before setting up web push notifications:
- HTTPS Required - Web push notifications require HTTPS (except for localhost)
- Service Worker - A service worker file is required at the root of your domain
- VAPID Keys - VAPID keys must be configured in your app settings (generated automatically)
- User Identification - Users must be identified before subscribing to push notifications
Browser Support
Web push notifications are supported in:
- ✅ Chrome (Desktop & Android)
- ✅ Firefox (Desktop & Android)
- ✅ Edge
- ✅ Safari 16.4+ (macOS & iOS)
- ✅ Opera
Note: Safari 16.4+ uses the standard Web Push API with VAPID keys. Older Safari versions (< 16.4) are not supported.
Step 1: Configure Web Push in Dashboard
- Log into your Tappd Dashboard
- Navigate to Settings > Apps
- Select your web app
- Go to Push Configuration > Web Push
- Enable Web Push
- Click Generate Keys to generate VAPID keys automatically
- Optionally configure:
- Default Icon URL - Icon shown in notifications
- Site Name - Display name for your website
- Permission Prompt Settings - Customize how users are prompted
Safari Certificate (Optional)
For legacy Safari support (< 16.4), you can optionally upload a p12 certificate:
- Website Push ID - Your Apple Website Push ID (e.g.,
web.com.example.website) - P12 Certificate File - Certificate file from Apple Developer account
- Certificate Password - Password for the certificate (if encrypted)
Note: Safari 16.4+ uses VAPID keys (same as Chrome/Firefox), so p12 certificates are only needed for older Safari versions.
Step 2: Create Service Worker
Create a service worker file at the root of your domain (e.g., /sw.js):
// sw.js
self.addEventListener('push', function(event) {
const data = event.data ? event.data.json() : {};
const options = {
body: data.body || '',
icon: data.icon || '/icon-192x192.png',
badge: data.badge || '/badge-72x72.png',
image: data.image,
data: data.data || {},
requireInteraction: data.requireInteraction || false,
tag: data.tag,
renotify: data.renotify || false,
silent: data.silent || false,
timestamp: data.timestamp || Date.now(),
vibrate: data.vibrate || [200, 100, 200],
actions: data.actions || []
};
event.waitUntil(
self.registration.showNotification(data.title || 'Notification', options)
);
});
self.addEventListener('notificationclick', function(event) {
event.notification.close();
// Handle notification click
const url = event.notification.data.url || '/';
event.waitUntil(
clients.matchAll({ type: 'window', includeUncontrolled: true }).then(function(clientList) {
// Check if there's already a window/tab open with the target URL
for (let i = 0; i < clientList.length; i++) {
const client = clientList[i];
if (client.url === url && 'focus' in client) {
return client.focus();
}
}
// If not, open a new window/tab
if (clients.openWindow) {
return clients.openWindow(url);
}
})
);
});Make sure your service worker is accessible at the root of your domain (e.g., https://yourdomain.com/sw.js).
Step 3: Subscribe to Push Notifications
Basic Subscription
import { TappdSDK } from '@tappd/web-sdk';
const tappd = new TappdSDK({
appId: 'YOUR_APP_ID',
apiUrl: 'https://sdk.gotappd.com/api/v1/sdk'
});
// Identify user first (required)
await tappd.identify({
external_id: 'user_123',
email: 'john@example.com',
name: 'John Doe'
});
// Subscribe to push notifications
try {
const subscription = await tappd.subscribeToPush();
console.log('Successfully subscribed to push notifications');
} catch (error) {
console.error('Failed to subscribe:', error);
}Check Subscription Status
Before subscribing, check if the user is already subscribed:
// Check if user is subscribed
const isSubscribed = await tappd.isSubscribed();
if (isSubscribed) {
console.log('User is already subscribed');
} else {
// Prompt user to subscribe
await tappd.subscribeToPush();
}Custom Permission Prompt
You can show a custom permission prompt before subscribing:
// Show native browser prompt
await tappd.showPermissionPrompt('native');
// Or use custom UI before subscribing
function showCustomPrompt() {
// Show your custom UI
if (userClickedAllow) {
await tappd.subscribeToPush();
}
}Complete Setup Example
Here's a complete example with error handling:
import { TappdSDK } from '@tappd/web-sdk';
const tappd = new TappdSDK({
appId: 'YOUR_APP_ID',
apiUrl: 'https://sdk.gotappd.com/api/v1/sdk'
});
async function setupWebPush() {
try {
// Check browser support
if (!('serviceWorker' in navigator) || !('PushManager' in window)) {
console.log('Push notifications are not supported in this browser');
return;
}
// Identify user first (required)
await tappd.identify({
external_id: 'user_123',
email: 'john@example.com'
});
// Check if already subscribed
const isSubscribed = await tappd.isSubscribed();
if (isSubscribed) {
console.log('Already subscribed to push notifications');
return;
}
// Subscribe to push notifications
const subscription = await tappd.subscribeToPush();
console.log('Successfully subscribed to push notifications');
// Track subscription event
await tappd.track('push_notification.subscribed', {
endpoint: subscription.endpoint
});
} catch (error) {
if (error.message.includes('permission denied')) {
console.log('User denied push notification permission');
} else if (error.message.includes('not supported')) {
console.log('Push notifications are not supported');
} else {
console.error('Failed to set up push notifications:', error);
}
}
}
// Call when user clicks "Enable Notifications" button
document.getElementById('enable-notifications').addEventListener('click', setupWebPush);Unsubscribe from Push Notifications
Allow users to unsubscribe:
async function unsubscribeFromPush() {
try {
await tappd.unsubscribeFromPush();
console.log('Successfully unsubscribed from push notifications');
// Track unsubscribe event
await tappd.track('push_notification.unsubscribed');
} catch (error) {
console.error('Failed to unsubscribe:', error);
}
}
// Call when user clicks "Disable Notifications" button
document.getElementById('disable-notifications').addEventListener('click', unsubscribeFromPush);Permission Prompt Types
The SDK supports different permission prompt types configured in your app settings:
1. Slidedown (Default)
A customizable slide-down banner that appears at the top of the page.
// Show slidedown prompt
await tappd.showPermissionPrompt('slidedown');2. Bell Icon
A bell icon that users can click to subscribe.
// Show bell prompt
await tappd.showPermissionPrompt('bell');3. Native Browser Prompt
The browser's native permission prompt.
// Show native prompt (triggers browser's permission dialog)
await tappd.showPermissionPrompt('native');4. Custom UI
Build your own custom UI and call subscribeToPush() when the user clicks allow.
// Build your custom UI, then:
await tappd.subscribeToPush();Sending Push Notifications
From Dashboard
- Navigate to Templates > Push Templates
- Create a new push template or select an existing one
- Configure the notification (title, body, icon, URL, etc.)
- Create a Journey with a push notification step
- Target the journey to specific customers or segments
From API
Use the Tappd Management API to send push notifications programmatically:
// Send push notification via API
const response = await fetch('/api/v1/workspaces/:workspaceId/push/send', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY'
},
body: JSON.stringify({
customerId: 'customer_id',
appId: 'app_id',
notification: {
title: 'Hello!',
body: 'This is a test notification',
url: 'https://example.com',
icon: 'https://example.com/icon.png'
}
})
});Testing Push Notifications
Test from Dashboard
- Go to Settings > Apps > [Your App]
- Scroll to Web Push Configuration
- Click Test Web Push
- Select a customer and enter notification details
- Click Send Test Push
Test Programmatically
// Check subscription status
const isSubscribed = await tappd.isSubscribed();
console.log('Subscribed:', isSubscribed);
// Subscribe if not already subscribed
if (!isSubscribed) {
await tappd.subscribeToPush();
}
// Then send a test notification from the dashboard or APIService Worker Best Practices
1. Keep Service Worker Simple
Keep your service worker focused on push notifications. Avoid heavy operations that could slow down message handling.
2. Handle Offline Scenarios
// sw.js
self.addEventListener('push', function(event) {
const data = event.data ? event.data.json() : {};
// Always show notification, even if offline
event.waitUntil(
self.registration.showNotification(data.title || 'Notification', {
body: data.body || '',
icon: data.icon || '/icon-192x192.png',
data: data.data || {}
})
);
});3. Handle Notification Clicks
Always handle notification clicks to improve user experience:
// sw.js
self.addEventListener('notificationclick', function(event) {
event.notification.close();
const url = event.notification.data.url || '/';
event.waitUntil(clients.openWindow(url));
});Troubleshooting
Service Worker Not Registering
Problem: Service worker fails to register
Solutions:
- Ensure service worker is at the root of your domain (
/sw.js) - Check that HTTPS is enabled (required for production)
- Verify service worker file is accessible (visit
https://yourdomain.com/sw.jsin browser) - Check browser console for errors
Permission Denied
Problem: User denies notification permission
Solutions:
- Respect user's choice - don't prompt repeatedly
- Explain the value of notifications before asking
- Allow users to enable notifications later from settings
- Use a custom UI to explain benefits before showing native prompt
Notifications Not Received
Problem: Subscribed but notifications not arriving
Solutions:
- Verify subscription status:
await tappd.isSubscribed() - Check that VAPID keys are configured in dashboard
- Ensure service worker is active and registered
- Check browser console for errors
- Verify user is identified before subscribing
- Check that push notification is sent from dashboard/API
Subscription Expired
Problem: Subscription becomes invalid
Solutions:
- Listen for subscription changes
- Re-subscribe when subscription expires
- Handle subscription errors gracefully
// Check subscription periodically
setInterval(async () => {
const isSubscribed = await tappd.isSubscribed();
if (!isSubscribed) {
// Re-subscribe if needed
try {
await tappd.subscribeToPush();
} catch (error) {
console.error('Re-subscription failed:', error);
}
}
}, 24 * 60 * 60 * 1000); // Check dailyBest Practices
- Identify users first - Push subscriptions require identified users
- Request permission at the right time - Ask when users understand the value
- Respect user choice - Don't repeatedly prompt if denied
- Provide clear opt-out - Make it easy for users to unsubscribe
- Test thoroughly - Test on different browsers and devices
- Handle errors gracefully - Not all browsers support push notifications
- Track subscription events - Track when users subscribe/unsubscribe
- Keep service worker lightweight - Avoid heavy operations in service worker
Browser-Specific Notes
Chrome/Edge
- Full support for Web Push API
- Uses VAPID keys (automatically configured)
- Supports notification actions and badges
Firefox
- Full support for Web Push API
- Uses VAPID keys (automatically configured)
- Good support for notification features
Safari (16.4+)
- Supports standard Web Push API
- Uses VAPID keys (same as Chrome/Firefox)
- Works on macOS and iOS (iOS 16.4+)
Safari (< 16.4)
- Not supported (requires p12 certificate which is complex)
- Recommend users upgrade to Safari 16.4+
Next Steps
- API Reference - Complete SDK method documentation
- Configuration - SDK configuration options
- Examples - Complete code examples
- Journey API Triggers - Trigger journeys with push notifications
