-
Notifications
You must be signed in to change notification settings - Fork 0
CodeExamples
Complete, copy-pasteable examples for every public method of the Convert iOS SDK. All examples use Swift's async/await; completion-handler equivalents are shown where the SDK provides them. All examples assume a single ConvertSwiftSDK instance created at app startup (see Initialization).
import ConvertSwiftSDK
// Key path: fetches config from the CDN.
let sdk = ConvertSwiftSDK(configuration: ConvertConfiguration(sdkKey: "YOUR_SDK_KEY"))
// Key path with options.
let sdk = ConvertSwiftSDK(configuration: ConvertConfiguration(
sdkKey: "YOUR_SDK_KEY",
environment: "prod",
logLevel: .info
))
// Direct-data path: pre-fetched config bytes bypass the CDN.
let sdk = ConvertSwiftSDK(configData: preloadedData)try await sdk.ready()
// Decisions are available from here on.sdk.ready { result in
// Called on the MainActor.
switch result {
case .success:
// SDK is ready.
break
case .failure(let error):
print(error.errorDescription ?? "unknown")
}
}ready() resolves on a successful or degraded load; it throws ConvertError only on an unrecoverable configuration error (empty SDK key, or empty/invalid direct-data). A transient network failure does NOT throw — the SDK resolves degraded.
// Anonymous visitor — auto-generated UUID, persisted in Keychain.
let context = sdk.createContext()
// Explicit visitor ID.
let context = sdk.createContext(visitorId: "visitor-42")
// Explicit visitor ID with initial attributes.
let context = sdk.createContext(
visitorId: "visitor-42",
attributes: ["plan": "premium", "accountAgeDays": 120]
)createContext is synchronous and never blocks; it can be called before ready() resolves. Attribute values must be scalars (String, Int, Double, Bool) — nested dictionaries, arrays, and NSNull are dropped at call time and logged at debug.
if let variation = await context.runExperience("homepage-redesign") {
switch variation.key {
case "control": renderControl()
case "treatment": renderTreatment()
default: renderControl()
}
} else {
renderControl() // SDK not ready, visitor not bucketed, or experience absent
}let variations = await context.runExperiences()
for variation in variations {
applyVariation(variation)
}runExperiences() returns only the experiences the visitor is bucketed into; experiences that fail audience or location rules are excluded. Returns [] when the SDK is not yet ready.
context.runExperiences { variations in
// Called on the MainActor.
for variation in variations {
applyVariation(variation)
}
}// Evaluate but do not report to the network (e.g. consent-denied flow).
let variation = await context.runExperience("homepage-redesign", enableTracking: false)
let variations = await context.runExperiences(enableTracking: false)Bucketing, sticky persistence, audience rules, and the internal bucketing event still fire — only the outbound network event is skipped. See Tracking Control.
let feature = await context.runFeature("checkout-v2")
if feature.status == .enabled {
enableCheckoutV2()
}runFeature is non-optional by contract — it returns Feature.disabled(key:) (not nil) when the SDK is not ready or the feature is absent. It never throws. Unlike the experience API, runFeature has no enableTracking parameter (Android parity).
let feature = await context.runFeature("checkout-v2")
// Typed accessor — returns nil on key miss or type mismatch.
let color = feature.variable("ctaColor", as: String.self) ?? "#0066ff"
let limit = feature.variable("maxItems", as: Int.self) ?? 20
let price = feature.variable("price", as: Double.self) ?? 9.99
let experimental = feature.variable("experimental", as: Bool.self) ?? falseFor JSON variables, read as Data and decode at the call site:
if let raw = feature.variable("config", as: Data.self) {
let decoded = try? JSONDecoder().decode(MyConfig.self, from: raw)
}let features = await context.runFeatures()
for feature in features where feature.status == .enabled {
print("enabled:", feature.key)
}Returns one Feature per entry in the config, in config order. Returns [] when the SDK is not yet ready. No enableTracking parameter (Android parity).
// Bare goal — no transactional data.
await context.trackConversion("signup-completed")
// With goal data.
let data: GoalData = [
.amount: .double(49.99),
.productsCount: .double(3),
.transactionId: .string("tx-42"),
]
await context.trackConversion("purchase-completed", goalData: data)GoalData is [GoalDataKey: GoalDataValue] — use a dictionary literal. Never use a constructor form. trackConversion is async but never throws (AOD-6).
By default the same goal is recorded only once per visitor. For renewals or repeat purchases, bypass dedup with forceMultipleTransactions:
await context.trackConversion(
"purchase-completed",
goalData: [.amount: .double(49.99)],
forceMultipleTransactions: true
)On the repeat call the conversion event is skipped (already recorded), the transaction payload is sent, and the conversion event fires. See Tracking Conversions.
// Six recognised string keys; unknown keys are WARN-logged and ignored.
await context.setDefaultSegments([
"country": "US",
"visitorType": "returning",
"browser": "Chrome",
])Segment fields flow into outbound tracking events and feed audience rules. Each call merges over the visitor's existing segments (overlay semantics — existing recognised keys are overwritten, unset keys are untouched). Fires SystemEvent.segments once.
await context.setCustomSegments(["vip", "beta-tester"])Appends identifiers to the visitor's customSegments list. Backend owns dedup (matching JS SDK behavior). Fires SystemEvent.segments once.
let token = await sdk.on(.conversion) { payload in
// Called each time a conversion is tracked.
print("conversion fired:", payload)
}
// Cancel the subscription.
await sdk.off(token)Pass any SystemEvent case to on(_:callback:). The callback is @Sendable and may be called from any concurrency context — dispatch to MainActor if you need to update the UI:
let token = await sdk.on(.ready) { _ in
Task { @MainActor in updateUI() }
}// Suppress — e.g. on consent withdrawal.
await sdk.setTrackingEnabled(false)
// Re-enable — e.g. on consent re-grant.
await sdk.setTrackingEnabled(true)
// Read the current state.
let isOn = await sdk.isTrackingEnabled()Completion-handler overloads (delivered on MainActor):
sdk.setTrackingEnabled(false) { /* gate is closed */ }
sdk.isTrackingEnabled { isOn in
print("tracking:", isOn)
}When tracking is disabled, no events reach the network, but bucketing and sticky assignment are unaffected. See Tracking Control for the full three-layer consent model.
Forward the AppDelegate background-session callback to the SDK for prompt OS release. This is optional — the SDK recovers persisted events on the next launch regardless.
// In your UIApplicationDelegate:
func application(
_ application: UIApplication,
handleEventsForBackgroundURLSession identifier: String,
completionHandler: @escaping () -> Void
) {
ConvertSwiftSDK.shared?.handleEventsForBackgroundURLSession(
identifier: identifier,
completionHandler: completionHandler
)
}The SDK rejects any identifier it does not own, so passing unrelated session identifiers is safe.
do {
try await sdk.ready()
} catch ConvertError.invalidSdkKey(let detail) {
print("Bad SDK key:", detail)
} catch ConvertError.invalidConfiguration(let detail) {
print("Bad config:", detail)
} catch {
print("Unexpected:", error)
}Only ready() throws. All decisioning and tracking methods degrade silently (return nil, [], or a disabled Feature; log at warn).
- Return Types & Models — what each call returns
-
Configuration — all
ConvertConfigurationparameters - Offline Behavior — what happens to tracked events offline
Copyrights © 2026 All Rights Reserved by Convert Insights, Inc.
Getting Started
iOS SDK
- Quickstart
- Installation
- Initialization
- Configuration
- Return Types & Models
- Code Examples
- Offline Behavior
- Tracking Control
- App Privacy & Data Collection
- Objective-C Interop
Core Concepts
- Experiences & Variations
- Feature Flags
- Bucketing Algorithm
- Rule Evaluation
- Segments
- Data Management
- Event System
- API Communication
How-To Guides
- Running Experiences
- Running Features
- Tracking Conversions
- Visitor Context
- Persistent Storage
- Troubleshooting
Contributing