Skip to content

tracking conversions

Joseph Samir edited this page Jun 16, 2026 · 1 revision

Tracking Conversions

Conversion tracking lets you record goal completions for visitors bucketed into experiences. The SDK evaluates the goal's configured triggering rules and sends conversion (and optionally transaction) events to the Convert tracking API.

Basic Conversion Tracking

Track a goal conversion by passing its unique key:

await ctx.trackConversion("goal-key")

Conversion with Goal Data

You can pass additional revenue and transaction data with your conversion. GoalData is a dictionary literal keyed by GoalDataKey:

await ctx.trackConversion(
    "goal-key",
    goalData: [
        .amount: .double(10.30),
        .productsCount: .double(2),
        .transactionId: .string("transaction-unique-id"),
    ]
)

GoalData Reference

GoalData is a type alias for [GoalDataKey: GoalDataValue]. Construct it as a dictionary literal:

let data: GoalData = [
    .amount: .double(49.99),
    .transactionId: .string("txn-abc-123"),
    .customDimension1: .string("premium"),
]

GoalDataKey cases:

Key Description
.amount Order value (numeric)
.productsCount Order quantity (numeric)
.transactionId Unique transaction identifier (string or numeric)
.customDimension1.customDimension5 Custom dimensions for additional data

GoalDataValue cases:

Case Type Example
.double(Double) Numeric value .double(99.99)
.string(String) String value .string("txn-123")
.strings([String]) Array of strings .strings(["a", "b"])

Revenue Tracking

To report revenue, include goalData with .amount and .transactionId at minimum:

await ctx.trackConversion(
    "purchase-completed",
    goalData: [
        .amount: .double(99.99),
        .productsCount: .double(3),
        .transactionId: .string("txn-abc-123"),
    ]
)

When goalData is present, the SDK sends two events: a conversion event and a transaction event containing the goal data.

Force Multiple Transactions

By default, each goal fires once per visitor per experience. Subsequent calls to trackConversion for the same visitor and goal are silently deduplicated.

For recurring transactions such as subscription renewals, override deduplication by setting forceMultipleTransactions to true:

await ctx.trackConversion(
    "subscription-renewal",
    goalData: [
        .amount: .double(29.99),
        .transactionId: .string("renewal-456"),
    ],
    forceMultipleTransactions: true
)

Behavior Summary

Scenario Conversion Event Transaction Event
First trigger, no goal data Sent Not sent
First trigger, with goal data Sent Sent
Repeat trigger, no force Not sent Not sent
Repeat trigger, force=true, no goal data Not sent Not sent
Repeat trigger, force=true, with goal data Not sent Sent

Note: When forceMultipleTransactions is enabled on a repeat trigger, only the transaction event is sent (revenue is accumulated). The conversion event itself is still deduplicated — it only fires once per visitor per experience.

Tracking Control

trackConversion has no per-call enableTracking parameter. Event delivery is gated on the global tracking flag only:

  • Config-level (ConvertConfiguration.networkTracking): when false at init, no events are ever enqueued.
  • Runtime (sdk.setTrackingEnabled(_:)): a mutable actor-isolated flag for mid-session consent withdrawal.

When tracking is off, the deduplication mark is still written and the SystemEvent.conversion bus event still fires (for local subscribers). Only network delivery is suppressed. See Tracking Control.

Completion-Handler Overload

trackConversion is async with no return value. For UIKit callers that prefer a callback style, wrap it in a Task:

Task {
    await ctx.trackConversion("purchase-completed", goalData: [.amount: .double(49.99)])
}

Clone this wiki locally