Flutter SDK / Identity & analytics

Identity & analytics

The SDK measures the funnel for you: every flow session reports its lifecycle automatically. Identity APIs connect those sessions to your users, and track() covers everything beyond the flow.

Automatic events

No instrumentation needed — each flow session emits these on its own:

EventTypeDescription
flow_startedautoA flow session began, with its entry screen.
screen_changedautoNavigation between screens (from → to).
variable_setautoAn answer was recorded — powers per-screen answer breakdowns in analytics.
purchase_<stage>autoPaywall funnel stages: attempted, succeeded, cancelled, failed, pending.
flow_completed / flow_abandonedautoTerminal events with the end reason and collected variables.

Events carry context automatically — platform, OS version, locale, SDK version, your appVersion, attribution, and experiment assignment when one is active.

Identity

Users start anonymous: the SDK generates a persistent anonymous ID on first launch and attaches it to every event. When the user authenticates, link the two:

dart
// After your own auth completes:
await UpliftFunnel.identify(
  user.id,
  attributes: {'plan': 'free', 'signup_source': 'organic'},
);

// On logout — rotates to a fresh anonymous ID:
await UpliftFunnel.resetIdentity();

Custom events & attribution

dart
// Custom events: lowercase, [a-z0-9_:] after the first letter.
await UpliftFunnel.track('workout_saved', properties: {
  'duration_min': 32,
  'type': 'strength',
});

// Ad attribution — joins campaigns to funnel + revenue analytics.
await UpliftFunnel.setAttribution({
  'source': 'meta',
  'campaign': 'summer_launch',
  'ad_set': 'lookalike_us',
  'creative': 'video_a',
});

Events tracked while a flow is on screen are tied to that session and variant automatically; events outside a flow get an app-level session. Attribution keys are limited to source, campaign, ad_set, and creative, and feed the campaign table in analytics.

Delivery you don't have to think about

  • Events are batched and flushed every few seconds, and immediately when the app goes to background.
  • The queue is persisted to disk — events survive app kills and offline stretches, with exponential-backoff retries once the network returns.
  • Client-side event IDs make delivery idempotent: retries never double count.
  • Need a manual flush (e.g. right before logout)? await UpliftFunnel.flushEvents().