Skip to main content
The SDK tracks the flow lifecycle for you and sends events to the FlowPilot backend, where they power placement and experiment analytics. You do not wire up any of the automatic events; you can forward every event into your own analytics pipeline, and you can add purchase conversions.

Automatic events

These events are emitted automatically during a flow:
Event (eventName)When it fires
flow_startA session starts.
screen_viewA new screen is displayed.
screen_exitThe user navigates away from a screen (carries time_on_screen_ms).
element_interactionThe user taps, toggles, or changes a component (carries interaction_type).
flow_completeThe flow ended via a closeFlow action or the final screen.
flow_exitThe flow was dismissed before completion.
experiment_exposureThe user was assigned to an A/B test variant.
conversionYou called FlowPilot.trackConversion(...).
Every event also carries a delivery_source (network, cache, stale_cache, or bundled_default) so offline and fallback renders are distinguishable from live network resolves in the dashboard. See Caching.
These event names match the backend’s accepted event types and the iOS SDK exactly. The canonical list and field definitions live in the Event taxonomy reference.

Forward events to your own analytics

Register a callback to mirror every FlowPilot event into your own analytics provider (Amplitude, Mixpanel, Segment, PostHog, and so on). It fires for every event the SDK emits, before the event goes to the FlowPilot backend.
import { FlowPilot } from '@flowpilotjs/react-native-sdk';

FlowPilot.setAnalyticsCallback(({ eventName, properties }) => {
  // Mirror every FlowPilot event into your pipeline
  Analytics.track(eventName, properties);
});
The callback receives a small shape:
type AnalyticsCallback = (event: {
  eventName: string;                       // the event type, e.g. 'screen_view'
  properties: Record<string, unknown>;     // event properties, enriched with flow_id and screen_id
}) => void;
properties is the event’s property bag enriched with the flow’s flow_id and the current screen_id, so you can attribute the event without plumbing context yourself. Set the callback once at startup, after configure(...).
The callback is additive: it forwards events, it does not replace FlowPilot’s own delivery. Events still go to the FlowPilot backend regardless of what your callback does. A callback that throws is caught and logged, so it cannot break tracking.

How events are delivered

Understanding the delivery model helps explain why an event might appear a little later than it fired:
  • Batched. Events are sent in batches of 10, or every 30 seconds, whichever comes first.
  • Flushed on background. When the app goes to the background (or iOS reports inactive), the queue is flushed, so leaving the app does not lose recent events.
  • Persisted to disk. The queue is written to disk with expo-file-system between launches. A force-quit mid-flow does not lose data: persisted events replay on the next launch before the first flush.
  • Retried, then dropped. A failed send is retried up to 3 times; after that the batch is dropped to avoid an unbounded queue. The in-memory queue is capped at 100 events.
  • Deduplicated server-side. Each event has a stable event_id, and the backend deduplicates, so a replayed batch after a crash does not double-count.

Conversions

Revenue is tracked separately, because it originates from your purchase flow, not the UI. See Conversions and revenue for trackConversion, which emits a conversion event attributed to the most-recently-presented flow.

Common mistakes

  • Doing heavy work in the callback. It fires on the event path. Keep it light (hand off to your analytics SDK) so you do not stall tracking.
  • Setting the callback after presenting. Register it once at startup so it catches flow_start and everything after.
  • Expecting instant delivery in the dashboard. Events are batched (10 or 30s). For a quick check, background the app to force a flush, or set logLevel: 'debug'.
  • Assuming a force-quit loses events. It does not; queued events persist to disk and replay next launch. Missing events are usually a network failure after retries, visible in the debug log.

Troubleshooting

  • Events not appearing. Set logLevel: 'debug' to see batch flushes. Common causes: the app force-quit before the 30s timer (events replay next launch, they are not lost), or a network error after retries are exhausted (a Logger.warn line in the log). On-disk persistence needs expo-file-system; confirm it is installed as a peer dependency.
  • Duplicate events in the dashboard. Expected and harmless on a replay-after-crash; the backend deduplicates by event_id.
  • conversion missing. A conversion before any flow is presented is dropped. See Conversions.