Open-source Real User Monitoring (RUM) SDK for Android, built on OpenTelemetry. Exports telemetry via standard OTLP/HTTP — works with Last9, Jaeger, Grafana Tempo, or any OTLP-compatible backend.
- App startup tracking — cold and warm start times via OTel Android agent
- Crash reporting — unhandled exceptions captured as error spans with stack traces
- ANR detection — main thread blocked >5s reported as spans
- OkHttp instrumentation — automatic CLIENT spans with W3C
traceparentinjection for distributed tracing - Session tracking — automatic session lifecycle management
- Custom spans — manual instrumentation API for business logic
The SDK is not yet published to Maven Central. For now, use a local build or JitPack:
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
maven("https://jitpack.io")
}
}
// app/build.gradle.kts
dependencies {
implementation("com.github.last9:android-kotlin-rum:<version>")
}import android.app.Application
import io.last9.android.rum.Last9
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
Last9.init(this) {
token = "<your-auth-token>"
serviceName = "my-android-app"
baseUrl = "https://your-otlp-endpoint.com"
useStandardEndpoint = true
useBasicAuth = true
// Optional
deploymentEnvironment = "production"
serviceVersion = BuildConfig.VERSION_NAME
}
}
}Register in AndroidManifest.xml:
<application android:name=".MyApp" ... />val rum = Last9.getInstance()
val httpClient = OkHttpClient.Builder()
.addInterceptor(rum.createOkHttpInterceptor())
.build()This automatically creates spans for every HTTP request and injects traceparent headers for distributed tracing across your backend services.
val tracer = Last9.getInstance().getTracer()
val span = tracer.spanBuilder("checkout.confirm").startSpan()
try {
processCheckout()
} catch (e: Exception) {
span.recordException(e)
throw e
} finally {
span.end()
}Enable debug logging temporarily:
Last9.init(this) {
// ...
debugMode = true
}Check Logcat for Last9SpanExporter and Last9AgentConfigurator tags.
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
token |
String | Yes | — | Auth token for the OTLP endpoint |
serviceName |
String | Yes | — | Identifies your app in the backend |
baseUrl |
String | Yes | https://otlp.last9.io |
OTLP endpoint base URL |
useStandardEndpoint |
Boolean | No | false |
Use /v1/traces path (recommended for most setups) |
useBasicAuth |
Boolean | No | false |
Send Authorization: Basic header instead of X-LAST9-API-TOKEN |
deploymentEnvironment |
String | No | "" |
deployment.environment resource attribute |
serviceVersion |
String | No | "" |
service.version resource attribute |
enableCrashReporting |
Boolean | No | true |
Capture unhandled exceptions |
enableAnrDetection |
Boolean | No | true |
Detect Application Not Responding events |
enableOkHttpInstrumentation |
Boolean | No | true |
Enable createOkHttpInterceptor() |
debugMode |
Boolean | No | false |
Log span exports to Logcat |
additionalResourceAttributes |
Map | No | {} |
Extra OTel resource attributes on every span |
Don't embed backend credentials in your APK. Route telemetry through your own proxy:
App ──► Your Proxy ──► OTLP Backend
(holds real (Last9, Jaeger,
credentials) Tempo, etc.)
Last9.init(this) {
serviceName = "my-android-app"
token = "<your-app-session-token>" // your own auth, not backend creds
baseUrl = "https://telemetry.yourco.com" // your proxy
useStandardEndpoint = true
useBasicAuth = false // proxy handles backend auth
}The proxy validates the caller, injects backend credentials, and forwards the OTLP payload. See how Datadog recommends this pattern for mobile apps.
Requirements: JDK 11+, Android SDK (API 36), Android Studio Ladybug or later.
git clone https://github.com/last9/android-kotlin-rum.git
cd android-kotlin-rum
# Run unit tests
./gradlew :rum-sdk:test
# Build the SDK AAR
./gradlew :rum-sdk:assembleRelease
# Run the example app (device/emulator required)
./gradlew :example:installDebugThe AAR is output to rum-sdk/build/outputs/aar/.
Last9.init(app) { ... }
│
├── Last9Options ← Configuration DSL
├── AgentConfigurator ← Wires OTel Android agent
│ ├── ExporterFactory ← OTLP/HTTP span exporter
│ ├── Last9SpanExporter ← Debug logging wrapper
│ └── ResourceAttributeBuilder ← device/OS/SDK attributes
└── Last9RumInstance ← Public handle
├── getTracer()
└── createOkHttpInterceptor()
Key dependencies:
- OpenTelemetry Android v1.0.1 — crash, ANR, startup, session instrumentation
- OpenTelemetry Java v1.57.0 — OTLP exporter, SDK, API
- OkHttp 4.12.0 (
compileOnly— apps bring their own version)
| Version | |
|---|---|
| Minimum SDK | API 26 (Android 8.0) |
| Compile SDK | API 36 |
| Kotlin | 2.1+ |
| Java target | 11 |
Contributions are welcome. Please open an issue first to discuss what you'd like to change.
# Fork and clone
git clone https://github.com/<you>/android-kotlin-rum.git
# Create a branch
git checkout -b my-feature
# Make changes, run tests
./gradlew :rum-sdk:test
# Push and open a PR
git push origin my-featureApache License 2.0 — see LICENSE for details.