Skip to main content

Browser Push Notifications

SendSeven lets you collect browser push subscribers and send them notifications through campaigns and flows. There are two ways to ask visitors for push permission:

Hosted by SendSevenOn your own domain
InstallationNothing to installOne file + one script tag
Permission promptOpens in a SendSeven-hosted popup window (your-workspace.push.sendseven.com)Shown directly on your page
Notification sender shown by the browserYour SendSeven push subdomainYour own domain
Trigger momentVia SendSeven widgetsAnywhere — automatically, or from your own buttons and code (e.g. after checkout)
Works on hosted site builders without file accessYesNo (you must be able to serve a file from your webroot)

Both modes can be used side by side. Subscribers are stored in the same lists either way.

Permission is per origin

Browser push permission is bound to the exact origin it was granted on. Subscribers collected on your SendSeven push subdomain keep working there, but they do not transfer to your own domain — the own-domain list starts fresh.

Prerequisites

  • A SendSeven account with the Browser Push channel (created automatically for every workspace)
  • A widget ID — any widget from Settings → Widgets works; the SDK uses it to load your branding and default lists
  • For own-domain mode: the ability to place a file at the root of your website

Own-domain setup

Step 1 — Add the service worker file

Create a file at the root of your website (the file must be served from your own origin, at the top level, so it can control the whole site):

https://www.your-domain.com/sendseven-sw.js
importScripts('https://widget.sendseven.com/service-worker.js');

That single line is the whole file. The actual push-handling logic is loaded from SendSeven's CDN, so you never need to update this file — we ship improvements automatically.

No redirects

Browsers refuse service worker scripts that are served via a redirect. /sendseven-sw.js must answer with 200 OK directly. A server-side rewrite or proxy rule is fine; a 301/302 is not.

Already have a service worker? If your site is a PWA with an existing service worker, don't add a second file — add the importScripts(...) line at the top of your existing service worker instead, and set data-sw-path (below) to its path.

Step 2 — Add the SDK snippet

Add this before the closing </body> tag on every page where you want push functionality:

<script src="https://widget.sendseven.com/push-sdk.js"
data-widget-id="YOUR_WIDGET_ID" async></script>

Script tag attributes

AttributeRequiredDefaultDescription
data-widget-idYesWidget ID used for branding, language, and default lists
data-autoNofalse"true" shows the branded permission prompt automatically
data-delayNo5Seconds to wait before the automatic prompt
data-sw-pathNo/sendseven-sw.jsPath to the service worker file on your origin
data-listsNoComma-separated list IDs new subscribers are added to
data-languageNochannel setting"auto" follows the visitor's browser language, or pass a locale code (ar, de, en, es, fr, hr, it, ja, ko, nl, pl, pt, ru, tr, zh). Omit it to use the language configured on the Browser Push channel
data-fallback-languageNoenLocale used when the visitor's language is not supported

The prompt's title, description and buttons are translated automatically; any custom texts you configured on the Browser Push channel always win over the translation.

With data-auto="true" the SDK shows a branded, non-blocking "soft ask" card first; the browser's native permission dialog only appears after the visitor clicks Allow. If the visitor dismisses the card, it is not shown again automatically for 7 days.

Step 3 — Verify the installation

In the SendSeven app, open Settings → Channels → Browser Push → Settings → Install on your website, enter your domain, and click Verify installation. SendSeven checks that:

  1. https://your-domain.com/sendseven-sw.js is reachable,
  2. it is served without a redirect, and
  3. it imports the SendSeven service worker.

JavaScript API

Once loaded, the SDK exposes window.SendSevenPush:

SendSevenPush.prompt(options?)

Shows the branded soft-ask card, then (on Allow) the native permission dialog, then subscribes. Returns a Promise.

const result = await SendSevenPush.prompt({
listIds: ['LIST_ID_1', 'LIST_ID_2'], // optional, overrides data-lists
email: '[email protected]', // optional, links to an existing contact
externalId: 'user-4711' // optional, your own user reference
});
// result: { subscribed: boolean, reason?: string }

