Skip to Content
AI Powered Docs! 🤖 These docs are translated with AI, so keep an eye out for minor quirks. We're always improving!

Web Push Implementation Guide

Overview

This guide provides complete documentation for implementing Web Push notifications using the Metrix Web SDK. Web Push enables you to send browser notifications to users who have granted permission.

Key Concepts

User Association

  • Anonymous Users: If authorizeUser is not called before permission is granted, an anonymous user is created in Metrix for each device that grants push notification permission.
  • Identified Users: Call authorizeUser before requesting permission to associate the subscription with an identified user.

Subscription Lifecycle

  1. Initialize SDK with push configuration including VAPID public key
  2. Configure Service Worker (either Metrix-provided or existing)
  3. Request Permission using one of four available methods
  4. Receive Notifications through Metrix dashboard

Prerequisites

  • HTTPS: Required for production (localhost allowed for development)
  • Modern Browser: Chrome 50+, Firefox 44+, Edge 15+, Safari 16+
  • Service Worker Support: Browser must support Service Workers and Push API
  • VAPID Public Key: Provided by Metrix

You can use the following sample implementations to add Web Push to your website:

Implementation Steps

Step 1: Service Worker Setup

  1. Download metrix-sw.js
  2. Place at your website root (same directory as index.html)
  3. File must be accessible at: https://YOUR_DOMAIN/metrix-sw.js

When hasSW: false (default), the SDK automatically registers this worker.

Option B: Use Existing Service Worker

If you already have a service worker:

// Add to your service worker file importScripts('https://cdn.metrix.ir/sdk/web/metrixweb-sw.js');

Then initialize with hasSW: true:

init('APP_ID', 'API_KEY', { push: { enabled: true, publicKey: 'YOUR_VAPID_PUBLIC_KEY', hasSW: true, }, });

Step 2: SDK Initialization

