Skip to the page
Docs
Kotlin (Android)

Docs SDKs

Version 0.x

Kotlin (Android)

For native Android apps, minSdk 24. No Google Play services, no dependencies, about 65 KB. Compose screens come in a second, optional library.

Install

Kotlin
// app/build.gradle.kts
implementation("fyi.apparent:apparent-android:0.2.0")

With Compose, add the screens library too (same version, also on Maven Central):

app/build.gradle.kts
implementation("fyi.apparent:apparent-compose:0.2.1")

Optional: Play's install referrer library, so Apparent knows which link brought each install.

app/build.gradle.kts
implementation("com.android.installreferrer:installreferrer:2.2")

Start it

In your Application class's onCreate:

Kotlin
import fyi.apparent.Apparent

Apparent.start(this, app = "<app id>", key = "<write key>", apiUrl = "https://in.apparent.fyi")

Add disabled = BuildConfig.DEBUG if debug builds shouldn't send. Emulators and Google's test phones are left out of the numbers by themselves.

Screens

Compose (the apparent-compose library), at the top of each screen:

Kotlin
@Composable fun Paywall() { TrackScreen("paywall"); /* … */ }

Jetpack Navigation, once:

Kotlin
val entry by navController.currentBackStackEntryAsState()
TrackNavigation(entry?.destination?.route)   // "practice/{topic}" → "practice/[topic]"

Without Compose: Apparent.screen("paywall"), or ApparentConfig(…, trackActivities = true) for one screen per Activity.

Events and users

Kotlin
Apparent.track("paywall_view", mapOf("source" to "onboarding"))
Apparent.setProperties(mapOf("plan" to "free"))   // on every later event; null removes one
Apparent.identify(user.id)                        // after sign-in
Apparent.logout()                                 // on sign-out

Calls work from any thread and never block the main thread. More in Events and users.

Purchases

Kotlin
Apparent.linkRevenueCat { Purchases.sharedInstance.setAttributes(it) }   // with RevenueCat
Apparent.trackPurchase("pro_yearly", 29.99, "EUR")                       // Play Billing, without RevenueCat

The link (App Link or your own scheme) or Firebase notification tap that launches an Activity is sent on its own, as deep_link_opened and push_opened. For the ones that bring a running Activity back, pass the Intent on:

Kotlin
override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    setIntent(intent)
    Apparent.handleIntent(intent)
}

Notifications you show yourself (a Firebase message while the app is open, a local notification): Apparent.trackPushOpened(message.data, message.messageId) when it's tapped. Links you route yourself: Apparent.trackDeepLink(url).

  • Secrets in a link (token, code, password, key, auth, session, sig…) are sent as [redacted], and utm_source, utm_medium, utm_campaign come out as their own fields. A campaign link that opens the app on its first day counts as where that person came from.
  • push_opened carries only campaign (or utm_campaign) and title from the notification's data, never what it said.
  • Off: ApparentConfig(…, trackDeepLinks = false, trackPushOpens = false).

Your own filter

beforeSend sees every event before it is saved. Return it changed, or null to drop it:

Kotlin
Apparent.start(this, ApparentConfig(app = "einb", key = "…", beforeSend = { event ->
    if (event.name == "debug_tap") null
    else event.copy(properties = event.properties?.minus("email"))
}))

If it throws, the event is kept as it was.

Errors and opting out

  • Uncaught exceptions are saved before the app goes down and sent on the next launch.
  • Errors you catch: Apparent.captureError(e).
  • Apparent.optOut() / Apparent.optIn(), remembered.
  • Ask for consent first? Start with ApparentConfig(…, optOutByDefault = true) and call Apparent.optIn() once they agree. Nothing is collected before that.
  • Nothing showing up? In a debug build the SDK prints Apparent: app id or key is wrong — events are not being saved once when the app id or key doesn't match. Copy both again from Connect.
  • Simulators and emulators say so themselves (simulator in each batch), so they're never counted, even in a release build.

Good to know

  • The SDK never reads the advertising id, so you don't need the AD_ID permission.
  • Its state lives in noBackupFilesDir: a phone restored from a backup counts as a new install.
  • R8 rules come with the library.
  • It never throws into your app: a start without an app id or key is ignored with a Logcat warning, and odd property values (dates, big numbers, lists) are turned into plain ones.
  • Data safety answers: Privacy answers.

Updated 2026-10-24 · Markdown · Report a mistake