Skip to main content
FlowPilot already tracks flow analytics for you and sends them to the FlowPilot backend, which powers placement analytics and experiment results. The analytics callback is an extra tap on that same stream: it hands you every event the SDK records so you can forward selected events into Amplitude, Mixpanel, Segment, or your own pipeline. The callback is additive. It does not replace FlowPilot’s own ingestion. Both happen for every event.

Set the callback

public func setAnalyticsCallback(_ callback: @escaping AnalyticsCallback)
// AnalyticsCallback = (AnalyticsEvent) -> Void
Set it once at startup, right after FlowPilot.configure(...):
FlowPilot.shared?.setAnalyticsCallback { event in
    print("FlowPilot event:", event.eventName)
}
The callback is captured into each flow session when the session is created. Set it before you present or create a session, otherwise events from that session will not reach your callback.

The event

Each call gives you an AnalyticsEvent. The useful fields:
FieldTypeNotes
eventNameStringThe event type, for example flow_complete. (Encoded on the wire as event_type.)
flowIdStringThe flow that produced the event.
flowVersionIdStringThe exact published version.
placementIdString?The placement that resolved the flow.
experimentIdString?Set when the user is in an experiment.
variantId / variantNameString?The assigned variant, when in an experiment.
screenId / screenNameString?The current screen, for screen and interaction events.
screenIndexInt?0-indexed screen position.
elementId / elementType / interactionTypeString?Set for element_interaction events.
revenue / currencyDouble? / String?Set for conversion events.
properties[String: AnyCodable]?Custom properties (for example product_id on a conversion).
userId / sessionIdStringStable user id and the current session.
timestampDateWhen the event fired.
Most fields are optional and only present for the event types that carry them. For the complete field list and per-event meaning, see Event taxonomy.

Event names

The SDK fires these automatic event names (from AutomaticEventType):
Event nameWhen
flow_startA flow begins.
screen_viewA screen appears.
screen_exitA screen is left (carries time on screen).
flow_completeThe flow completes (a closeFlow from completion).
flow_exitThe flow is dismissed before completing.
experiment_exposureThe user is assigned to an experiment variant.
element_interactionThe user drives an action chain (tap, toggle, and so on).
Two more event names appear in the stream but are not part of AutomaticEventType:
  • conversion is emitted when you call trackConversion. It carries revenue, currency, and any properties you pass, and it reaches your callback like any other event.
  • resolve_no_flow is a backend-side event recorded when a placement resolves to no flow. The iOS SDK does not emit it, so do not expect it in this callback.
These names match the backend’s event taxonomy exactly, so the names you forward line up with what FlowPilot reports. The Swift eventName property maps to the event_type field on the wire.

Example: forward to your analytics

Forward completions and conversions, with flow and experiment context attached:
FlowPilot.shared?.setAnalyticsCallback { event in
    switch event.eventName {
    case "flow_complete":
        Analytics.track("Onboarding Completed", properties: [
            "flow_id": event.flowId,
            "variant": event.variantName ?? "control"
        ])

    case "conversion":
        Analytics.track("Purchase", properties: [
            "revenue": event.revenue ?? 0,
            "currency": event.currency ?? "USD",
            "flow_id": event.flowId,
            "experiment_id": event.experimentId ?? ""
        ])

    default:
        break   // ignore the rest
    }
}

Notes

  • It runs in-process. The callback is invoked synchronously while the SDK records the event. Keep it fast and non-blocking. If you need to do heavy work, hand the event to your own queue and return.
  • It is additive, not a replacement. FlowPilot still sends every event to its backend. Your callback is an extra copy for your own tools.
  • Most fields are optional. Guard against nil. A field like revenue is only set on conversion events; screenId is only set on screen-scoped events.

Common mistakes

  • Setting the callback after presenting. The session captures the callback at creation time. Set it before presentPlacement or createSession, ideally right after configure.
  • Assuming it replaces FlowPilot ingestion. It does not. FlowPilot tracks independently. If you only wanted to disable FlowPilot’s own tracking, that is a separate concern, not this callback.
  • Double-counting purchases. If you call trackConversion and also forward the conversion event to a provider that already tracks the purchase elsewhere, you can count it twice. Pick one source of truth per metric.
  • Heavy work in the callback. Logging, disk writes, or network calls inline will slow the flow. Offload them.