iOS SDK (Swift) / Identity & analytics

Identity & analytics

The flow reports its own funnel. These calls tell it who the person is and where they came from, so the numbers join up with the rest of your stack.

The calls

swift
import UpliftFunnel

// Install attribution — attached to every subsequent event.
try await UpliftFunnel.setAttribution([
    "network": "meta_ads",
    "campaign": "summer",
    "adgroup": "lookalike_1",
    "creative": "video_a"
])

// After your login. Use the same id your billing stack uses — for
// RevenueCat that is app_user_id — so revenue joins up.
try await UpliftFunnel.identify(
    userId: currentUser.id,
    attributes: ["plan": .string("free"), "signup_source": .string("organic")]
)

// An activation event of your own.
try await UpliftFunnel.track(
    "first_workout_completed",
    properties: ["type": .string("beginner")]
)

// On logout: a fresh anonymous identity, and A/B stickiness resets.
try await UpliftFunnel.resetIdentity()
MethodTypeDescription
identify(userId:attributes:)async throwsAttach the session to a known user. `userId` is a label, not a named parameter's afterthought — use the same id your billing stack uses.
resetIdentity()async throwsLog out: clears the user and starts a fresh anonymous identity, so the next person on the device is a new subject.
track(_:properties:)async throwsA product event alongside the flow's own. Names must match ^[a-z][a-z0-9_:]*$ — an invalid one throws rather than being silently dropped.
setAttribution(_:)async throwsInstall-attribution parameters, attached to every subsequent event.
setTrackingEnabled(_:)Turn analytics on or off at runtime — a consent banner.
flushEvents()asyncSend anything queued now, rather than on the next natural flush.

What the SDK reports on its own

You do not instrument a flow. Every screen entry, every answer, every paywall attempt and its outcome is reported by the engine, which is what the dashboard's per-screen breakdown and drop-off numbers are built from. Reporting never blocks app startup or onboarding, and nothing is lost if the app is killed or the device is offline — the queue is persisted and drains later.

Consent, and what leaves the device

Your code always gets every answer. onCompletedhands you the full variable map — it is your user's data. What follows is only about what reaches the Uplift API.

Mark a variable Private in the dashboard and the SDK reports it as answered, never as its content. Use it for anything that identifies a person or describes their body — name, email, phone, birth date, weight. Leave it off for the bounded answers segmentation runs on (choice, rating, scale, toggle), which keep their values.

swift
// Start with analytics off and turn it on when the user consents.
await UpliftFunnel.configure(
    apiKey: "fnl_pk_…",
    trackingEnabled: false,
    // Redact these whatever the flow says — for a flow you have not
    // re-authored, or for values you pass in via userVariables.
    redactVariables: ["referral_note"]
)

UpliftFunnel.setTrackingEnabled(true)   // consent granted

Turning tracking off drops whatever is already queued rather than holding it. Flows still fetch and render while it is off — gating that on consent would leave you with a blank screen instead of an onboarding. What to declare in App Privacy →