Android (Kotlin)
Install the Android (Kotlin) SDK, register installs, track events, and read attribution. Setup takes about 5 minutes.
Requirements
- Android 7.0+ (API 24+)
- compileSdk 36+
- Java 17 (Kotlin 2.0+ for source builds)
Install
Maven Central
// app/build.gradle.ktsdependencies {implementation("app.appsprint:sdk:1.1.2")}
Sync Gradle after adding the dependency. The SDK already declares INTERNET, ACCESS_NETWORK_STATE, and com.google.android.gms.permission.AD_ID, so you do not need to add them to your manifest.
Published on Maven Central. Always use the latest version.
Configure
import com.appsprint.sdk.AppSprintimport com.appsprint.sdk.AppSprintConfigclass MyApplication : Application() {override fun onCreate() {super.onCreate()AppSprint.shared(applicationContext).configure(AppSprintConfig(apiKey = "as_live_xxxxx"))}}
Non-blocking. configure() returns immediately; install registration and device-info collection run off the main thread on the SDK's executor. The lifecycle observer is registered automatically.
Track events
// Standard eventval appSprint = AppSprint.shared(applicationContext)appSprint.sendEvent(AppSprintEventType.LOGIN)
// Revenue event. Currency must be a 3-letter ISO code.appSprint.sendEvent(AppSprintEventType.PURCHASE,params = mapOf("revenue" to 9.99, "currency" to "USD"))
// Custom event with parametersappSprint.sendEvent(AppSprintEventType.CUSTOM,name = "level_complete",params = mapOf("level" to 5, "score" to 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.
val attr = appSprint.getAttribution()println(attr?.source) // "apple_ads", "tracking_link", or "organic"println(attr?.isAttributed) // Booleanprintln(attr?.campaignName) // Campaign name when availableprintln(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.
val result = appSprint.sendTestEvent()println("${result.success} — ${result.message}")
Reference
Configuration options
| Option | Type | Default | Description |
|---|---|---|---|
| apiKey | String | — | Your live API key (starts with as_live_). |
| apiUrl | String | https://api.appsprint.app | Override for staging or self-hosted environments. |
| enableAppleAdsAttribution | Boolean | false | iOS-only. Ignored on Android. |
| customerUserId | String? | null | Your internal user ID. Persists across launches and replays automatically if the first send fails. |
| autoTrackSessions | Boolean | true | Fires session_start on configure() and on ProcessLifecycleOwner.ON_START, debounced to one event per 30 minutes. |
| autoRefreshAttribution | Boolean | true | Refetches /v1/sdk/attribution on configure() and foreground transitions. |
| googleAdsConsent | GoogleAdsConsent? | null | Reserved for upcoming Google Ads uploads; not used while Google Ads is coming soon. |
| isDebug | Boolean | false | Forces logLevel = 0 (debug) and enables the optional debug overlay. |
| logLevel | Int | 2 (WARN) | 0 = DEBUG, 1 = INFO, 2 = WARN, 3 = ERROR. |
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(config)
Initializes the SDK. Returns immediately; install registration and lifecycle wiring run on the SDK executor.
appSprint.configure(AppSprintConfig(apiKey = "…"))
sendEvent(type, name?, params?)
Enqueues an event locally and schedules a flush.
appSprint.sendEvent(AppSprintEventType.PURCHASE, params = mapOf("revenue" to 9.99, "currency" to "USD"))
flush()
Drains the queue immediately.
appSprint.flush()
refreshAttribution()
→ AttributionResult?Fetches the latest attribution. Blocking; call from a background thread. Self-heals on 404 install_not_found.
val attr = appSprint.refreshAttribution()
setCustomerUserId(id)
Updates the customer user ID. Persists to disk and retries on the next configure() or foreground if the first send fails.
appSprint.setCustomerUserId("user-123")
getAppSprintId()
→ String?Returns the install ID, or null before install registration completes.
val id = appSprint.getAppSprintId()
getAttribution()
→ AttributionResult?Returns the cached AttributionResult.
val attr = appSprint.getAttribution()
getAttributionParams()
→ Map<String, String>Partner-ready flat payload for forwarding to RevenueCat, Superwall, etc.
val params = appSprint.getAttributionParams()
enableAppleAdsAttribution()
→ BooleanReturns false on Android. Apple Ads attribution is iOS-only.
appSprint.enableAppleAdsAttribution()
isInitialized()
→ BooleanTrue after configure() returns.
appSprint.isInitialized()
isSdkDisabled()
→ BooleanTrue if a 401 or 403 permanently disabled the SDK.
appSprint.isSdkDisabled()
sendTestEvent()
→ TestEventResultPosts a diagnostic event off the main thread. From the main thread, use sendTestEventAsync(callback).
val result = appSprint.sendTestEvent()
clearData()
Wipes local state and the event queue.
appSprint.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 thread-safe (@Synchronized) and returns immediately. Safe to call from Application.onCreate() or an activity.
- Apple Search Ads attribution is iOS-only. enableAppleAdsAttribution is accepted for cross-platform symmetry but does nothing on Android.
- GAID is read during install registration only, off the main thread. The SDK honors Limit Ad Tracking and drops the all-zero advertising ID so a bogus value never reaches the backend.
- Play Install Referrer is collected automatically. The package visibility entry for com.android.vending is in the SDK manifest, so it works on apps targeting Android 11+.
- If your app cannot collect advertising IDs (children's apps, regional policies), remove com.google.android.gms.permission.AD_ID in your host manifest with tools:node="remove".
- Events persist in SharedPreferences. They flush on foreground (ProcessLifecycleOwner.ON_START), background, the next sendEvent, or an explicit flush() call.
Next steps
Troubleshooting
| Problem | What to try |
|---|---|
| getAppSprintId() returns null | configure() returns before install registration finishes. Check isInitialized() and retry 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 result. Lower logLevel to 0 and check logcat under the AppSprint tag. |
| SDK disabled after 401/403 | A rejected key disables the SDK permanently. Call clearData(), then configure() with a valid key. |
| Events lost after app kill | Events persist to SharedPreferences and retry delivery on the next configure(). If they still do not appear, the queue may have been dropped by clearData() or hit the 100-entry cap. |
| AD_ID permission rejected by Play review | Either include advertising ID collection in your Data safety answers, or remove the permission with tools:node="remove" in your host manifest. |