Web Push setup
VAPID keys, the service worker, and the HTTPS requirement explained.
Web push has three moving parts you have to get right: VAPID keys, a service worker served from your origin, and HTTPS. This page covers each.
Registration UI
The styled copy-in toggle exposes the browser states users need to understand. It uses fixture state here, so it never opens a permission prompt or calls an API.
VAPID keys
VAPID (Voluntary Application Server Identification, RFC 8292) is how a push service knows your server is allowed to send to a subscription. You need one key pair for your whole application.
import { generateVapidKeys } from "@better-push/core/providers/web-push";
const { publicKey, privateKey } = generateVapidKeys();- The private key stays on your server and is passed to
webPush({ vapid }). - The public key is passed to
webPush({ vapid })and handed to the browser client asapplicationServerKey. - The subject must be a
mailto:orhttps:URL - a contact the push service can reach if there is a problem.
webPush({
vapid: {
subject: "mailto:you@example.com",
publicKey: process.env.VAPID_PUBLIC_KEY!,
privateKey: process.env.VAPID_PRIVATE_KEY!,
},
ttl: 86400, // optional, seconds a push service holds a message; default 1 day
});Rotating VAPID keys invalidates every existing subscription, so treat them as long-lived secrets.
The service worker
A push notification is delivered to a service worker, not to a page - that
is what lets a notification arrive when your site is not open. Service workers
cannot import npm modules without a build step, so better-push ships the worker
as a static file for you to copy to public/sw.js. The exact source is also
exported:
import { SERVICE_WORKER_SOURCE } from "@better-push/core/client/sw";The worker handles two events:
push- reads the JSON payload and callsshowNotification(title, { body, data }).notificationclick- focuses an existing window if there is one, else opensdata.url(or/).
The payload your worker receives is the JSON string
{ notificationId, title, body, data } produced by push.notify().
The HTTPS requirement
Service workers and the Push API require a secure context. The one exception
is http://localhost, which browsers treat as secure - so local development
needs no certificates.
Everywhere else, including a phone pointed at your machine's LAN IP, you need real HTTPS. This is why testing on devices means deploying to an HTTPS URL. See Testing On Devices.
How sending maps to the push protocol
When you call push.notify(), the web push provider:
- Parses each device's stored subscription JSON.
- Encrypts the payload per RFC 8291 and signs the request with your VAPID keys
(via the mature
web-pushpackage - better-push does not reimplement the crypto). - Sends to each subscription's endpoint with bounded concurrency.
- Maps the push service's response:
404/410mean the subscription is gone, so the device is disabled;413,429, and other errors are recorded on the delivery row without disabling the device.