Capture analytics
Capture events, report opened notifications, handle consent and credit installs to ads.
The SDK captures events for the current person and delivers them in batches, with no separate analytics package. See Events for the event model and built-in events.
Capture an event
voidhash.capture(
"upgrade_button_clicked",
mapOf("source" to "settings", "plan" to "monthly"),
)capture returns at once. Use stable names; names starting with $ are reserved for Voidhash. The
SDK trims the name and drops a blank one with the ANALYTICS_EVENT_INVALID
diagnostic. Events captured before initialize() are kept, with
their capture time, and sent after it.
Automatic events
With automaticLifecycleEvents on, the default, the SDK records:
| Event | When |
|---|---|
$app_installed | The first launch of an install. A reinstall, or a device restored from a backup, is a new install. |
$app_updated | The first launch after the version or build changed. |
$app_opened | The first activity of a process comes to the foreground. A process started in the background, for a push message or a job, records none until an activity starts. |
$app_backgrounded | The last visible activity stopped. |
$app_became_active | An activity returned to the foreground after $app_backgrounded. |
$app_crashed | The app crashed or stopped responding. See Crashes. |
$sign_out | signOut() or reset() was called. |
Set automaticLifecycleEvents = false if your app reports these itself. The SDK also records
screen views as $screen. Configure Voidhash in
Application.onCreate so it sees your first activity start.
Crashes
The SDK reads $app_crashed from the exit records Android keeps, on Android 11 (API 30) and later,
when an activity first comes to the foreground after a launch. It installs no crash handler, so it
doesn't interfere with your crash reporter.
The event carries crash_kind: crash for a JVM crash, native_crash for native code, or anr.
It holds no stack trace. $app_version is the version running when the event is reported, and the
event is dated no more than 24 hours back.
Report opened notifications
When a person opens a notification you sent with push notifications, report
it so Voidhash can compute open rates. It records $push_opened.
When your app is in the background, Android shows the notification and opens your launcher activity with its data as extras:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// A restored activity receives its old intent again.
if (savedInstanceState == null) voidhash.trackPushOpened(intent.extras)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
voidhash.trackPushOpened(intent.extras)
}
}When your app shows the notification itself, keep the message's data, for example in the
PendingIntent, and report it when the notification is opened:
voidhash.trackPushOpened(remoteMessage.data)Pass every notification you handle. Voidhash adds a voidhash_send_id key to the data of
notifications it sends, and the SDK ignores data without it. The same notification reported twice
in a row counts once.
Sessions and delivery
Every event carries a session ID. A session ends after 30 minutes without events, including time in
the background, and survives app restarts within that time. Signing out starts a new one. Read it
with voidhash.sessionId.
The SDK sends a batch at 20 events or every 5 seconds in the foreground, and once when the app goes
to the background. It retries failures with growing waits and honors Retry-After up to
30 seconds. The queue holds 1,000 events and drops the oldest beyond that. An event Voidhash refuses
is dropped alone; the rest of its batch is delivered. A refusal from a proxy or firewall in front
of Voidhash drops nothing: the event is kept and retried on its own, so it never holds back the
others.
Call flush() before a boundary the person may not come back from:
val status = voidhash.flush()It sends attribute and sign-in updates, then purchase reports, then up to 10 batches of events, and
returns within 2 seconds while delivery continues. FlushStatus reports flushed and pending
event counts.
Analytics consent
When a person declines analytics, or hasn't decided yet, tell the SDK:
import com.voidhash.sdk.AnalyticsConsent
voidhash.setAnalyticsConsent(AnalyticsConsent.DENIED) // GRANTED, DENIED or PENDINGDENIED and PENDING behave the same:
- No custom events, screens, lifecycle events,
$sign_outor paywall impressions are captured, queued or sent, and no session is kept. A crash or opened notification from that time is never reported. - Person attributes aren't sent, and
setPersonAttributesWithStatusreturnsSKIPPED. - The install referrer isn't read.
- Purchases, restores, access checks, feature flags, paywalls and
identifywork as usual. - The first skipped call reports the
ANALYTICS_CONSENT_DENIEDdiagnostic once.
Withdrawing consent discards queued events. Granting it collects from then on; nothing skipped is
sent later. $app_installed and $app_updated are recorded once consent is granted.
The analyticsConsent option sets consent until your app calls setAnalyticsConsent; it defaults
to GRANTED. Use PENDING when you ask first. The choice you set at runtime is stored on the device,
wins over the option on later launches, and survives sign-out. Read it with
voidhash.analyticsConsent.
Revenue comes from purchases and is unaffected. Metrics built from events, such as paywall conversion, count only people who granted consent.
Share purchases with ad platforms
Voidhash sends a person's purchases to an ad platform's Conversions API only when they agreed. Analytics consent doesn't cover this. Record the choice:
voidhash.setAdDataSharing(true)Agreeing is a person attribute, so it needs analytics consent. setAdDataSharing(false) always goes
through: the SDK stores it and sends it until Voidhash has it, for up to 48 hours if the person
doesn't exist yet. When someone rejects everything, call both setAdDataSharing(false) and
setAnalyticsConsent(AnalyticsConsent.DENIED).
Credit installs to ad campaigns
On a new install, the SDK reads the Google Play install referrer and records the campaign on the
person as their first and latest ad touch: utm_* parameters, click IDs such as gclid and
fbclid, campaign_id, adset_id, ad_id, the ad network and the click time. The touch carries
over when you call identify. Organic installs and referrers without campaign values record
nothing. A website link made with playStoreUrl() carries its campaign into
the install.
It runs once per install, in the background after the first activity starts, and only with
analytics consent. If Google Play can't answer, a later launch asks again, up
to 10 launches: INSTALL_ATTRIBUTION_DEFERRED reports a retry and INSTALL_ATTRIBUTION_ABANDONED
the end. Installs that ran an earlier SDK version aren't read. Turn it off with
installAttribution = false.
Meta app-install ads
Set metaAppId to your Meta app ID, and the SDK also asks the Facebook, Instagram and Facebook Lite
apps for the ad behind the install. Their answer wins over Google Play's and says whether the ad was
clicked or viewed.
VoidhashOptions(metaAppId = "1234567890")The SDK's manifest declares the <queries> entries for those apps. Meta encrypts the ad details, so
add your install referrer decryption key in
Studio or with the CLI.
Next steps
Something wrong or missing on this page? Tell us by email or on Discord.