Push Configuration

Complete guide to push notification configuration, VAPID keys, Service Worker setup, permissions, and advanced features.
developer

Push Configuration

What is push configuration?

Push configuration defines how your website handles web push notifications, including Service Worker setup, VAPID keys, permission handling, and notification display. It follows this flow:

VAPID key → Service Worker registration → Permission request → Notification delivery

Benefits:

  • Real-time notifications — Send notifications even when users aren’t on your site
  • User engagement — Re-engage users with timely, relevant content
  • Cross-platform — Works on desktop and mobile browsers
  • Customizable — Control when and how notifications are shown
  • Analytics integration — Track notification performance and user behavior

Push notification types

  • Permission Requests: Ask users to allow notifications for initial setup and re-engagement to build notification audience.
  • Direct Notifications: Send immediate notifications for breaking news and alerts to enable real-time communication.
  • Scheduled Notifications: Send notifications at specific times for reminders and promotions to enable timed engagement.
  • Triggered Notifications: Send based on user actions like abandoned cart and welcome messages for contextual messaging.

Push configuration structure

  • key (string, required): VAPID public key - Server authentication for secure push delivery.
  • push_serviceworker (string, default: /sw.js): Service Worker path - Background script for notification handling.
  • serviceWorkerScope (string, auto-detected): Service Worker scope - Control which pages can receive notifications.
  • push_enable_subdomain_subscription (boolean, default: false): Subdomain subscription - Separate notification preferences per subdomain.
  • prompts (array, default: []): Modal prompts - Pre-permission dialogs to improve conversion and comply with browser requirements.

Basic push configuration

{
  "key": "BExxx...VAPID...",
  "push_serviceworker": "/sw.js",
  "serviceWorkerScope": "/",
  "push_enable_subdomain_subscription": false
}

Push configuration options

VAPID Key (key)

Purpose: VAPID (Voluntary Application Server Identification) public key enables secure push notification delivery by authenticating your server to browser push services.

Why it’s required:

  • Security: Prevents unauthorized servers from sending notifications to your users
  • Browser compliance: Chrome, Firefox, and Safari require VAPID for push notifications
  • User trust: Users know notifications come from verified, legitimate sources
  • Spam prevention: Blocks malicious actors from sending fake notifications

Requirements:

  • Length: Must be at least 85 characters
  • Format: Base64-encoded string
  • Security: Must match your server’s VAPID private key
  • HTTPS: Only works over HTTPS connections

Examples:

{ "key": "BExxx...VAPID...PUBLIC...KEY..." }
{ "key": "BEl62iUYgUivxIkv69yViEuiBIa40HI8..." }

Generation: VAPID keys are generated using your server-side application. The public key is used in the SDK configuration.

Validation: SDK validates key length and availability before registering Service Worker.

Service Worker Path (push_serviceworker)

Purpose: Defines the location of your Service Worker file that handles push notifications in the background, even when your website is closed.

Why it’s important:

  • Background processing: Service Worker runs independently of your website
  • Notification delivery: Receives and displays notifications when site is closed
  • Offline capability: Can cache and queue notifications for later delivery
  • Performance: Lightweight background script doesn’t impact site performance

Supported paths:

  • Root path: /sw.js - Controls entire website
  • Subdirectory: /js/sw.js - Controls specific sections
  • Custom path: /custom-service-worker.js - Branded naming
  • CDN path: https://cdn.example.com/sw.js - External hosting

Examples:

{ "push_serviceworker": "/sw.js" }
{ "push_serviceworker": "/js/service-worker.js" }
{ "push_serviceworker": "/custom-sw.js" }

Fallback options: SDK also checks for customsw, pushserviceworker, and service_worker_path if push_serviceworker is not provided.

Requirements: Service Worker file must exist and be accessible via HTTPS.

Service Worker Scope (serviceWorkerScope)

Purpose: Controls which parts of your website the Service Worker can manage, providing security and performance benefits.

Why scope matters:

  • Security: Prevents Service Worker from accessing unauthorized parts of your site
  • Performance: Smaller scope means faster registration and less memory usage
  • Multi-app architecture: Different Service Workers for different app sections
  • Isolation: Prevents conflicts between different parts of your application

Auto-detection: If not specified, SDK automatically detects scope from Service Worker path:

  • /sw.js → scope: / (entire site)
  • /js/sw.js → scope: /js/ (only JS directory)
  • /custom/sw.js → scope: /custom/ (only custom directory)

