iOS (Swift)
Install the iOS (Swift) SDK, register installs, track events, and read attribution. Setup takes about 5 minutes.
Requirements
- iOS 14.0+
- Xcode 15+
- Swift 5.9 with structured concurrency (async/await)
Install
Swift Package Manager (recommended) or CocoaPods
// Swift Package Manager. In Xcode: File → Add Package Dependencies…// Or in Package.swift:.package(url: "https://github.com/getappsprint/appsprint-ios-sdk", from: "1.1.7")// CocoaPods. In your Podfile:pod "AppSprintSDK", "~> 1.1.7"
Shipped as a precompiled XCFramework with a bundled PrivacyInfo.xcprivacy manifest. No source code is included.
Published on GitHub (SPM + CocoaPods). Always use the latest version.
Configure
import AppSprintSDK// Call as early as possible. App.init() (SwiftUI) or AppDelegate.didFinishLaunching.Task {await AppSprint.shared.configure(AppSprintConfig(apiKey: "as_live_xxxxx"))}
Non-blocking. configure() returns after restoring local state; install registration runs in a detached Task with exponential backoff. Queued events flush automatically once install completes.
Track events
// Standard eventawait AppSprint.shared.sendEvent(.login)
// Revenue event. Currency must be a 3-letter ISO code.await AppSprint.shared.sendEvent(.purchase, params: ["revenue": 9.99,"currency": "USD"])
// Custom event with parametersawait AppSprint.shared.sendEvent(.custom, name: "level_complete", params: ["level": 5,"score": 1200,])
Read attribution
Once install registration completes, the SDK caches the attribution result from the install response. Native iOS and Android expose synchronous getters; React Native and Flutter bridge calls are asynchronous.
let attr = AppSprint.shared.getAttribution()print(attr?.source) // "apple_ads", "tracking_link", or "organic"print(attr?.isAttributed) // Boolprint(attr?.campaignName) // Campaign name when availableprint(attr?.appleAds?.campaignId)print(attr?.link?.name)
Verify the connection
Send a test event to confirm end-to-end delivery. You should see it in the AppSprint dashboard within seconds.
let result = await AppSprint.shared.sendTestEvent()print("\(result.success) — \(result.message)")
Reference
Configuration options
| Option | Type | Default | Description |
|---|---|---|---|
| apiKey | String | — | Your live API key (starts with as_live_). |
| apiURL | URL | https://api.appsprint.app | Override for staging or self-hosted environments. |
| enableAppleAdsAttribution | Bool | true | Fetches the Apple AdServices token at install time and triggers a delayed attribution refresh 75 seconds later. |
| customerUserId | String? | nil | Your internal user ID. Persists across launches and replays automatically if the first send fails. |
| autoTrackSessions | Bool | true | Fires session_start on configure() and on foreground, debounced to one event per 30 minutes. |
| autoRefreshAttribution | Bool | true | Refetches /v1/sdk/attribution on configure(), foreground, and after a late AdServices PATCH. |
| googleAdsConsent | GoogleAdsConsent? | nil | Reserved for upcoming Google Ads uploads; not used while Google Ads is coming soon. |
| isDebug | Bool | false | Forces logLevel = .debug. |
| logLevel | AppSprintLogLevel | .warn | .debug, .info, .warn, or .error. Routes through os.Logger on iOS 14+. |
Supported event types
session_startloginsign_upregisterpurchasesubscribestart_trialadd_payment_infoadd_to_cartadd_to_wishlistinitiate_checkoutview_contentview_itemsearchsharetutorial_completeachieve_levellevel_startlevel_completecustomUse custom with a name parameter for any event not in this list.
Attribution fields
| Field | Description |
|---|---|
| source | "apple_ads", "tracking_link", or "organic" |
| isAttributed | false for organic installs, true otherwise |
| matchType | Backend match method: apple_ads, idfa, idfv, gaid, ttclid, gclid, gbraid, wbraid, ip_user_agent, or organic |
| campaignName | Signal Campaign name when available |
| link | Signal link object: id, name |
| appleAds | Apple AdServices payload: campaignId, adGroupId, keywordId, countryOrRegion, conversionType |
| utmSource | UTM source from the signal link |
| utmMedium | UTM medium from the signal link |
| utmCampaign | UTM campaign value from the signal link |
API reference
configure(_:)
→ asyncInitializes the SDK. Returns immediately; install registration runs in the background with retry on failure.
await AppSprint.shared.configure(AppSprintConfig(apiKey: "…"))
sendEvent(_:name:params:)
→ asyncEnqueues an event locally and schedules a flush. Does not block on a network round-trip.
await AppSprint.shared.sendEvent(.purchase, params: ["revenue": 9.99, "currency": "USD"])
flush()
→ asyncDrains the queue immediately. Safe to call repeatedly; concurrent flushes are deduplicated.
await AppSprint.shared.flush()
refreshAttribution()
→ AttributionResult?Fetches the latest attribution from /v1/sdk/attribution. Self-heals a 404 install_not_found by re-running install.
let attr = await AppSprint.shared.refreshAttribution()
setCustomerUserId(_:)
→ asyncUpdates the customer user ID. Sent immediately if install is registered; otherwise queued and retried automatically.
await AppSprint.shared.setCustomerUserId("user-123")
getAppSprintId()
→ String?Returns the install ID, or nil before install registration completes.
let id = AppSprint.shared.getAppSprintId()
getAttribution()
→ AttributionResult?Returns the cached AttributionResult. Available synchronously without a network call.
let attr = AppSprint.shared.getAttribution()
getAttributionParams()
→ [String: String]Partner-ready flat payload for forwarding to RevenueCat, Superwall, etc.
let params = AppSprint.shared.getAttributionParams()
enableAppleAdsAttribution()
→ BoolRe-enables Apple Ads at runtime and sends the AdServices token via PATCH. Returns whether the SDK was configured.
AppSprint.shared.enableAppleAdsAttribution()
isInitialized
→ BoolTrue after configure() returns. Does not imply install registration succeeded.
AppSprint.shared.isInitialized
isSdkDisabled()
→ BoolTrue if a 401 or 403 from the backend permanently disabled the SDK.
AppSprint.shared.isSdkDisabled()
sendTestEvent()
→ TestEventResultPosts a diagnostic event and returns (success, message). Use during development.
let result = await AppSprint.shared.sendTestEvent()
clearData()
Wipes local state and the event queue. Use to reset the SDK.
AppSprint.shared.clearData()
Offline behavior
- Events that fail to send are queued in native storage (up to 100 events).
- The queue persists across app restarts.
- Queued events are retried when
configure()completes, when another event is sent, when lifecycle flushes run, or when you callflush(). - If a queued event receives a 401/403, the SDK disables itself and clears the queue.
Platform notes
- configure() is annotated @MainActor and is non-blocking. Calling it from didFinishLaunchingWithOptions or App.init() does not delay app startup.
- ATT must be requested while the app is foreground-active. AppSprintNative.requestTrackingAuthorization() waits for that state internally, so calling it from app init is safe.
- IDFA is collected only when ATT is authorized. If the user grants ATT after install, the SDK PATCHes the IDFA on the next foreground automatically.
- Apple AdServices token fetch (AAAttribution.attributionToken) runs on iOS 14.3+. Failure is non-fatal; a fresh token is fetched on retry.
- The SDK uses URLSession.waitsForConnectivity = true, so transient offline windows queue inside the OS rather than failing fast.
- Background flushes are wrapped in beginBackgroundTask so iOS does not kill the queue worker mid-loop.
Next steps
Troubleshooting
| Problem | What to try |
|---|---|
| getAppSprintId() returns nil | configure() returns before install registration finishes. Wait until isInitialized is true, then poll briefly, or read the value inside an event handler that fires after first launch. |
| Events do not appear in dashboard | Confirm the API key starts with as_live_. Call sendTestEvent() and inspect the returned message. Check Console.app for [AppSprint] logs at debug level. |
| SDK disabled after 401/403 | A rejected key disables the SDK permanently. Call clearData(), then configure() with a valid key. |
| Attribution returns organic when an Apple Ads install was expected | Backend resolution can take up to 75 seconds for Apple AdServices. The SDK refetches automatically by default. If autoRefreshAttribution is off, call refreshAttribution() manually. |
| Queued events seem to never send | A queued event over ~90 KB is dropped on the next flush (the backend caps bodies at 100 KB). Smaller events flush on foreground, background, or another sendEvent. |