ScaleBun
Skip to article

Events

react-nativeDeveloper

Track custom events and revenue, understand the automatic lifecycle events, and design an event schema that stays useful.

Updated Reviewed

An event is a named thing that happened, with optional properties.

TypeScript
ScaleBun.track('checkout_started', { cartValue: 42.5, currency: 'USD', items: 3 });

What is emitted for you#

You do not need to instrument these:

EventWhen
first_openFirst launch after install
app_openEach foreground
session_startEach new session

Controlled by autoLifecycleEvents (default true). Screens, deep links, interactions and push events come from the automatic instrumentation — enabled by default when you use ScaleBunProvider, and opt-in via automaticEventTracking when you call init() directly.

Revenue#

Purchases have a dedicated call because revenue needs a consistent shape to be aggregated:

TypeScript
ScaleBun.trackPurchase({  revenue: 42.5,  currency: 'USD',  transactionId: 'txn_abc123',  // any additional properties are preserved  sku: 'pro_monthly',});

transactionId must be unique and stable. It is what deduplicates a purchase that gets reported twice — from a receipt validation retry, for example — so a random value per call will inflate your revenue.

Use the real amount charged in the real currency. Do not pre-convert to USD; the platform does currency handling, and pre-converting loses the original.

Designing an event schema#

The names you pick become your analytics vocabulary. A few rules that prevent the most common mess:

TypeScriptRecommended
// Consistent snake_case, past tense, one concept per name.ScaleBun.track('checkout_started', { cart_value: 42.5, item_count: 3 });ScaleBun.track('checkout_completed', { cart_value: 42.5, item_count: 3 });ScaleBun.track('checkout_failed', { reason: 'card_declined' });
  • Put variables in properties, not names. checkout_failed with { reason: 'card_declined' } stays one funnel step. Encoding the reason in the name creates one event per failure mode, and no funnel.

  • Keep property values low-cardinality where you intend to group by them. A timestamp or an id as a property is fine to store, but you will never group by it usefully.

  • Never put secrets or PII in properties. Events are readable by everyone with dashboard access and appear in exports.

Flushing#

Events batch by design — that is what keeps capture cheap. The batch drains on its own schedule (flushIntervalMs, default 5000).

Force a drain when you are about to lose the process:

TypeScript
await ScaleBun.flush();

Worth doing before a deliberate sign-out or an app-initiated restart. Not worth doing after every track() call: it defeats batching and adds network churn for no benefit, since the outbox already survives an app kill.

Offline behaviour#

Nothing is lost when there is no connection. Envelopes are written to an on-device outbox, persisted across restarts, and drained with retry and backoff when connectivity returns. track() does not wait on the network and does not fail when it is unavailable.

Debugging what you send#

TypeScript
// Confirm the current identity and ids the SDK will attach.ScaleBun.events.ids();
// Start a fresh analytics session (useful when testing session-scoped funnels).ScaleBun.events.newSession();

For live inspection during development, enable the desktop debugger:

TypeScript
await ScaleBun.init({  projectId: '…',  publishableKey: '…',  apiBaseUrl: '…',  desktopDebug: true,  verbose: true,});
Events · Monitoring · React Native SDK · ScaleBun