On this page

Android SDK

Add the dependency, call start() once, and the signals below arrive on their own. There is no event taxonomy to design first and no tracking plan to keep up to date.

Published on Maven Central · dev.drengr:analytics-android.

Before you start

Requirements for the Android SDK
RuntimeminSdk 21 (Android 5.0) or newer, compiled against SDK 34.
Permissionsandroid.permission.INTERNET, declared by the SDK's own manifest and merged into yours. You do not need to add it.
Publishable keyConsole, under Settings. It is a publishable key, safe to ship in client code: it can only append events.

Install

kotlin
implementation("dev.drengr:analytics-android:0.2.0")

Start it

In Application.onCreate(). Your publishable key is safe to ship in client code: it can only write.

Application.onCreate()kotlin
// build.gradle.kts: implementation("dev.drengr:analytics-android:0.2.0")val client = OkHttpClient.Builder()    .addInterceptor(        Drengr.start(            context = applicationContext,            publishableKey = "drengr_pk_YOUR_KEY",            ingestUrl = "https://ziryfxrwrvnunwjupgfg.supabase.co/functions/v1/ingest",            appPackage = "com.example.app",        )    )    .build()

What arrives on its own

You do not instrument these. They are captured from the moment start() runs. The third column names the Android API behind each one, so you can check the claim against your own app.

Signals the Android SDK captures automatically, and the platform hook behind each
SignalWhat it recordsWhere it comes from
screen_viewEvery screen or route the user lands onApplication.registerActivityLifecycleCallbacks, on onActivityResumed. Jetpack Navigation and Navigation-Compose can be added with Drengr.trackNavigation()
tapTaps, with the element's own label when it has oneA wrapper around the activity's Window.Callback
net / net_failOutgoing requests: host, path, status, duration, sizeThe OkHttp Interceptor that start() returns, plus an HttpsURLConnection hook
crashUncaught exceptions with their stackThread.setDefaultUncaughtExceptionHandler, chaining the previous handler
rage_tap / dead_tapRepeated taps that did nothing — the friction signalThe same Window.Callback wrapper as tap
rage_scroll / dead_scrollScroll thrash and scrolls that moved nothingThe same Window.Callback wrapper as tap
app_foreground / app_backgroundLifecycle, which is what sessions are built fromApplication.registerActivityLifecycleCallbacks
identifyYour own user id, when you choose to send oneYour own call to Drengr.identify()

Drengr.start() returns an OkHttp Interceptor. Add it to the client your app already uses — requests made through other clients are not captured.

Screen and tap capture attach through the Application lifecycle, so no per-Activity wiring.

What never leaves the device

Emails, phone numbers, card numbers and government ids are detected and sealed on the device before the first byte is sent. Our servers hold ciphertext they cannot open. Labels and URLs are redacted and length-capped on the device too.

And what is never collected in the first place:

What the Drengr SDKs do not collect, and why that is structural
Not collectedHow you can tell
Screen recordings, screenshots or DOM snapshotsThere is no column for pixels or markup on the events table, and no SDK reads the framebuffer.
KeystrokesTap capture records that a tap happened and the element's own accessibility label. No SDK attaches a key or text listener.
Raw request and response bodiesWhat is stored is a safe dotted-path projection, redacted and capped at 64 KiB on the device before anything is sent.
Authorization headers, cookies and API keysMasked by name before capture, along with password, pin, cvv, ssn, otp and iban field names.
An IP address on the eventThe events table has no ip or geo column, so no stored event carries one.
Advertising or cross-app identifiersIdentity is a random install_id the SDK generates. No IDFA, no GAID, and no device fingerprint is used for identity.

Most autocapture tools promise not to look. This is built so we cannot. Full design in Security and Privacy.

Start paused behind a consent gate with Drengr.start(startEnabled = false), then resume once the user agrees. A persisted opt-out always wins over that argument, so an opted-out install stays paused across restarts.

Consent controls on the Android SDK
Start pausedDrengr.start(startEnabled = false)
Opt outDrengr.optOut()
Opt back inDrengr.optIn()
Where the choice is storedSharedPreferences file drengr_sdk, key opt_out

Retention, deletion and what a GDPR or CCPA request maps to are on Privacy controls.

Check it worked

Run the app and use it for a few seconds, then open the console. Overview checks for your first event every 15 seconds on its own, so you do not need to keep reloading.

Nothing showing up

Common reasons no events appear, and how to tell
What you seeMost likely cause
Console stays on “Get your first events in”The key belongs to a different organisation, so the events landed in someone else’s tenant.
Events arrive, but the app you picked looks emptyThe app_package you passed to start() is not the one you are scoped to in the console. Switch the scope, or match the value.
Nothing until you close the appThe first batch flushes on background. Send the app to the background once, or wait for the flush interval.
Taps and network arrive, screens do notScreen capture attaches at start(); check that start() runs before your first screen.
Nothing at all, everstart() is not reached, or it runs after the events you expected. Put it as early as you can and check for a thrown error before it.

Where to go next

Once events are arriving, these are the things worth doing in order.

  • Set up consent and opt-out before you ship to real users.
  • Name your events. Drengr proposes names from the traffic itself; you accept or reject them in the console's review queue.
  • Bring your history across from whatever you use today, so the numbers do not start at zero.

Not ready to install anything?

Drop a .har of traffic you already have and see the business events your current analytics is missing. It runs in your browser; nothing is uploaded.

Scan for blind spots →