SendSevenPush.subscribe(options?)

Same options and return value as prompt(), but skips the soft-ask card and goes straight to the native permission dialog. Use this when your own UI already asked the question — for example a "Notify me about my order" button on the order confirmation page:

document.querySelector('#order-updates').addEventListener('click', async () => {
const { subscribed } = await SendSevenPush.subscribe({
listIds: ['ORDER_UPDATES_LIST_ID'],
email: order.customerEmail
});
if (subscribed) showToast('You will be notified about your order!');
});

Passing email stores the address with the subscriber: if no contact with that email exists yet, a contact is created with it (instead of an anonymous push subscriber). If a contact with that email already exists, the subscription is kept separate and the address is stored as a claimed email on the subscription — because the visitor's identity isn't verified, SendSeven never links a browser to an existing contact based on an email alone. You can merge them manually in the app.

SendSevenPush.isSubscribed()

Returns Promise<boolean>true when permission is granted and an active push subscription exists.

SendSevenPush.unsubscribe()

Removes the browser-side push subscription. Returns Promise<boolean>.

Result reasons

prompt() / subscribe() resolve with { subscribed: false, reason } when subscription did not happen:

ReasonMeaning
dismissedVisitor clicked "Not now" on the soft-ask card
deniedBrowser permission is (or was previously) denied
unsupportedBrowser does not support push notifications
sw_missing/sendseven-sw.js was not found on your origin (check the browser console for details)
sw_error, init_failed, subscribe_failed, save_failedTechnical failures — details in the browser console

Calling the SDK before it has loaded

The script loads with async, so SendSevenPush may not exist yet when your code runs. Two options:

Ready event:

window.addEventListener('sendseven:push-ready', () => {
// SendSevenPush is fully available here
});

Command queue (safe to call from inline onclick handlers at any time):

<script>
window.SendSevenPush = window.SendSevenPush || { q: [] };
window.SendSevenPush.prompt = window.SendSevenPush.prompt ||
function (o) { window.SendSevenPush.q.push(['prompt', o]); };
window.SendSevenPush.subscribe = window.SendSevenPush.subscribe ||
function (o) { window.SendSevenPush.q.push(['subscribe', o]); };
</script>

<button onclick="SendSevenPush.prompt()">Get updates</button>

Queued calls are executed in order once the SDK loads. Note that queued calls cannot receive the Promise return value — use the ready event if you need the result.

Ready-made buttons

The Promotion tools tab under Widgets in the SendSeven app generates copy-paste subscribe-button snippets with your lists pre-selected.

Customizing the prompt

The soft-ask card uses your Browser Push channel settings (Settings → Channels → Browser Push): company name, logo, brand color, language (12 languages supported), and per-text overrides (title, description, buttonText).

Hosted mode

Without any installation, SendSeven widgets (e.g. the newsletter widget) offer push subscription through a popup window on your workspace's push subdomain (your-workspace.push.sendseven.com). Visitors grant permission to that subdomain and notifications are delivered from it. This remains the right choice for hosted site builders where you cannot place a file in the webroot.

Limitations

  • iOS Safari delivers web push only for sites the visitor has added to their home screen (an iOS platform restriction, both modes).
  • The service worker file must be at a path that covers the pages where you subscribe visitors — serving it from the webroot is strongly recommended. Deeper scopes require the Service-Worker-Allowed response header.
  • Subscribers are origin-bound: switching between hosted and own-domain mode does not migrate existing subscribers.

Troubleshooting

SymptomCause / fix
reason: 'sw_missing' and a console errorThe stub file is missing, or your server answers unknown paths with index.html (common on SPAs — add an explicit route for /sendseven-sw.js)
Verify fails with "redirect"Your server redirects the file (e.g. to a canonical host or trailing slash). Serve it with a direct 200
Prompt never appears with data-autoPermission was previously denied in the browser, or the visitor dismissed the card within the last 7 days
Notification permission dialog blocked by the browserSome browsers require a user gesture — trigger subscribe()/prompt() from a click handler