Examples:

{ "serviceWorkerScope": "/" }           // Entire website
{ "serviceWorkerScope": "/app/" }       // Only /app/ section
{ "serviceWorkerScope": "/dashboard/" } // Only dashboard area

Use cases:

  • Root scope (/): Service Worker controls entire site - best for simple websites
  • Limited scope (/app/): Service Worker only controls specific sections - better for complex apps
  • Multi-app: Different Service Workers for different app sections - enterprise applications

Subdomain Subscription (push_enable_subdomain_subscription)

Purpose: Creates separate push notification subscriptions for each subdomain, enabling targeted messaging and better user experience.

Why use subdomain subscriptions:

  • Brand separation: Different notifications for different brands (brand1.example.com vs brand2.example.com)
  • User preferences: Users can opt-in to notifications from specific subdomains only
  • A/B testing: Test different notification strategies per subdomain
  • Compliance: Meet regional requirements for different markets
  • Analytics: Track notification performance per subdomain separately

Behavior:

  • false (default): Single subscription for entire domain - simpler setup
  • true: Separate subscriptions per subdomain - more granular control

Storage keys:

  • Single domain: push - one subscription for all subdomains
  • Subdomain enabled: psh<hash> where hash is checksum of hostname - unique per subdomain

Examples:

{ "push_enable_subdomain_subscription": false }  // Single subscription for all
{ "push_enable_subdomain_subscription": true }   // Separate per subdomain

Use cases:

  • Multi-tenant apps: Different notifications for different tenants
  • A/B testing: Different notification strategies per subdomain
  • Brand separation: Separate notification preferences per brand
  • Regional compliance: Different notification rules per region

Purpose: Custom modal dialogs shown before the native browser permission request to improve conversion rates and comply with browser requirements.

Why modal prompts are essential:

  • Browser compliance: Chrome requires user gesture interaction before showing native permission prompt (prevents violations)
  • Higher conversion: 3-5x better permission acceptance rates compared to direct native prompts
  • User education: Explain the value of notifications before asking for permission
  • Better UX: Custom branding, messaging, and design that matches your site
  • Targeted messaging: Show different prompts to different user segments
  • A/B testing: Test different approaches to find what works best

Browser requirements:

  • Chrome: Requires user gesture (click, scroll, etc.) before native prompt
  • Firefox: More lenient but still benefits from user education
  • Safari: Strict about permission timing and user context

Structure: Array of modal configuration objects with triggers and filters.

Examples:

{
  "prompts": [
    {
      "id": "push-permission-modal",
      "template": "push-permission-template",
      "triggers": [{ "type": "pageView" }],
      "filters": [
        { "c": "{{data.user_segment}}", "o": "eq", "m": "engaged" }
      ],
      "options": {
        "theme": "light",
        "animation": "slide-up"
      }
    }
  ]
}

Benefits:

  • Higher conversion: Explain value before requesting permission
  • Better UX: Custom messaging and branding
  • Targeted prompts: Show only to relevant users
  • A/B testing: Test different prompt strategies
  • Compliance: Meet browser requirements for user gesture

Integration: Uses same modal system as regular modals with group: 'push' for identification.

Push configuration examples

For comprehensive push configuration examples including basic setup, advanced features, modal prompts, e-commerce integration, and multi-brand setups, see Push configuration examples.

Push notification flow

Registration process

  1. VAPID validation - Check key length and format
  2. Service Worker registration - Register SW with specified path and scope
  3. Permission check - Check current notification permission status
  4. Subscription management - Handle existing subscriptions and repairs
  5. Event binding - Set up push event listeners

Permission states

  • granted: User allowed notifications - Subscribe to push notifications.
  • denied: User blocked notifications - Show alternative engagement options.
  • prompt: Permission not requested yet - Show custom prompt or native prompt.
  • closed: User dismissed prompt - Retry with different strategy.
  • auto-block: Browser auto-blocked - Use alternative engagement methods.

Error handling

// SDK automatically tracks push errors
Hood('on', 'pushError', (error) => {
  console.log('Push error:', error);
  // Handle specific error types
});

Common error scenarios:

  • Invalid VAPID key
  • Service Worker registration failure
  • Permission denied
  • Network connectivity issues
  • Browser compatibility problems

Integration with other features

Push + Modals

Push prompts can be integrated with the modal system:

