Skip to content
anecticoDocsDashboard
Browse documentation
Guide

Android

Capture Android identity, events, errors, crashes, and backend request context.

On this page

The native Kotlin SDK supports Android minSdk 24 and has no third-party runtime dependency. During early access, add the artifact and repository configuration supplied during onboarding.

Add the dependency

During early access, copy the supplied AAR into your app module's libs/anectico-sdk.aar, then add:

dependencies {
    implementation(files("libs/anectico-sdk.aar"))
    // Optional when using the Anectico OkHttp interceptor:
    implementation("com.squareup.okhttp3:okhttp:4.12.0")
}

After the public Maven release, replace the local AAR with the exact published com.anectico:sdk:<version> coordinate supplied for your release.

The SDK's INTERNET permission is merged into the application manifest.

Initialize once

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        Anectico.init(
            this,
            AnecticoOptions(
                apiKey = BuildConfig.ANECTICO_API_KEY,
                environment = "production",
                release = "com.acme.shop@2.4.1+241",
                dist = "241",
                enableCrashReporting = true,
                debug = BuildConfig.DEBUG,
            ),
        )
    }
}

serviceName defaults to the application ID and serviceVersion to versionName.

init reports failure rather than absorbing it — IllegalArgumentException for invalid configuration, AnecticoInitException (with the cause) for anything else that stops setup — so an app that starts is an app whose telemetry is really running. Methods called before a successful init record and send nothing: a debug build throws AnecticoNotInitializedException at the call site, and a release build logs the first one at ERROR. See the Android SDK API reference.

Use a project-scoped key with ingest:write and analytics:write. Do not include read, management, or agent scopes in the application.

Connect identity and events

Anectico.identify("user_8842", mapOf("email" to "buyer@acme.example", "plan" to "pro"))
Anectico.group("company", "acme", mapOf("plan" to "enterprise"))
Anectico.capture("checkout_started", mapOf("cart_size" to 3))
Anectico.screen("Checkout")
Anectico.captureLog(
    "checkout prepared for offline sync",
    severity = "info",
    attributes = mapOf("items" to 3),
)

// On logout:
Anectico.reset()

reset also clears global error-user context and buffered breadcrumbs, preventing the prior account's diagnostic context from attaching to the next account on a shared device.

Every captured event — not only the automatic $app_opened/$app_backgrounded lifecycle events — carries the reserved $release and $app_version properties, sourced from the same release/serviceVersion you pass to AnecticoOptions (or versionName when you don't set them explicitly). Neither is invented: an app that never configures a release sends events with neither property. See Reserved event properties.

captureLog sends OTLP logs to /v1/logs with the current customer/session and Android app/device/release context. Logs are atomically persisted before delivery, retain their occurrence time and stable anectico.log.id across process recreation, and retry network/429/5xx failures in oldest-first order. Anectico.flush flushes both events and logs.

maxQueueSize is applied separately: the SDK can retain that many diagnostic events and that many logs, rather than splitting one count between them. The log spool also drops oldest past 10 MiB.

Capture errors and upload mappings

try {
    checkout()
} catch (error: Exception) {
    Anectico.captureError(error, CaptureOptions(tags = mapOf("screen" to "checkout")))
}

Anectico classifies explicit captureError calls as severity error, handled, with mechanism java.caught_exception. The uncaught-exception handler classifies fatal crashes as severity fatal, unhandled, with mechanism java.uncaught_exception. Those values are SDK-owned and cannot be replaced by capture tags; unrelated application tags still appear on the occurrence.

The occurrence also includes SDK-owned app version/build, Android model and OS version, and Anectico SDK/platform context for Issue Story. These are shared runtime descriptors, not physical-device identifiers; the SDK never collects Android ID, serial number, installation ID, or the user-assigned device name.

Fatal exceptions and failed manual error sends are spooled and retried on the next launch. Upload the exact R8/ProGuard mapping for the captured release and dist:

anectico symbols upload-proguard mapping.txt --release "$RELEASE" --dist "$DIST"

The Issue Story identifies missing or mismatched mappings beside the raw R8 frames and shows the exact release/distribution keys to upload. An empty distribution is a real key; preserve it with --dist ''. After a mapping resolves, each recovered Original source entry remains paired with a Raw frame line containing the captured obfuscated function and location; R8 inline entries repeat that raw evidence in mapping order. The upload key requires errors:write.

Propagate to your backend

For OkHttp:

val client = OkHttpClient.Builder()
    .addInterceptor(com.anectico.sdk.okhttp.AnecticoInterceptor())
    .build()

For HttpURLConnection, call AnecticoPropagation.apply(connection). Send these headers only to trusted application services.

Verify

Identify a test user, capture one event and caught error, call Anectico.flush, and confirm the evidence shares one customer. Test a fatal crash only in a safe test build, then relaunch so the spool drains.