Skip to content

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:

  1. HTTPS Required - Web push notifications require HTTPS (except for localhost)
  2. Service Worker - A service worker file is required at the root of your domain
  3. VAPID Keys - VAPID keys must be configured in your app settings (generated automatically)
  4. 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

  1. Log into your Tappd Dashboard
  2. Navigate to Settings > Apps
  3. Select your web app
  4. Go to Push Configuration > Web Push
  5. Enable Web Push
  6. Click Generate Keys to generate VAPID keys automatically
  7. 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):

javascript
// 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

javascript
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:

javascript
// 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:

javascript
// 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:

javascript
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:

javascript
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.

javascript
// Show slidedown prompt
await tappd.showPermissionPrompt('slidedown');

2. Bell Icon

A bell icon that users can click to subscribe.

javascript
// Show bell prompt
await tappd.showPermissionPrompt('bell');

3. Native Browser Prompt

The browser's native permission prompt.

javascript
// 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.

javascript
// Build your custom UI, then:
await tappd.subscribeToPush();

Sending Push Notifications

From Dashboard

  1. Navigate to Templates > Push Templates
  2. Create a new push template or select an existing one
  3. Configure the notification (title, body, icon, URL, etc.)
  4. Create a Journey with a push notification step
  5. Target the journey to specific customers or segments

From API

Use the Tappd Management API to send push notifications programmatically:

javascript
// 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

  1. Go to Settings > Apps > [Your App]
  2. Scroll to Web Push Configuration
  3. Click Test Web Push
  4. Select a customer and enter notification details
  5. Click Send Test Push

Test Programmatically

javascript
// 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 API

Service 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

javascript
// 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:

javascript
// 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:

  1. Ensure service worker is at the root of your domain (/sw.js)
  2. Check that HTTPS is enabled (required for production)
  3. Verify service worker file is accessible (visit https://yourdomain.com/sw.js in browser)
  4. Check browser console for errors

Permission Denied

Problem: User denies notification permission

Solutions:

  1. Respect user's choice - don't prompt repeatedly
  2. Explain the value of notifications before asking
  3. Allow users to enable notifications later from settings
  4. Use a custom UI to explain benefits before showing native prompt

Notifications Not Received

Problem: Subscribed but notifications not arriving

Solutions:

  1. Verify subscription status: await tappd.isSubscribed()
  2. Check that VAPID keys are configured in dashboard
  3. Ensure service worker is active and registered
  4. Check browser console for errors
  5. Verify user is identified before subscribing
  6. Check that push notification is sent from dashboard/API

Subscription Expired

Problem: Subscription becomes invalid

Solutions:

  1. Listen for subscription changes
  2. Re-subscribe when subscription expires
  3. Handle subscription errors gracefully
javascript
// 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 daily

Best Practices

  1. Identify users first - Push subscriptions require identified users
  2. Request permission at the right time - Ask when users understand the value
  3. Respect user choice - Don't repeatedly prompt if denied
  4. Provide clear opt-out - Make it easy for users to unsubscribe
  5. Test thoroughly - Test on different browsers and devices
  6. Handle errors gracefully - Not all browsers support push notifications
  7. Track subscription events - Track when users subscribe/unsubscribe
  8. 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

Released under the MIT License.