Web configuration
Two files touch your site — a script tag and a service worker — and nothing else. Everything a visitor sees (when the prompt appears, what it says, whether a welcome notification follows) lives in the console, so changing it never means a redeploy.
Console path: Settings → Push platforms → Web push.
1 · Choose your integration
| Path | Pick it when |
|---|---|
| Typical site | You can add a script tag and upload a file to the site root. |
| WordPress, Shopify or another CMS | You edit a theme, and the site root is not yours to write to. |
| Custom code | You want to decide exactly when the prompt appears, from your own button. |
The choice only changes the steps the console shows you and whether the snippet
passes autoPrompt: false. Switching later costs nothing — subscribers are
bound to your VAPID keys, not to this setting.
2 · Add the snippet
<script src="https://api.notibase.com/sdk/notibase.js" defer></script>
<script>
window.notibaseDeferred = window.notibaseDeferred || [];
notibaseDeferred.push(function (nb) {
nb.init({ clientKey: "ck_live_...", apiUrl: "https://api.notibase.com" });
});
</script>
The script is deferred, so the queue exists before the SDK does — push a
callback and it runs the moment the SDK loads. init() fetches your site
configuration, registers the service worker, restores an existing subscription, and
(unless you turned it off) asks for permission the way you configured it.
It is safe to call on every page load and it never throws into your page. A site with no VAPID keys yet simply ends up with a registered worker and no prompt.
3 · Serve the service worker
Download it from the console — or write one line yourself:
// public/sw.js
importScripts("https://api.notibase.com/sdk/sw.js");
/assets/sw.js can never
receive push for /. Serve it from the site root unless you have set a different
path under Advanced push settings.On a CMS that will not let you write to the root, a redirect or rewrite from
/sw.js to our hosted copy works just as well — the file only has to answer at that
path with a JavaScript content type.
HTTPS is required. localhost is treated as secure for development;
a plain http:// host is not.
4 · Permission prompt
Three styles:
| Style | What happens |
|---|---|
| Slide prompt (default) | Our own prompt appears first. The browser is only asked once the visitor clicks Allow. |
| Browser dialog | The native dialog fires directly, after your delay. |
| Never | Nothing is asked. You call nb.promptForPush(). |
The slide prompt is the default for a blunt reason: a browser-level Block is permanent and cannot be undone from your site. A visitor who dismisses a soft prompt can be asked again next week; a visitor who blocks the browser dialog is gone for good. Chrome and Firefox also auto-block sites whose prompts are ignored repeatedly.
Safari refuses a permission request that is not tied to a user gesture, so the browser dialog style will not fire there at all. The slide prompt requests permission from inside its own Allow click, which Safari accepts.
Timing is two conditions, both of which must pass: a delay in seconds, and a page-view
number counted in that browser's localStorage. A dismissal is remembered for
seven days.
Asking from your own button
await nb.init({ clientKey: "ck_live_...", apiUrl: "https://api.notibase.com", autoPrompt: false });
document.querySelector("#enable-push").addEventListener("click", async () => {
const result = await window.notibase.promptForPush();
if (result) console.log("subscribed", result.deviceId);
});
promptForPush() resolves to { deviceId } on success and null
if the visitor or the browser said no. It never throws. Copy and timing still come from the
console, so marketing can change the wording without touching your code.
await nb.isSubscribed(); // reflect the real state in your own UI
5 · Welcome notification
Sent once, to the browser that just subscribed — not on every page load, and not when a returning visitor's subscription is silently restored. It goes through the normal send pipeline, so it appears in the delivery log like any other message and a failure is visible instead of silent.
An empty title means off, even with the toggle on: there is nothing worth showing.
Advanced push settings
| Setting | Effect |
|---|---|
| Service worker path / filename / scope | Where the file lives. Change only if your hosting forces you to. |
| Auto-resubscribe | Browsers occasionally drop a push subscription while keeping permission granted. With this on, a return visit restores it silently instead of losing the subscriber. |
| Focus an existing tab | A click focuses an already-open tab on the same path instead of opening a second copy. Matching is by origin and path — query strings differ per campaign and would defeat every match. |
| Persistence | Notifications wait for a dismissal instead of fading. Ignored on macOS, where the system always auto-hides banners. |
Changing your VAPID keys
Two operations that look alike and are opposites:
- Import an existing pair — subscriptions survive. This is the only way to carry web subscribers over from another provider, and it needs the original private key. Most providers will not export it, so confirm you can get it before planning a migration around it.
- Regenerate — every existing subscription is destroyed, permanently. Each browser subscription is bound cryptographically to the key pair that created it. Do this only if the private key leaked.
Browser support
| Browser | Status |
|---|---|
| Chrome, Edge, Firefox, Opera (desktop + Android) | ✅ Full support |
| Safari macOS 16+ | ✅ Standard web push |
| Safari iOS/iPadOS 16.4+ | ✅ for web apps added to the Home Screen — prompt visitors to “Add to Home Screen” first |
Nothing is subscribing — what to check
- The page is on HTTPS (or
localhost). - The worker answers at the exact path shown in the console, with a JavaScript content type — open it in a tab and look.
- The client key belongs to this app. A key from another app registers devices you will never see here.
- The browser is not in a private window, where a subscription is discarded when the window closes.
- Permission is not already blocked for the origin — check the site settings in the address bar. Nothing your site does can override that.
The console's Check for subscribed devices button answers the same question from our side.
API reference for the SDK itself: @notibase/web.