Skip to content
ABTO Guide

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.

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.

Use only an Event Key (ek-abto-…) in the client. Never put a Calling Key or provider key in the app.

import android.content.Context
import app.abto.sdk.AbtoClient
import app.abto.sdk.AbtoConfig
import 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.

import android.content.SharedPreferences
import 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.

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 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.

  • 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_only information 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.
  • batchSize accepts 1 through 100, defaults to 20, and the default flush interval is 5 seconds.
  • Metric value must be finite with at most 38 integer digits and 12 fractional digits; scale is 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-event retry results 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.