Skip to main content
This guide takes a new website integration from channel configuration to a real journey or campaign notification. The recommended flow keeps customer identity and private keys on your backend while the browser add-on owns the Web Push lifecycle.
Shopify Online Store themes use Sagepilot’s Shopify app embed and Theme App Extension instead of installing this npm add-on directly. Follow Shopify Web Push setup. Use this guide for websites and custom/headless storefronts whose application code and public assets you control.

What you will build

The browser never receives the VAPID private key, the channel identity signing secret or Sagepilot send authority. It receives only the public VAPID key through the authenticated Push session.

Prerequisites

  • A Sagepilot workspace and an active Push Notifications channel.
  • A stable customer ID from your website’s authenticated session. Do not generate a new ID on every login or page load.
  • An HTTPS website. Browser-recognized loopback hosts such as localhost can be used for local development.
  • A backend route that can authenticate the current website customer and sign a short-lived proof.
  • A supported browser. Check capability with isWebPushSupported() instead of relying on a hard-coded browser list.
If your site has a strict Content Security Policy, allow same-origin workers and connections to your Sagepilot host, normally https://app.sagepilot.ai. If the same customer also uses your mobile app, use the same canonical customer identity for the app and website. Sagepilot stores the mobile FCM/APNs token and browser Web Push subscription as separate endpoints under that customer.

1. Configure the Sagepilot channel

In Sagepilot, create or edit a Push Notifications channel:
  1. Under General, turn on Web Push and keep the channel active.
  2. Under Web Push, add one VAPID public key, its matching private key and a contact email.
  3. Under SDK & delivery, generate an Identity signing secret. Copy it now; the saved secret cannot be retrieved later.
  4. Choose the anonymous-customer policy and notification image policy your product needs.
  5. Click Save Changes.
You need these integration values:
Ask your Sagepilot workspace administrator for the workspace_id:push_channel_id integration key if your application team does not manage the channel.
SAGEPILOT_PUSH_IDENTITY_SECRET and the VAPID private key are different secrets. Both stay server-side. Do not put either value in a browser-exposed variable such as NEXT_PUBLIC_* or VITE_*.
To generate a new VAPID pair when your organization does not already manage one, you can use the standard web-push utility:
Store the pair in your secret manager and enter it in the channel. The browser add-on obtains only the public key from Sagepilot.

2. Install the packages

Install the Push add-on. The Website Widget installation remains a separately loaded Sagepilot script when your site also uses chat.

Deploy the service worker

Copy the worker shipped by the add-on into your framework’s public/static directory so it is served at this exact same-origin URL:
For Next.js, Vite or Create React App projects whose static directory is public/:
Automate the copy in your build or postinstall script so package upgrades deploy the matching worker. Verify the production URL returns JavaScript without authentication or a redirect:
For a portable build step, save this as scripts/copy-sagepilot-push-worker.mjs:
Then run it after install and before every production build:
The add-on registers this worker automatically with the isolated /sagepilot-push/ scope. It does not replace an existing root PWA service worker. Do not manually register the Sagepilot worker or change its filename or scope.

3. Generate a customer identity proof on your backend

Next.js App Router example

Use the complete Next.js example for authentication, the proof route, browser initialization, consent, logout and failed-revocation retry.
Install a maintained JWT library in your server application. This example uses jose:
Create an HS256 proof only after your normal authentication middleware has established the current customer:
Expose it through an authenticated, same-origin backend route:
Adapt requireAuthenticatedCustomer() to your framework. The route must derive customer.id from the authenticated server session, not from an untrusted customer ID in the request body. The proof contract is: You may use an existing Sagepilot customer_id instead of client_customer_id when your backend already stores that UUID. Do not send both identities unless you intentionally validate that they refer to the same customer.

4. Identify the customer in the browser

