Integration guide
Android / Kotlin
Collects user behavior and Custom Events in Android and Kotlin/JVM apps. Install it from Maven Central.
Client SDKRuns in the browser or a mobile app (Event Key)
The Android SDK is a pure Kotlin/JVM JAR with no android.* dependency.
In Android apps, adapt the existing SharedPreferences store to AbtoKeyValueStore
to keep a stable device_id for each installation.
Install
Section titled “Install”The Maven Central badge above shows the current public version. The install command below it is checked against the latest public Android SDK release tag during every Docs build.
Initialize
Section titled “Initialize”Use only an Event Key (ek-abto-…) in the client.
Never put a Calling Key or provider key in the app.
import android.content.Contextimport app.abto.sdk.AbtoClientimport app.abto.sdk.AbtoConfigimport app.abto.sdk.AbtoEnvironment
val abto = AbtoClient( AbtoConfig( projectKey = "ek-abto-…", environment = AbtoEnvironment.PRODUCTION, ), store = SharedPreferencesStore( context.getSharedPreferences("abto", Context.MODE_PRIVATE), ),)
abto.identify("user-123", "tenant-123")abto.capture("checkout_completed", mapOf("order_id" to "order-123"))The second tenantId is optional.
Call abto.reset() on sign-out to clear the user and tenant context and create a new device_id and session.
The persistent store keeps the newly created device_id across later app restarts.
Connect Android’s persistent store
Section titled “Connect Android’s persistent store”import android.content.SharedPreferencesimport app.abto.sdk.AbtoKeyValueStore
class SharedPreferencesStore( private val preferences: SharedPreferences,) : AbtoKeyValueStore { override fun get(key: String): String? = preferences.getString(key, null)
override fun set(key: String, value: String) { preferences.edit().putString(key, value).apply() }}Forward abto.deviceId as x-abto-device-id with the related server request
to connect behavior observed in the app with the Gateway model call.
Join an AI request to response behavior
Section titled “Join an AI request to response behavior”The Mobile SDK does not call a model or the Gateway directly.
Send deviceId and featureId to your application backend.
The backend must validate them, pass them through Server SDK context, and expose
the resulting x-abto-request-id in its response.
The backend side is covered in Node / Server JavaScript and Python.
val trace = abto.startLlmTrace( featureId = "resume.make", taskType = "draft_generation", surface = "editor",)
trace.submitPrompt(prompt = promptText, language = "en")
val backendResponse = callBackend( deviceId = abto.deviceId, featureId = trace.featureId, prompt = promptText,)
trace.attachRequestId(backendResponse.headerFields)trace.markResponseVisible(responseId = "resp-123", timeToVisibleMs = 1_200)trace.captureOutcome(AbtoResponseInteraction.COPIED, responseId = "resp-123")AbtoResponseInteraction exposes the 12 canonical response actions.
The legacy string overload remains source-compatible during the 0.x line, but is deprecated and validates at runtime.
Unsupported strings are warned and dropped before enqueueing; use a Custom Event for product-specific actions.
callBackend stands for your application’s existing networking function.
Never send a Calling Key or provider key from the app.
Response events captured after attachRequestId() carry the same $request_id
as the Gateway call.
Flush with the app lifecycle
Section titled “Flush with the app lifecycle”Flush the buffer from an existing lifecycle callback when the app moves to the background. The SDK sends events on a dedicated daemon thread, so the UI thread is never left waiting for delivery.
override fun onStop() { abto.flush() super.onStop()}Failed deliveries return to the internal buffer and retry on the next flush.
Collection and delivery limits
Section titled “Collection and delivery limits”- Custom Properties passed to
capture()do not go through Browser DOM masking. Do not put secrets or raw personal data in properties. - LLM trace prompt and response helpers record
metadata_onlyinformation such as content length instead of the raw text. - Event names cannot be empty, start with
$, or exceed 200 UTF-16 code units. Custom Properties starting with$are omitted. batchSizeaccepts 1 through 100, defaults to 20, and the default flush interval is 5 seconds.- Metric
valuemust be finite with at most 38 integer digits and 12 fractional digits;scaleis limited to 16 characters. An invalid metric is omitted while the event is still sent. - The in-memory delivery buffer holds at most 1,000 events and drops the oldest on overflow. It retries
408,429,5xx, and per-eventretryresults up to 5 attempts or 30 minutes after first enqueueing, with jittered exponential backoff capped at 2 minutes. - Delivery failures are not thrown into the app. The memory buffer does not survive process termination, so flush before the app enters the background.
How to name events and design Custom Properties is in Event design.