Crossdeck Docs
Dashboard

Event Delivery & Data Durability

SDKs 4 min read · The honest contract behind every event you send

This page is the precise promise Crossdeck makes about your analytics events — how they queue, how they deliver, what survives a crash or an outdated SDK, and where the edges are. It is written so the bounds are numbers, not adjectives. And it draws one line clearly: analytics events are durable best-effort with honest bounds; your money — payments, subscriptions, entitlements — never travels through this queue at all.

Normal operation

Every SDK queues events on-device and delivers them in batches — flushing every few seconds or when the buffer fills, whichever comes first. Network failures re-queue the batch and retry with backoff; duplicate delivery is impossible because the server deduplicates on a per-event idempotency key, so a retry after a mid-flight crash never double-counts. On platforms with durable storage the queue is persisted on every enqueue: a crash, a force-quit, or a restart picks up exactly where it left off on the next launch.

Per-platform durability

SDKQueue lives inSurvives restart?Bound
@cross-deck/weblocalStorageYes — across page loads and browser restartsmost recent ~1,000 events / device
@cross-deck/react-nativeAsyncStorageYes — across app restartsmost recent ~1,000 events / device
@cross-deck/swifton-disk queueYes — across relaunchesmost recent ~1,000 events / device
@cross-deck/nodeprocess memoryNo — a process restart clears the queueheld within the process lifetime
Node's caveat, stated plainly. The server SDK's queue is in-memory today: events buffered between flushes are lost if the process dies before they deliver. Long-running servers flush every 1.5 seconds by default and drain on shutdown (await server.shutdown()), so the at-risk window is small — but it is real, we say so, and an opt-in disk-backed queue is on the roadmap (tracked internally; the SDK changelog will announce it).

PARK: what happens on a version rejection

If your installed SDK is too old for the current event format, the server refuses the batch with HTTP 426 Upgrade Required (sdk_version_unsupported). Your SDK recognises that exact response and parks — a third outcome, deliberately distinct from retry (this isn't transient) and drop (your data isn't invalid; only the wire dialect is old):

The scariest sentence — "your data stopped" — is actually "your data is waiting, and we told you immediately."

The bounds, in plain numbers

The contract, in one sentence

Crossdeck guarantees delivery of queued events across normal failures; during a version-rejection window we preserve the most recent ~1,000 events per device — the longer the window, the more history ages out. Keep SDKs current; we make that one line.

"One line" is literal: npm install @cross-deck/web@latest (or a SwiftPM bump) and ship. The advisory in your dashboard names the exact minimum version.

What's never at risk

Payments, subscriptions, and entitlements never travel through this queue. Money moves on server-side rails — Stripe, Apple, and Google report directly to Crossdeck's backend via signed webhooks, with their own retry semantics, idempotency keys, and reconciliation sweeps that re-check the rail's records against ours. A parked analytics queue, a full device, an outdated SDK, a phone at the bottom of a lake: none of it can lose a payment record or flip an entitlement.

That is the line this page exists to draw: money is sacred and multiply-guarded; analytics is durable best-effort with honest, numeric bounds. The two never share a failure mode.