Create the Push instance in browser code after your host application restores its authenticated session. For server-rendered frameworks, keep this code in a client-only module or component.
Call connectSagepilotPush() after login and on a full page reload while the customer remains signed in. identify() never prompts for notification permission. It also repairs a previously granted subscription, completes browser subscription rotation and flushes retained observations. sync() reports the current state:

5. Request permission from a clear customer action

Call subscribe() from the click handler of an explicit button. Do not call it during page load, login or chat initialization.
Use { marketingConsent: true } only when the button copy clearly tells the customer that they are opting into marketing notifications. For support-only notifications, call subscribe() without that option and persist the appropriate support preference separately. Browser permission and marketing consent are independent:
  • Browser permission allows this origin to display notifications.
  • Sagepilot preferences determine which notification categories the customer permits.
  • A channel must also be active and the endpoint must be eligible for the send.
Read or update explicit preferences after identification:

6. Use chat and Push together

Chat and Push remain separate even when your website uses both. Identify them from the same host-authenticated customer:
The chat channel and Push channel use different keys. The Push proof’s client_customer_id should equal the stable user_id used for chat. Generate sagepilotUserHash on your server with the Website Widget identity secret and return it with the authenticated customer. Never expose that secret or generate the hash in browser code. If Website Widget identity verification is disabled, omit user_hash. The Widget hash and Push proof are separate credentials; neither replaces the other.

7. Handle logout, opt-out and teardown

Use the method that matches the customer’s action:
Attempt and await logout() before clearing the host session, but never abandon the website’s sign-out flow if Push was not connected or the Sagepilot API is temporarily unavailable. A failed logout() retains the add-on’s delete-only binding. The fallback above removes the local browser subscription immediately, and retryPendingSagepilotPushLogout() retries server revocation before another customer can be identified. Report both failures to your monitoring. After a successful Push logout, the customer must explicitly subscribe again on the next login because logout removed the browser subscription. Use a same-origin HTTPS deep link that your website can load. The worker restricts notification navigation to the website’s own origin. An external-origin destination falls back to the website origin. When a notification is sent, the worker records signed observations automatically: For destination_opened, instantiate and identify the Push add-on on the landing page. The worker places only an opaque click marker in the URL; the add-on removes it after capture. Signed event data never enters the URL. The worker retains observations when no page is open. The next identified page uploads them automatically. During testing, you can wait for an immediate upload:
Static notification images use the channel’s image policy and a publicly accessible HTTPS image URL. If an image fails, notification text remains available.

9. Test end to end

1

Verify the worker asset

Open /sagepilot-push/sagepilot-push-worker.js on the deployed origin and confirm it returns 200 JavaScript without a login page or redirect.
2

Identify a real test customer

Sign in through your website. Confirm connectSagepilotPush() returns permission_required, not_subscribed or registered without opening a prompt.
3

Subscribe explicitly

Click your notification opt-in button, allow the browser prompt and confirm the result is registered with a non-null endpointId.
4

Send through the real product flow

Create a test list or segment containing only this customer, then send a Journey or Campaign through the Push channel. The current channel Test Send form targets Android/FCM, so do not use it as the Web Push verification path.
5

Test browser states

Confirm notification behavior with the page focused, in the background and closed. Browser and operating-system settings can affect presentation.
6

Verify engagement

Click the notification, confirm the intended same-origin page opens, call flush() during development and inspect received, opened and destination-opened metrics separately.
7

Verify cross-platform fan-out

Register the same customer in your mobile app and browser, then run one controlled Journey or Campaign. Each eligible active endpoint should receive its platform notification.
8

Verify revocation

Call unsubscribe() or logout(), send again and confirm the revoked web endpoint is no longer eligible.
A UI result such as “queued” proves only that the send entered Sagepilot’s delivery pipeline. It does not prove provider acceptance, service-worker receipt, browser presentation or a customer click. Use the separate analytics stages to locate a failure.

Troubleshooting

For method signatures and error fields, see the Web SDK API reference.