{
  "push_config": {
    "key": "BExxx...VAPID...",
    "push_serviceworker": "/sw.js",
    "prompts": [
      {
        "id": "push-permission-modal",
        "template": "push-permission-template",
        "triggers": [{ "type": "pageView" }],
        "filters": [
          { "c": "{{data.push_eligible}}", "o": "eq", "m": "true" }
        ],
        "options": {
          "theme": "light",
          "animation": "slide-up",
          "limit_type": "session",
          "limit_count": 1
        }
      }
    ]
  }
}

Push + Analytics

Track push notification performance:

// Track permission requests
Hood('trackEvent', 'push_permission_requested', {
  prompt_type: 'modal',
  user_segment: 'premium'
});

// Track permission granted
Hood('trackEvent', 'push_permission_granted', {
  method: 'native_prompt',
  time_to_grant: 5000
});

Push + User Properties

Use user data for targeted push prompts:

{
  "push_config": {
    "key": "BExxx...VAPID...",
    "push_serviceworker": "/sw.js",
    "prompts": [
      {
        "id": "personalized-push-modal",
        "template": "personalized-push-template",
        "triggers": [{ "type": "pageView" }],
        "filters": [
          { "c": "{{data.subscription_tier}}", "o": "eq", "m": "premium" },
          { "c": "{{data.push_opted_out}}", "o": "neq", "m": "true" }
        ]
      }
    ]
  }
}

Best practices

Performance optimization

Info

Performance Tips

  • Early registration: Register Service Worker as early as possible
  • Efficient SW: Keep Service Worker file lightweight
  • Proper scope: Use appropriate Service Worker scope
  • Error handling: Implement robust error handling for registration failures
  • Fallback strategies: Have alternative engagement methods for blocked users

User experience

  • Clear value proposition: Explain benefits before requesting permission
  • Timing: Request permission at optimal moments (after engagement)
  • Frequency: Don’t spam users with permission requests
  • Custom prompts: Use modal prompts to improve conversion rates
  • Respect user choice: Honor permission decisions

Security considerations

  • HTTPS only: Push notifications only work over HTTPS
  • VAPID security: Keep VAPID private key secure on server
  • Scope limitations: Use appropriate Service Worker scope
  • Content validation: Validate notification content before sending

Troubleshooting

If push notifications aren’t working as expected, try these solutions:

Service Worker not registering?

  1. Verify the Service Worker file exists at the specified path
  2. Check that the file is accessible over HTTPS (not HTTP)
  3. Inspect browser console for registration errors
  4. Test the path directly in your browser (e.g., https://yoursite.com/sw.js)
  5. Ensure the Service Worker scope is correct for your domain structure

VAPID key invalid?

  1. Verify the key is at least 85 characters long
  2. Check that it’s properly base64-encoded
  3. Ensure you’re using the public key (not the private key)
  4. Confirm the key matches your server’s VAPID configuration
  5. Test with a fresh key pair if issues persist

Permission denied by user?

  1. Respect the user’s choice - don’t repeatedly ask
  2. Provide alternative engagement methods (email, SMS, in-app messages)
  3. Explain the value of notifications before requesting permission
  4. Consider using modal prompts to improve conversion rates
  5. Track denial reasons to improve your permission strategy

Notifications not showing?

  1. Check that the Service Worker is active: navigator.serviceWorker.getRegistrations()
  2. Verify notification permission is granted: Notification.permission === 'granted'
  3. Test with a simple notification to isolate the issue
  4. Check browser console for push event errors
  5. Ensure the Service Worker is properly handling push events

Cross-domain or scope issues?

  1. Verify the Service Worker scope matches your domain structure
  2. Check that the Service Worker path is correct for your setup
  3. Ensure HTTPS is properly configured (including certificates)
  4. Test with root scope (/) first, then narrow down if needed
  5. Review browser DevTools → Application → Service Workers for status

Debug mode

Enable debug logging for push notifications:

// Enable debug mode
Hood('config', 'debug', true);

// Check push status
Hood('pushStatus', (status) => {
  console.log('Push status:', status);
});

Testing

Test push configuration in development:

// Test Service Worker registration
navigator.serviceWorker.getRegistrations().then(registrations => {
  console.log('SW registrations:', registrations);
});

// Test permission status
navigator.permissions.query({name: 'notifications'}).then(result => {
  console.log('Permission status:', result.state);
});