Server-side A/B testing, feature flags, and personalisations for Android applications — the native Kotlin/Java client for the Convert Experiences platform. Decisions are resolved on-device from a cached bucketing config; tracking events are batched, persisted to disk, and flushed in the background via WorkManager so nothing is lost when the network is down.
- Kotlin-first (Java interop via
@JvmOverloads+ SAM-convertiblefun interfacecallbacks) - Offline-safe (SQLite queue + WorkManager exponential backoff)
- Privacy-aware (app-scoped UUID only — no device identifiers, no PII)
- JS-SDK parity (same bucketing hash, same wire format)
// settings.gradle.kts — make sure Maven Central is declared
dependencyResolutionManagement {
repositories {
mavenCentral()
google()
}
}
// packages/app/build.gradle.kts (or your app module)
dependencies {
implementation("com.convert:sdk-android:+")
}Latest released version: see the Maven Central badge above. Replace + with the version you want to pin.
import android.app.Application
import com.convert.sdk.android.ConvertSDK
import com.convert.sdk.core.model.LogLevel
class MyApp : Application() {
lateinit var convertSdk: ConvertSDK
override fun onCreate() {
super.onCreate()
convertSdk = ConvertSDK.builder(this)
.sdkKey("YOUR_SDK_KEY") // from your Convert dashboard
.logLevel(LogLevel.INFO) // optional; DEBUG for integration work
.build()
}
}Register the class in your AndroidManifest.xml:
<application android:name=".MyApp" ... />The SDK fetches its bucketing config in the background. Use onReady { ... } to be notified when decisions become available.
val sdk = (application as MyApp).convertSdk
sdk.onReady {
val ctx = sdk.createContext() // auto-persisted UUID visitor id
val variation = ctx.runExperience("homepage-redesign")
when (variation?.key) {
"control" -> renderControl()
"treatment" -> renderTreatment()
null -> renderControl() // SDK not ready yet / visitor not bucketed
}
}import com.convert.sdk.core.model.GoalData
import com.convert.sdk.core.model.GoalDataKey
import kotlinx.serialization.json.JsonPrimitive
val ctx = sdk.createContext()
// Bare conversion.
ctx.trackConversion("signup-completed")
// With transactional goal data.
ctx.trackConversion(
goalKey = "purchase-completed",
goalData = listOf(
GoalData(key = GoalDataKey.AMOUNT, value = JsonPrimitive(49.99)),
GoalData(key = GoalDataKey.TRANSACTION_ID, value = JsonPrimitive("tx-42")),
),
)That's it. Everything else is in the Quickstart guide.
| Toolchain | Minimum |
|---|---|
| JDK (build) | 17 |
| Android API (runtime) | 24 (Android 7.0) |
| Android API (compile) | 35 |
| Kotlin | 2.x (binary-compatible with any 2.x consumer) |
| Gradle | 8.x |
For best offline-recovery behaviour, declare ACCESS_NETWORK_STATE in your app's manifest — the SDK uses it to trigger a queue flush when connectivity returns. If the permission is missing the SDK degrades gracefully (the foreground retry path still delivers events; only the "flush-on-network-regained" push is skipped).
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />Release notes are published as GitHub Releases on every release-triggering merge to main — each on its vX.Y.Z tag with conventional-commit-grouped notes generated by semantic-release. The Maven Central listing also carries the full version history per artifact.
- Wiki — full documentation: Quickstart, Installation, Initialization, and Configuration, plus feature flags, running experiences, conversion tracking, segmentation, offline behaviour, Data Safety, Java interop, and troubleshooting
- API Reference — published by the release pipeline as the Javadoc JAR alongside every Maven Central release
- Release Process — how the release pipeline works, one-time setup for the repo admin
- Triggering a Release — conventional commits drive every release
For production issues, open a ticket via your Convert dashboard. For bugs in this SDK, open a GitHub issue with a minimal reproducer.
Copyright (c) 2026 Convert Insights, Inc. Licensed under the Apache License, Version 2.0.