iOS Quickstart
Get running with the iOS SDK in 5 minutes
Get the Convert iOS SDK running and serving your first experiment. This page is the fast path; for the conceptual background read Quickstart Overview and How Convert Works first.
You need an SDK Key from your Convert dashboard and an Xcode project targeting iOS 15+, macOS 12+, or tvOS 15+.
1. Add the dependency
Swift Package Manager (preferred)
In Xcode, choose File ▸ Add Package Dependencies…, enter the URL below, and add the ConvertSwiftSDK product to your app target:
https://github.com/convertcom/ios-sdk.git
Or add it to Package.swift:
// Package.swift
dependencies: [
.package(url: "https://github.com/convertcom/ios-sdk.git", from: "1.0.0")
],
targets: [
.target(name: "MyApp", dependencies: [
.product(name: "ConvertSwiftSDK", package: "ios-sdk")
])
]CocoaPods
# Podfile
pod 'ConvertSwiftSDK', '~> 1.0'Then run pod install and open the generated .xcworkspace. ConvertSwiftSDK pulls ConvertSwiftSDKCore transitively — you only name ConvertSwiftSDK.
See Installation for toolchain requirements and the privacy manifest.
2. Initialize once at app startup
ConvertSwiftSDK owns a background URLSession, an offline event queue, and a config-refresh scheduler, so create exactly one instance per process.
SwiftUI
import SwiftUI
import ConvertSwiftSDK
@main
struct MyApp: App {
let sdk = ConvertSwiftSDK(configuration: ConvertConfiguration(
sdkKey: "YOUR_SDK_KEY" // from your Convert dashboard
))
var body: some Scene {
WindowGroup {
ContentView()
.task {
try? await sdk.ready()
}
.environmentObject(sdk) // or pass `sdk` down however your app shares singletons
}
}
}UIKit AppDelegate
import UIKit
import ConvertSwiftSDK
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var sdk: ConvertSwiftSDK!
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
sdk = ConvertSwiftSDK(configuration: ConvertConfiguration(
sdkKey: "YOUR_SDK_KEY", // from your Convert dashboard
logLevel: .info // use .debug while integrating
))
return true
}
}3. Await config, then run an experience
The SDK fetches its bucketing config in the background. await sdk.ready() suspends until decisions are available; runExperience called before that returns nil.
// async/await (in a Task or async function)
try await sdk.ready()
let ctx = sdk.createContext() // auto-persisted UUID visitor ID
if let variation = await ctx.runExperience("homepage-redesign") {
switch variation.key {
case "control":
renderControl()
case "treatment":
renderTreatment()
default:
renderControl()
}
} else {
renderControl() // nil = not ready / visitor not bucketed — not an error
}Completion-handler style (UIKit / callback call sites)
sdk.ready { result in
// Delivered on MainActor
guard case .success = result else { return }
let ctx = self.sdk.createContext()
Task { @MainActor in
if let variation = await ctx.runExperience("homepage-redesign") {
self.applyVariation(variation.key)
}
}
}4. Track a conversion
// Bare conversion (deduped per visitor + goal automatically).
await ctx.trackConversion("signup-completed")
// With revenue goal data.
await ctx.trackConversion(
"purchase-completed",
goalData: [.amount: .double(49.99), .transactionId: .string("tx-42")]
)
// Force a second transaction entry for a repeat purchase (conversion event stays deduped).
await ctx.trackConversion(
"purchase-completed",
goalData: [.amount: .double(29.99)],
forceMultipleTransactions: true
)trackConversion is async but never throws. Events are batched, persisted to disk, and flushed in the background — they survive the device going offline and an app restart. An unknown goal key logs a [WARN] and is silently dropped. See Offline Behavior.
Next steps
- Initialization —
ready(), direct-data mode, event subscription, AppDelegate wiring - Configuration Options — every
ConvertConfigurationparameter - Code Examples — complete Swift snippets for every method
- Running Experiences — the cross-SDK guide