VoidhashDocs
DocumentationAPI reference
Dashboard
Get started
Introduction
Quickstart
Setup
Setup overview
Create a project
Products and perks
Paywall locations
CLI
Paywall components
Components
Develop a component
Editor panels
Component definition
Publishing
Installing and capabilities
SDKs
Swift
Kotlin
React Native
Web
Store setup
Connect the App Store
Connect Google Play
Connect Stripe
API libraries
Node.js
PHP
Rust
Go
Resources
MCP server
Meta ads
Migrate in observer mode
Delete a person's data
React Native SDK
Check access
Identify customers
Evaluate feature flags
Capture analytics
Track screens
Errors

Identify customers

Link anonymous purchase history to accounts in your authentication system.

Voidhash creates an anonymous distinct ID on first launch and persists it, so purchases and events work before anyone signs in. If your app has accounts, call identify() after authentication. Access then follows the customer across devices.

Identify after sign-in

Pass a stable identifier from your backend, plus optional profile fields:

await voidhash.client.identify(user.id, {
  email: user.email,
  name: user.name,
});

Use an opaque, unique ID such as a UUID. Do not use an email address or a sequential database ID as the primary identifier.

When an anonymous customer signs in, Voidhash moves their purchase history and entitlements to the identified person. Events captured before the switch stay attributed to the anonymous identity.

Identify while offline

identify() switches the identity on the device first, then asks Voidhash to link the anonymous ID to the new one. The link is stored on the device before it is sent. If Voidhash cannot be reached, or the publishable key is rejected, the new identity stays in place and the link is sent later: at the next launch, when the app returns to the foreground or the connection comes back, on flush(), or on a retry timer. It survives app restarts.

A customer who bought something before signing in keeps their access in the meantime. The SDK serves their last known entitlements for the new identity, marked isStale, until Voidhash has merged the two identities. Use identifySync() to learn whether the switch was confirmed by the server or is still deferred.

identify() returns an error only when Voidhash refuses the switch for good, for example because the anonymous ID already belongs to another account. The previous identity is then restored.

Follow authentication state

Wait until your authentication system has finished loading. Then call identify(user.id) for a signed-in user, or signOut() once sign-out is confirmed. A loading session is not a signed-out session; resetting during startup discards the persisted identity before authentication restores it.

Identity changes are ordered by the SDK, including calls during initialization. Repeating identify() for the same ID without profile changes leaves the session and cached state intact. Any non-blank string works as an ID, including non-Latin text such as jürgen or 用户42. An empty or whitespace-only ID returns an INVALID_ARGUMENT error and leaves the current identity unchanged, so guard against a missing user ID before calling identify(). Switching directly between accounts does not merge them. Events and queued transactions retain the identity that captured them, and purchases retain the identity that started them.

No declarative identity prop, additional provider, or app-side identity queue is needed.

Sign out

Sign out of Voidhash after your own sign-out completes:

await auth.signOut();
await voidhash.client.signOut();

signOut() flushes pending events under the old identity, then starts a fresh anonymous session. Use reset() only when you need the same identity reset without recording a sign-out event.

Set customer attributes

Set attributes on the current customer without waiting for the server:

await voidhash.client.setPersonAttributes({
  email: "ada@example.com",
  name: "Ada Lovelace",
  plan_source: "referral",
});

The call stores the update on the device and sends it in the background, retrying until Voidhash accepts it. Updates made before a queued identity link has been delivered wait for that link, so they land on the right person. Call await voidhash.client.flush() when delivery must be attempted immediately. If you need the updated person in the same call, use setPersonAttributesSync() instead. It answers deferred with the last known person when the update has to wait, and skipped when the end user has not granted analytics consent.

Attribute values can be strings, numbers, booleans, or null. email and name map to built-in person fields and must be strings. Other keys become custom traits. A nested object or an array returns an INVALID_ARGUMENT error and nothing is stored, whether or not the device is online.

Read the distinct ID

Read the distinct ID of the current identity, anonymous or identified:

const distinctId = await voidhash.client.getDistinctId();

This is useful in support logs, and when you correlate a client session with your backend.

Anonymous or identified?

Which setup fits depends on how your app handles accounts.

  • No accounts. Keep the automatically generated anonymous identity.
  • Optional accounts. Let purchases work anonymously, then identify after sign-in.
  • Account required. Identify immediately after restoring your app session.

Next steps

  • Check the identified customer's access
  • Capture analytics events and traits
PreviousCheck accessNextEvaluate feature flags

On this page

Identify after sign-inIdentify while offlineFollow authentication stateSign outSet customer attributesRead the distinct IDAnonymous or identified?Next steps