When Notibase is down

Every SDK we ship is built on one rule: our outage must never become yours. This page says exactly what that means, and where it stops.

The short version. Your app does not crash, does not hang, and does not stop rendering. Devices that are already subscribed keep receiving and displaying notifications, because delivery does not involve our API. What you lose is the ability to send something new, the analytics events from that window, and the ability to subscribe new devices.

Push delivery does not go through us

This is the part worth understanding, because it is the part people assume wrongly. When you send a campaign, we hand each message to Apple, Google or the browser’s push service and they deliver it. From that moment we are not in the path.

MomentWho is involved
You press SendUs, then APNs / FCM / Web Push
The notification arrives on a handsetAPNs / FCM / the browser. Not us.
It is drawn on screenThe OS, or our service worker running in your user’s browser. Not us.
Someone taps itThe OS opens your app or your URL. Not us.
The tap is countedUs — a beacon fired alongside the open, never in front of it.

So an outage on our side does not stop a single already-delivered notification from arriving, showing, or opening. A tap during an outage costs you the click metric and nothing else — on every platform the beacon runs in parallel with the navigation, and losing it is silent by design.

What each call does when we are unreachable

CallWhat happens
configure() / init() / Notibase.init()Never waits on us. On mobile the work is handed to a background queue and the call returns immediately. On web it is bounded at five seconds and then continues on defaults.
track(), trackPurchase(), identify()Resolve false on web and Flutter; log and return on Android and iOS, where the call is already fire-and-forget on a background queue. None of them throw. The event is lost; nothing else is.
Registering a push tokenFails quietly and retries on the next token refresh or app launch. A device that was already registered stays registered.
A notification tapOpens your app and your URL immediately. The click beacon is fire-and-forget.
Reading the inboxThis one signals failure — it rejects on web, returns null on mobile. You asked for data we could not fetch, and rendering an empty inbox as though it were genuinely empty would be a lie. Show your own error state.
Live in-app messagesThe socket reconnects with exponential backoff. Nothing is queued for later; live means live.

What genuinely stops

WhatWhy, and what to do
New web subscriptionsThe browser needs your app’s VAPID public key to create a subscription, and it comes from us. Browsers already subscribed are unaffected. If this matters to you, pass vapidPublicKey to init() and the SDK stops needing us for it — see below.
Sending anythingThe console and the API are the same service. Scheduled sends are not lost: they sit in the queue and go out when we are back, which is what Delivery → Scheduled shows.
Events from that windowNot buffered and not retried later. An event is a fact about a moment, and replaying an hour of them on recovery makes every funnel wrong twice.
New device registrationsRetried on the next launch or token refresh, so this heals on its own.

Two things you can do

Pin your VAPID key

The one degradation with a real fix. Pass the key you can copy from Settings → Web push and new subscriptions no longer depend on us being reachable:

await notibase.init({
  clientKey: "ck_live_…",
  vapidPublicKey: "BPx…",   // from Settings → Web push
});

A locally-passed value always wins over the hosted config, so this is safe to set permanently. The trade is that rotating the key becomes a deploy on your side.

Watch for one console line

When the browser SDK cannot reach the hosted config it says so, once, and names the consequence:

[notibase] could not reach https://api.notibase.com/v1/web/config — running on defaults.
Browsers already subscribed keep working; new subscriptions cannot be created until it is
reachable, unless you pass vapidPublicKey to init().

It used to be silent, which meant a subscribe rate falling to zero looked exactly like a week with no visitors.

Where the script itself comes from

notibase.js and sw.js are static files on disk, served by our edge, not generated by the API. An API outage does not touch them. The tag is defer, so even a complete failure to load cannot block your page from parsing or rendering — window.notibase is simply never defined.

If you call the SDK from your own click handlers, that last case is worth one guard: if (window.notibase) await window.notibase.promptForPush(). Without it, a bundle that failed to load turns your button into a TypeError.

Your service worker imports ours with importScripts. If our origin is unreachable when the browser runs its periodic update check, the update fails and the worker you already have keeps running — so subscribed browsers carry on receiving push. Only a first-time install fails.

Timeouts, in one table

Every network call every SDK makes is bounded. None of them can hang.

SDKConnectReadAttemptsWorst case per call
Webbrowser default; hosted config bounded at 5s1one attempt
Android10s15s3 (2 retries), backoff 0.5s / 2s~76s, on a background thread
iOS15s inactivity3 (2 retries), backoff 0.5s / 2s~48s, on a background queue
Flutter10s15s3 (2 retries), backoff 0.5s / 2s~78s, never awaited at startup

Only 429 and 5xx are retried; a 4xx is your bug and repeating it would not fix it. Click beacons are never retried and are bounded at 5 seconds.

Where to look

notibase.com/status.html is a static file served independently of the API, so it stays up when we do not. It is the honest place to check — a status page that runs on the thing it reports on is decoration.

← Delivery errorsSecurity & keys →