VoidhashDocs
DevelopersHelp centerGuidesAPI reference
Dashboard
Get started
Introduction
Quickstart
How Voidhash works
Glossary
Versions and releases
Concepts
Teams, projects and environments
API keys
Products and perks
Offers
Subscription lifecycle
People and identity
Groups
Events
Features
Paywalls in your app
Feature flags and A/B tests
Paywall components
Push notifications
Ad attribution in your app
Client SDKs
React Native
Swift
Kotlin
Web
Your backend
Node.js
PHP
Go
Rust
Other languages
Payment sources
Forward store notifications
Developer tools
CLI
MCP server
Query analytics with VoidQL
Kotlin SDK
Kotlin quickstart
Display a paywall
Make and restore purchases
Check access
Identify users
Evaluate feature flags
Capture analytics
Groups
Track screens
Development mode
Kotlin SDK reference
Errors
Diagnostic codes
Troubleshooting

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:

EventWhen
$app_installedThe first launch of an install. A reinstall, or a device restored from a backup, is a new install.
$app_updatedThe first launch after the version or build changed.
$app_openedThe 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_backgroundedThe last visible activity stopped.
$app_became_activeAn activity returned to the foreground after $app_backgrounded.
$app_crashedThe app crashed or stopped responding. See Crashes.
$sign_outsignOut() 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 PENDING

DENIED and PENDING behave the same:

  • No custom events, screens, lifecycle events, $sign_out or 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 setPersonAttributesWithStatus returns SKIPPED.
  • The install referrer isn't read.
  • Purchases, restores, access checks, feature flags, paywalls and identify work as usual.
  • The first skipped call reports the ANALYTICS_CONSENT_DENIED diagnostic 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

  • Track screens.
  • Events and Check your data.
  • Ad attribution in your app.

Something wrong or missing on this page? Tell us by email or on Discord.

PreviousEvaluate feature flagsNextGroups

On this page

Capture an eventAutomatic eventsCrashesReport opened notificationsSessions and deliveryAnalytics consentShare purchases with ad platformsCredit installs to ad campaignsMeta app-install adsNext steps