web-push

Node.js library for sending Web Push notifications with VAPID and payload encryption

Library
npm
v3.6.7
3,566 stars
Mozilla Public License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
70 /100 Good
Development Activity 68
Maintenance 44
Community 68
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
75 /100 Good
Architecture 76
Code Quality 78
Innovation 74
Learning Curve 72

web-push is a Node.js library that implements the Web Push Protocol and its accompanying Message Encryption spec, letting an application server send push messages to a subscribed browser without running its own push infrastructure. It handles VAPID key generation and signing, per-message payload encryption (aes128gcm and the legacy aesgcm scheme), and the raw HTTPS request to whichever push service (FCM, Mozilla, or another vendor endpoint) owns the subscription.

Beyond the JS API, the package ships a web-push CLI for generating VAPID key pairs and firing test notifications from the command line, which makes it a common first stop for teams wiring up browser push notifications on top of the standard Push API and Notifications API.

What You Get

  • sendNotification(subscription, payload, options) — encrypts an optional payload and POSTs it to the subscription’s push service endpoint, returning a Promise
  • generateVAPIDKeys() / setVapidDetails() — VAPID key pair generation and application-server identification for authenticating push requests
  • Built-in payload encryption implementing the Message Encryption for Web Push spec (aes128gcm, with legacy aesgcm support)
  • A web-push CLI binary for generating VAPID keys and sending test notifications without writing code
  • Support for proxy, custom HTTPS agent, TTL, urgency, topic (notification coalescing), and per-request timeout options
  • Legacy GCM API key support (setGCMAPIKey) for older Android push endpoints

Common Use Cases

  • Sending browser push notifications from a Node.js backend to subscribers registered via the Push API
  • Re-engagement and transactional alerts for PWAs (new message, order update, price drop) without a third-party notification SaaS
  • Generating and rotating VAPID key pairs for a self-hosted push notification service
  • Building a lightweight notification worker/queue consumer that calls sendNotification() per subscriber

Under The Hood

Architecture — The package is a thin, single-purpose pipeline: src/index.js exposes a small functional surface backed by one WebPushLib class instance (src/web-push-lib.js) that holds module-level gcmAPIKey/vapidDetails state. sendNotification() first calls generateRequestDetails(), which validates the subscription, merges per-call options over the stored defaults, optionally runs the payload through encryption-helper.js, and picks an auth strategy (VAPID header via vapid-helper.js, or a legacy GCM/FCM API key) based on the subscription endpoint’s hostname. The resulting { endpoint, headers, body } is then handed to a node:https request wrapped in a Promise, with an optional https-proxy-agent swapped in when a proxy option is set. src/cli.js is a separate thin wrapper that parses minimist argv and calls into the same library. Tech Stack — Plain ESM JavaScript ("type": "module") for Node >= 16, with no TypeScript and no framework dependency. Runtime dependencies are minimal and purpose-built: asn1.js (DER-encodes EC private keys for VAPID JWT signing), jws (JWT signing), http_ece (Encrypted Content-Encoding for payload encryption), https-proxy-agent, and minimist for CLI parsing. Dev tooling is mocha + c8 for tests/coverage, eslint (flat config) for linting, and Playwright for browser-based encryption interop tests. Code Quality — The test/ directory has 8 test files with unit coverage over VAPID header generation, encryption, CLI argument handling, and setGCMAPIKey/setVapidDetails, plus a testBrowsers.js that exercises real payload decryption in Playwright-driven browsers to validate protocol interop rather than just unit-testing the crypto locally. Input validation is thorough and defensive — generateRequestDetails() rejects unknown option keys, malformed subscriptions, and invalid TTL/urgency/topic/proxy/agent values with descriptive errors before any network call is attempted. The code favors plain functions and explicit checks over abstraction layers, keeping the failure surface easy to trace. API Design — The public API is deliberately small: one function to send a notification, one to generate VAPID keys, one to set them globally, and generateRequestDetails() exposed separately for callers who want the raw request shape without an HTTP call (e.g. to send it through their own client). Global mutable state for VAPID/GCM defaults (set once via setVapidDetails) trades some purity for a shorter call site in the common case, with per-call options.vapidDetails available as an escape hatch. Errors carry the push service’s status code, headers, and body via a dedicated WebPushError class, making upstream failures (expired subscriptions, invalid VAPID audience, etc.) programmatically distinguishable from network errors.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers