# 23-Jun-2026 — Web Push Notifications and VAPID Keys

_____

A companion to [NGX Ramblers Architecture Overview](https://ngx-ramblers.org.uk/how-to/technical-articles/2026-02-11-ngx-ramblers-architecture). It explains the **Web Push (VAPID) keys** listed in the System Configuration section: what they are and why NGX stores them.

## What they are for

Web Push (VAPID) keys are the credential that lets NGX send a browser notification to a committee member when a new message arrives in a shared inbox.

## Web Push, in plain terms

Web Push is the browser standard behind notifications that appear even when the site is not open in a tab. NGX registers a small background script (a service worker) in each committee member's browser. When a new inbound message is stored, the server sends a push, and that script shows the notification and updates the unread badge.

The catch: a browser will not accept a push from just anyone. Each push travels through the browser maker's push service — Google's for Chrome, Mozilla's for Firefox, Apple's for Safari — and that service needs to know the push genuinely came from this application and not from a spammer.

## Where VAPID comes in

VAPID (Voluntary Application Server Identification) is how the application proves who it is. It is a pair of keys:

- a **public key**, handed to the browser when a member subscribes to notifications
- a **private key**, kept on the server and used to sign every push it sends

The push service checks the signature against the public key the browser registered, and only then delivers the message. A **subject** (a `mailto:` contact address) is included so the push service has someone to contact if there is a problem.

## How NGX uses them

- The keys are generated once and reused. They are stored in the central config (the `inboxPush` setting: `vapidPublicKey`, `vapidPrivateKey`, `vapidSubject`), alongside the other service credentials.
- When a committee member turns on notifications, their browser subscribes using the public key, and NGX stores that subscription (the `inboxPushSubscriptions` collection).
- When an inbound message is assigned to a role, NGX signs a push with the private key and sends it to each subscribed member of that role. The same signal drives the live unread badge in the admin UI.

## The flow at a glance

**1. Subscribe** (once, when a member turns on notifications):

```mermaid
flowchart LR
    APP1@{ icon: "ngx:ramblers", label: "NGX Ramblers", pos: "b", h: 48 }
    MEMBER@{ icon: "ngx:user", label: "Member's browser", pos: "b", h: 48 }
    STORE@{ icon: "ngx:mongodb", label: "inboxPushSubscriptions", pos: "b", h: 48 }
    APP1 -->|"public VAPID key"| MEMBER
    MEMBER -->|"subscription: endpoint + keys"| STORE
```

**2. Send** (each time a message arrives):

```mermaid
flowchart LR
    MSG["New inbound message"]
    APP2@{ icon: "ngx:ramblers", label: "NGX Ramblers", pos: "b", h: 48 }
    PUSHSVC["Browser push service<br/>Google · Mozilla · Apple"]
    SW["Service worker<br/>in member's browser"]
    BADGE["Notification + unread badge"]
    MSG --> APP2
    APP2 -->|"push signed with private key"| PUSHSVC
    PUSHSVC -->|"verify against public key, deliver"| SW
    SW --> BADGE
```

The inbound flow that triggers these notifications is described in the Email Architecture section of the [architecture overview](https://ngx-ramblers.org.uk/how-to/technical-articles/2026-02-11-ngx-ramblers-architecture).
