---
title: "Send web push with VAPID and an encrypted · Agent Wranglers"
url: https://agentwranglers.se/playbook/notifications/push-notifications/web-push-vapid
updated: 2026-10-20
licence: "All rights reserved"
---

# Send web push with VAPID and an encrypted payload

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Required
- Chapter: [Push notifications](https://agentwranglers.se/playbook/notifications/push-notifications)
- Rule: 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: 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 18.4 and later also accept declarative web push messages, which show without running a service worker.
- 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.

Example:

```js
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
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"]},
    )
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers notifications playbook: https://agentwranglers.se/playbook/notifications/push-notifications/web-push-vapid`.

- Previous: [Ask for permission after a clear action](https://agentwranglers.se/playbook/notifications/push-notifications/push-permission-in-context)
- Next: [Use the current APNs and FCM interfaces](https://agentwranglers.se/playbook/notifications/push-notifications/apns-fcm-current-apis)
- [Push notifications](https://agentwranglers.se/playbook/notifications/push-notifications)
