Agent Wranglers

NTF-10Recommended

Send web push with VAPID and an encrypted payload

Send web push through each subscription's push service with VAPID keys (RFC 8292) and an encrypted payload (RFC 8291). Never build your own polling or socket for background alerts.

How to do it

Make one VAPID key pair and keep the private key in the secret store. Put a mailto: or https: contact in the sub claim, so the push service can reach you. Send with a maintained library, such as web-push for Node.js, pywebpush for Python or webpush-go. It encrypts the payload with the keys in the subscription and signs the request. Store each subscription's endpoint and keys against the user, with a unique endpoint. A Topic value holds at most 32 characters from the URL-safe base64 alphabet. Safari also accepts declarative web push messages, which show without running a service worker. That works from Safari 18.4 on iPhone and iPad for web apps on the Home Screen, and from Safari 18.5 on macOS. The private key belongs where Keep secrets in a secrets store says.

Examples

JavaScript example

import webpush from 'web-push';

webpush.setVapidDetails('mailto:push@example.com', process.env.VAPID_PUBLIC_KEY, process.env.VAPID_PRIVATE_KEY);

export const sendPush = (subscription, message) =>
  webpush.sendNotification(subscription, JSON.stringify(message), { TTL: 3600, urgency: 'normal', topic: message.topic });

Python example

import json
import os
from pywebpush import webpush

def send_push(subscription: dict, message: dict):
    return webpush(
        subscription_info=subscription,
        data=json.dumps(message),
        vapid_private_key=os.environ["VAPID_PRIVATE_KEY"],
        vapid_claims={"sub": "mailto:push@example.com"},
        ttl=3600,
        headers={"Urgency": "normal", "Topic": message["topic"]},
    )

How to check

Send a test push to a staging subscription. The push service answers 201, and the notification shows on the device with the payload text.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/notifications/web-push/web-push-vapid">Agent Wranglers notifications playbook</a>. In code you write, add a comment next to it with the same link.