A/B testing, feature flags, segmentation, and conversion tracking for iOS, iPadOS, tvOS, and macOS.
import ConvertSwiftSDK
let sdk = ConvertSwiftSDK(configuration: ConvertConfiguration(sdkKey: "your-sdk-key"))
try await sdk.ready() // gates decisioning
let context = sdk.createContext() // visitorId optional → persistent auto-UUID
if let variation = await context.runExperience("pricing-test") {
print(variation.key) // switch your UI on the key, e.g. "variant-a"
}
await context.trackConversion("purchase-goal", goalData: [.amount: .double(49.99)])In Xcode, choose File ▸ Add Package Dependencies…, enter the package URL, and add the ConvertSwiftSDK product to your target.
Or add it to Package.swift:
dependencies: [
.package(url: "https://github.com/convertcom/ios-sdk.git", from: "1.0.0")
]Then list ConvertSwiftSDK in your target's dependencies.
Add the pod to your Podfile:
pod 'ConvertSwiftSDK', '~> 1.0'Then run pod install. ConvertSwiftSDK pulls ConvertSwiftSDKCore transitively — you only name ConvertSwiftSDK.
iOS 15+, macOS 12+, tvOS 15+. iPadOS rides the iOS target.
ready() gates decisioning. Everything else is order-independent.
Call ready() once after construction and await it before deciding. runExperience / runFeature called before ready() resolves return a degraded result — nil from runExperience, a disabled Feature from runFeature — never a crash. Once ready() returns, the cached config drives every subsequent decision with no further network.
A nil variation also covers the visitor being ineligible or the experience key being unknown. None of these are errors. ready() is the only call that throws, and only on an unrecoverable configuration error such as an empty SDK key.
The SDK ships three independent delivery controls:
- Static (init-time): set
ConvertConfiguration.networkTracking = falsebefore constructing the SDK to suppress all events for the session. - Per-call: pass
enableTracking: falsetorunExperience(_:enableTracking:)to bucket without emitting that one exposure event. - Runtime (mid-session): call
setTrackingEnabled(_:)after initialization — the supported path for GDPR consent withdrawal.
// Opt out at runtime (e.g. on consent withdrawal):
await sdk.setTrackingEnabled(false)
// Opt back in (suppressed events are not replayed):
await sdk.setTrackingEnabled(true)
// Read the current state:
let isOn = await sdk.isTrackingEnabled()Completion-handler twins exist for callback-style call sites:
sdk.setTrackingEnabled(false) {
// called on MainActor when the gate is closed
}
sdk.isTrackingEnabled { isOn in
// called on MainActor with the current flag
}- doc:GettingStarted — the linear install → init → ready → context → decide → track path.
- doc:OfflineAndBackgroundDelivery — how decisions and queued bucketing events behave offline and after the app is suspended.
- doc:FailureDetection — detecting a failed or slow start.
- doc:Privacy — the privacy manifest, visitor-identity guidance, and all delivery controls.
The full guide and the symbol-level API reference are the DocC articles in Sources/ConvertSwiftSDK/ConvertSwiftSDK.docc/.