Skip to main content
When a user buys something after seeing a flow, tell FlowPilot. A conversion event ties the revenue back to the exact flow, flow version, placement, screen, and experiment variant that was on screen, so your experiment results and placement analytics can measure what actually drove the purchase.

The API

trackConversion exists on both the SDK singleton and a FlowSession. Both are public and have the same signature.
// On the singleton: routes through the most-recently-started session.
public func trackConversion(
    amount: Double,
    currency: String,
    productId: String? = nil,
    metadata: [String: Any]? = nil
)

// On a session you hold: attributes to that specific flow.
public func trackConversion(
    amount: Double,
    currency: String,
    productId: String? = nil,
    metadata: [String: Any]? = nil
)
ParameterTypeMeaning
amountDoublePurchase amount in currency’s decimal units (for example 9.99). Pass 0 for a non-monetary conversion such as a signup.
currencyStringISO 4217 code (for example "USD"). The SDK uppercases it before sending.
productIdString?Optional product identifier (for example an Apple IAP product id). Sent under the product_id property.
metadata[String: Any]?Optional extra properties. A product_id set here takes precedence over the productId parameter.

Which one to call

  • Use FlowPilot.shared?.trackConversion(...) for purchases that complete outside the flow, such as a StoreKit transaction callback that fires seconds after the flow has already dismissed. The SDK keeps a strong reference to the most-recently-started session so the event still attributes correctly.
  • Use session.trackConversion(...) when you are holding the FlowSession (a SwiftUI FlowPresenterView integration) and want to attribute to that exact session.
The conversion is sent as an event with type conversion and carries the session’s full context: flow_id, flow_version_id, placement_id, experiment_id, variant_id, and the current screen. See Event taxonomy for the event shape.

Example: attributing a StoreKit purchase

Call trackConversion once the purchase is confirmed, from your transaction handler:
import StoreKit

func handle(_ transaction: Transaction) async {
    // Purchase is confirmed at this point.
    FlowPilot.shared?.trackConversion(
        amount: 9.99,
        currency: "USD",
        productId: transaction.productID   // e.g. "pro_monthly"
    )
    await transaction.finish()
}
If you are embedding a flow with SwiftUI and still hold the session, attribute to it directly:
session.trackConversion(
    amount: 9.99,
    currency: "USD",
    productId: "pro_monthly",
    metadata: ["billing_period": "monthly"]
)

Notes

  • It does not close the flow. Tracking a conversion only records the event. Dismiss or complete the flow separately (for example with a closeFlow action on a button).
  • Calling after the flow dismisses is fine. The session keeps its configured context for its lifetime, so an IAP callback that fires after the user has left the flow still attributes to the right flow and variant.
  • No active session means the event is dropped. FlowPilot.shared?.trackConversion(...) logs a warning and drops the event if no flow has been presented yet, because the backend requires flow context. Only call it after presentPlacement or createSession has run.

Common mistakes

  • Tracking before the purchase confirms. Call trackConversion only after the transaction succeeds, not when the user taps Buy. A failed or cancelled purchase should not produce a conversion.
  • Expecting it to dismiss the flow. It does not. Close the flow with its own action.
  • Calling it before any flow was presented. The singleton has no session to attribute to and the event is dropped. Present a flow first, or hold the session and call session.trackConversion.
  • Inconsistent currency codes. Use ISO 4217 codes. The SDK uppercases the value, but sending "usd" and "US Dollars" in different places will fork your reporting.