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.
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.
| Moment | Who is involved |
|---|---|
| You press Send | Us, then APNs / FCM / Web Push |
| The notification arrives on a handset | APNs / FCM / the browser. Not us. |
| It is drawn on screen | The OS, or our service worker running in your user’s browser. Not us. |
| Someone taps it | The OS opens your app or your URL. Not us. |
| The tap is counted | Us — 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
| Call | What 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 token | Fails quietly and retries on the next token refresh or app launch. A device that was already registered stays registered. |
| A notification tap | Opens your app and your URL immediately. The click beacon is fire-and-forget. |
| Reading the inbox | This 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 messages | The socket reconnects with exponential backoff. Nothing is queued for later; live means live. |
What genuinely stops
| What | Why, and what to do |
|---|---|
| New web subscriptions | The 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 anything | The 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 window | Not 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 registrations | Retried 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 (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.
| SDK | Connect | Read | Attempts | Worst case per call |
|---|---|---|---|---|
| Web | browser default; hosted config bounded at 5s | 1 | one attempt | |
| Android | 10s | 15s | 3 (2 retries), backoff 0.5s / 2s | ~76s, on a background thread |
| iOS | 15s inactivity | 3 (2 retries), backoff 0.5s / 2s | ~48s, on a background queue | |
| Flutter | 10s | 15s | 3 (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.