Identify users
Link a person's purchases and access to the account they sign in with.
Call identify when someone signs in, so their purchases and access follow them to every device.
Until then the SDK uses an anonymous distinct ID, so purchases and events work before sign-in. See
People and identity for how anonymous and identified people merge.
Identify after sign-in
Pass your stable user ID, and optionally an email and name:
voidhash.identify(externalUserId = "user_123", email = "ada@example.com", name = "Ada Lovelace")Use an opaque ID such as a UUID, not an email address. identify throws INVALID_ARGUMENT and
keeps the current identity when the ID is empty or whitespace, longer than 255 characters, contains
a NUL character, or starts with vh_anon_ or vh:anon:, the prefixes of anonymous IDs.
The switch happens on the device at once. If Voidhash can't be reached, identify doesn't throw: it
returns the person the SDK knows and delivers the sign-in later, across restarts. Until then, access
bought while anonymous stays cached, marked stale. identifyWithStatus tells you whether Voidhash
has the sign-in:
import com.voidhash.sdk.WriteStatus
when (voidhash.identifyWithStatus("user_123").status) {
WriteStatus.CONFIRMED -> Unit // Voidhash linked the identities
WriteStatus.DEFERRED -> Unit // applied on the device, delivered when Voidhash is reachable
WriteStatus.SKIPPED -> Unit // not used by identify
}identify throws a VoidhashApiException only when Voidhash refuses the sign-in: 400 for an
invalid request, 404 for an unknown target. The SDK then restores the previous identity.
If this device's anonymous ID already belongs to another identified person, identify doesn't
throw. The device switches to the new user without the anonymous history and purchases, which stay
with the other account, and the SDK reports the PERSON_WRITE_REJECTED diagnostic.
Follow your sign-in state
Wait until your authentication has loaded. Then call identify for a signed-in user, or signOut
once sign-out is confirmed. Don't sign out while your session is still loading: that discards the
stored identity before your authentication restores it.
Sign out only an identified person. signOut starts a new anonymous identity, so calling it for an
anonymous person loses the identity that holds their purchases. Use isAnonymousDistinctId to tell:
import com.voidhash.sdk.isAnonymousDistinctId
if (user != null) {
voidhash.identify(user.id)
} else if (!isAnonymousDistinctId(voidhash.getDistinctId())) {
voidhash.signOut()
}Repeating identify with the same ID and profile changes nothing. Switching from one account to
another doesn't merge them; events and purchases keep the identity they were made under. The SDK
orders identity calls, and a sign-in waiting on the network never delays initialize or signOut.
If you know the user when the app starts, pass their ID as the distinctId option instead.
initialize() then links the device's earlier anonymous ID to it. An ID identify would refuse is
ignored.
Sign out
Call signOut after your own sign-out completes:
voidhash.signOut()It records $sign_out, then starts a new anonymous identity and session, and clears that person's
cached access, flags, saved flow progress and groups. Queued deliveries are
kept. reset() does the same.
Set person attributes
Write attributes on the current person:
voidhash.setPersonAttributes(
mapOf(
"email" to "ada@example.com",
"plan_source" to "referral",
),
)Values can be strings, numbers, booleans or null; a map or list throws INVALID_ARGUMENT before
anything is sent. email and name set the built-in fields; other keys become custom attributes.
An empty map sends nothing.
Attribute writes never fail because Voidhash is unreachable: they're queued, and ones set right
after a queued sign-in wait for it. setPersonAttributesWithStatus returns the WriteStatus;
SKIPPED means analytics consent isn't granted, so
attributes aren't collected.
Read the distinct ID
getDistinctId() returns the current anonymous or identified ID, without suspending. Use it in
support logs or to match a session with your backend.
val distinctId = voidhash.getDistinctId()The SDK stores it in your app's private shared preferences. See Data collection for how backups affect it.
Next steps
- Check access for the identified person.
- Capture analytics.
- People and identity.
Something wrong or missing on this page? Tell us by email or on Discord.