import { init } from '@metrixorg/websdk'; init('APP_ID', 'API_KEY', { push: { enabled: true, publicKey: 'YOUR_VAPID_PUBLIC_KEY', hasSW: false, // Set to true if using existing service worker showBell: true, // Optional: Display bell icon showBackdrop: false, // Optional: Show permission dialog on init popUpText: 'Enable notifications', // Custom bell popup text position: 'bottom-right', // Bell position }, });

Step 3: Request User Permission

Method 1: subscribePush() - Programmatic Request

import { subscribePush } from '@metrixorg/websdk'; // Call from a user action (button click, etc.) async function enableNotifications() { try { const state = await subscribePush(); if (state === 'subscribed') { console.log('✓ Push notifications enabled'); } else if (state === 'blocked') { console.log('✗ User blocked notifications'); } else if (state === 'closed') { console.log('○ Permission dialog closed'); } } catch (error) { console.error('Failed to enable push:', error); } } // Attach to button or user action document.getElementById('enable-btn').addEventListener('click', enableNotifications);

Method 2: Automatic Backdrop on Init

init('APP_ID', 'API_KEY', { push: { enabled: true, publicKey: 'YOUR_VAPID_PUBLIC_KEY', showBackdrop: true, backdropDelay: 2000, // 2 second delay backdropText: 'Enable notifications to stay updated', }, });

Method 3: Manual Backdrop Control

import { openPushConfirmBackdrop } from '@metrixorg/websdk'; async function showPermissionDialog() { const state = await openPushConfirmBackdrop({ backdropText: 'Get important updates', backdropDelay: 500, }); console.log('User decision:', state); } // Show dialog after user interaction document.getElementById('settings-btn').addEventListener('click', showPermissionDialog);

Method 4: Bell Icon

init('APP_ID', 'API_KEY', { push: { enabled: true, publicKey: 'YOUR_VAPID_PUBLIC_KEY', showBell: true, popUpText: 'Click to enable notifications', position: 'bottom-right', // or top-left, top-right, bottom-left }, });

Users click the bell to initiate the permission flow.

Response States

All permission methods return a ConfirmPushState:

type ConfirmPushState = 'subscribed' | 'blocked' | 'closed';
StateMeaning
subscribedUser granted permission, subscription created
blockedBrowser permission denied or user blocked
closedDialog closed without user action

API Reference

Exported Functions

subscribePush()

Request notification permission from user interaction.

subscribePush(): Promise<ConfirmPushState>

Returns: Promise that resolves with user’s decision

Usage:

const state = await subscribePush();

openPushConfirmBackdrop(config)

Display permission dialog manually.

openPushConfirmBackdrop(config: { backdropText: string; backdropDelay?: number; }): Promise<ConfirmPushState>

Parameters:

  • backdropText (required): Dialog message text
  • backdropDelay (optional): Delay in milliseconds before showing

Usage:

const state = await openPushConfirmBackdrop({ backdropText: 'Enable notifications', backdropDelay: 1000, });

onPushStateResolved()

Wait for permission flow completion from any method.

onPushStateResolved(): Promise<ConfirmPushState>

Returns: Promise resolving with final permission state

Usage:

const finalState = await onPushStateResolved();

notificationPermissionState()

Check current browser permission state.

notificationPermissionState(): NotificationPermission | undefined

Returns: 'default' | 'granted' | 'denied' | undefined

Usage:

const permission = notificationPermissionState(); if (permission === 'granted') { console.log('Already enabled'); }

getPushSubscription()

Get current push subscription details.

getPushSubscription(): Promise<PushSubscriptionJSON | undefined>

Returns: Push subscription object or undefined

Usage:

const subscription = await getPushSubscription(); if (subscription) { console.log('Endpoint:', subscription.endpoint); }

Configuration Options

interface PushConfig { enabled: boolean; // Enable push (required) publicKey: string; // VAPID public key (required) hasSW?: boolean; // Existing service worker? (default: false) showBell?: boolean; // Show bell icon? (default: false) showBackdrop?: boolean; // Show backdrop on init? (default: false) backdropText?: string; // Backdrop message text backdropDelay?: number; // Backdrop delay in ms popUpText?: string; // Bell popup text position?: string; // Bell position (top-left, top-right, bottom-left, bottom-right) }

Complete Example

import { init, authorizeUser, subscribePush, notificationPermissionState, getPushSubscription, } from '@metrixorg/websdk'; // Initialize SDK init('APP_ID', 'API_KEY', { push: { enabled: true, publicKey: 'YOUR_VAPID_PUBLIC_KEY', hasSW: false, }, }); // Authorize user (optional but recommended) authorizeUser('user@example.com'); // Add permission request button document.getElementById('notify-btn').addEventListener('click', async () => { const permission = notificationPermissionState(); // Skip if already granted or denied if (permission === 'granted') { alert('Notifications already enabled'); return; } if (permission === 'denied') { alert('Enable notifications in browser settings'); return; } // Request permission try { const state = await subscribePush(); if (state === 'subscribed') { const sub = await getPushSubscription(); console.log('Subscribed:', sub?.endpoint); alert('✓ Notifications enabled'); } else if (state === 'blocked') { alert('Notifications blocked by browser'); } else { alert('Permission request cancelled'); } } catch (error) { console.error('Push error:', error); alert('Failed to enable notifications'); } });

Advanced Patterns

Delayed Permission Request

Request permission after user engagement:

import { init, openPushConfirmBackdrop } from '@metrixorg/websdk'; init('APP_ID', 'API_KEY', { push: { enabled: true, publicKey: 'YOUR_VAPID_PUBLIC_KEY', showBackdrop: false, // Don't show immediately }, }); // Show after 5 seconds of user interaction let hasInteracted = false; document.addEventListener('click', () => { if (!hasInteracted) { hasInteracted = true; setTimeout(() => { openPushConfirmBackdrop({ backdropText: 'Stay updated with notifications', backdropDelay: 500, }); }, 5000); } });

Conditional Permission Request

Request based on user action:

document.getElementById('checkout-btn').addEventListener('click', async () => { // Complete checkout... const permission = notificationPermissionState(); if (permission !== 'denied' && permission !== 'granted') { const state = await subscribePush(); if (state === 'subscribed') { console.log('User subscribed to order updates'); } } });

Combined Bell + Manual Permission

Allow multiple ways to request:

init('APP_ID', 'API_KEY', { push: { enabled: true, publicKey: 'YOUR_VAPID_PUBLIC_KEY', showBell: true, popUpText: 'Enable notifications', position: 'bottom-right', }, }); // Also add custom button document.getElementById('custom-notify-btn').addEventListener('click', subscribePush);

Troubleshooting

Service Worker Issues

Problem: Service worker not found

  • Solution: Ensure metrix-sw.js is at domain root, accessible via https://YOUR_DOMAIN/metrix-sw.js

Problem: “Service worker is not for Metrix”

  • Solution: Set hasSW: true and verify importScripts() is in your service worker

Permission Issues

Problem: Permission always denied

  • Solution: Check publicKey is correct VAPID key (not private key)

Problem: Permission prompt not appearing

  • Solution: Call subscribePush() from user interaction (click, tap, etc.)

Problem: Push not initializing

  • Solution: Verify enabled: true and publicKey are provided in config

Browser Support

Problem: “Push notification is not supported”

  • Solution: Use modern browser (Chrome 50+, Firefox 44+, Edge 15+, Safari 16+)

Problem: HTTPS required error

  • Solution: Use HTTPS in production, localhost allowed for development

Best Practices

  1. Timing: Request permission after user engagement, not on page load
  2. Context: Explain benefits before requesting permission
  3. User Identification: Call authorizeUser() before requesting permission
  4. Error Handling: Always handle rejected promises
  5. Fallback: Don’t require push; make it optional
  6. Testing: Use HTTPS or localhost with proper VAPID keys
  7. Privacy: Respect user choice; don’t re-prompt after denial
  8. Monitoring: Log permission states for analytics

Debugging

Enable logging to debug issues:

// Check push status const permission = notificationPermissionState(); console.log('Push initialized:', permission !== undefined); console.log('Permission:', permission); // Check subscription getPushSubscription().then(sub => { console.log('Subscription:', sub?.endpoint ? 'Active' : 'None'); }); // Monitor flow onPushStateResolved().then(state => { console.log('Final state:', state); });

Support

For issues or questions:

  • Review browser console for errors
  • Check that HTTPS/localhost is used
  • Verify VAPID public key is correct
  • Ensure service worker file is accessible
  • Confirm browser supports Push API