Skip to content

Android SDK

Capture events from Android apps — identity, sessions, persistence, feature flags and surveys under the shared SDK spec.

azfive-android brings AZ-Five product analytics to Android: events, identity, sessions, persistence, feature flags & experiments, and surveys, under the shared behavioral spec. minSdk 21.

Install

The package resolves through JitPack:

repositories {
    maven("https://jitpack.io")
}

dependencies {
    implementation("com.github.az-five:azfive-android:v0.1.0")
}

Honest packaging note: the published coordinate currently carries the core module only — the full analytics client (events, identity, sessions, flags, exposure dedup) as a pure-Kotlin JAR. The Android bindings layer — the AzFive.init(context, …) singleton, SharedPreferencesStore persistence, lifecycle flush-on-background, optional az.screen_view autocapture, and the SurveyBottomSheet renderer — lives in the SDK’s :android module, which isn’t separately installable from JitPack yet. Until it is, build that module from github.com/az-five/azfive-android; the core artifact alone works, but persistence defaults to in-memory (identity won’t survive restarts until you plug a Store into the config).

Initialize

Create a public ingest token with “Mobile app token” enabled (Settings → API Keys → Public Ingest Tokens) — native requests carry no browser Origin, and tokens without that flag fail closed.

With the :android bindings, initialize once in Application.onCreate():

val azfive = AzFive.init(this, "azfive_pub_…", host = "https://app.az-five.com")

AzFive.init wires SharedPreferencesStore, platform properties, and lifecycle flush automatically; AzFive.shared() returns the singleton anywhere. Core-only, construct the client directly:

val azfive = AzFiveClient(
    AzFiveConfig(
        token = "azfive_pub_…",
        host = "https://app.az-five.com",
        // store = <your Store implementation> — defaults to InMemoryStore
    )
)

Capture events

azfive.capture("signed_up", mapOf("plan" to "pro"))
azfive.screen("Checkout")   // az.screen_view + survey eligibility re-check

// Super properties — merged into every event
azfive.register(mapOf("deployment" to "eu-1"))

With the bindings, AzFive.init(…, autocaptureScreens = true) emits az.screen_view automatically from activity lifecycle callbacks.

Identify & person properties

azfive.identify("ava@example.com", mapOf("plan" to "pro"))
azfive.alias("legacy-77")
azfive.peopleSet(mapOf("favorite_color" to "teal"))
azfive.peopleSetOnce(mapOf("signup_date" to "2026-08-01"))

// on logout:
azfive.reset()   // new anonymous id; reset(resetDeviceId = true) also rotates the device id

identify merges the anonymous session into the person (az.identify with $anonymous_id) and refetches flags. Opt-out controls — optIn() / optOut() / hasOptedOut() — drop events at capture time, persist, and survive reset().

Feature flags

Flags load from /v1/decide on init, persist for stale-while-revalidate startup, and refresh on identify() / reset():

azfive.onFlags {
    val variant = azfive.getFlag("exp-checkout")   // "control" | "test" | false | null
    if (azfive.isFlagEnabled("new-billing")) {
        val payload = azfive.getFlagPayload("new-billing")  // no exposure event
    }
}
azfive.reloadFlags()   // force a refetch

getFlag and isFlagEnabled capture an az.flag_called exposure automatically, deduped per session:flag:value. getFlagPayload never does.

Surveys

Decide-delivered surveys are driven by azfive.surveys (a SurveyCoordinator in core: selection on screen() changes, per-survey suppression, question branching, and the az.survey_shown / az.survey_dismissed / az.survey_sent events). With the :android bindings, render them with the Material bottom sheet:

// in your single-activity host (detach in onDestroy)
val detach = SurveyBottomSheet.attach(this, azfive.surveys)

Or build your own UI on azfive.surveys.addListener(...) + advance(questionId, response) / dismiss().

Flush & shutdown

Delivery is automatic (10 events / 5 s); with the bindings, the queue also flushes when the last activity stops. flush() forces delivery; the client is AutoCloseableclose() flushes and stops the worker.

Reference

AzFiveConfig (core)

ParameterDefaultNotes
tokenrequiredPublic token (azfive_pub_…) with “Mobile app token” enabled
hostrequiredAZ-Five deployment base URL
project"default"Target project slug
batchSize10Queue length that triggers a flush
flushIntervalMs5000Background flush period
maxQueueSize1000Queue bound; oldest events dropped on overflow
gzipfalseContent-Encoding: gzip on event POSTs
optOutfalseStart opted out (persisted opt-out wins)
disableDecidefalseSkip flags/surveys/recording bootstrap
sessionIdleTimeoutMs30 minSession rotation on inactivity
storeInMemoryStore()Persistence backend; the bindings supply SharedPreferencesStore
enableSessionRecordingfalseSession replay opt-in; recording still requires the server to enable it

AzFive.init (bindings)

AzFive.init(context, token, host, project = "default", autocaptureScreens = false, configure = { it }) — the configure lambda receives the assembled AzFiveConfig for overrides.

Behavior notes

  • Sessions rotate after 30 minutes idle or 24 hours total; $session_id is stamped on every event.
  • Failed batches — 429 included — re-queue at the front and retry next flush; the public API never throws for delivery or flag problems.
  • Custom event names: anything except the reserved az. prefix, ≤ 200 characters; properties ≤ 64 KiB serialized.