Link accounts across platforms
Keep one person, with their purchases and perks, across your iOS app, Android app and website.
One account in your system should be one person in Voidhash, whether they use your iOS app, your
Android app or your website. You get there by calling identify with the same user ID everywhere.
Purchases from every store then land on that person, and their perks unlock every platform.
Identity itself is explained in People and identity.
Choose the user ID
Use your account's stable, opaque ID, such as a UUID. Don't use an email address, which can change,
or a sequential database ID. The ID is at most 255 characters and can't start with vh_anon_.
Give staging accounts their own IDs, for example with a staging: prefix: people aren't split by
environment.
Identify on every platform
Call identify as soon as your sign-in completes, on every platform:
try await voidhash.identify(externalUserId: "user_123")voidhash.identify(externalUserId = "user_123")await voidhash.client.identify("user_123");await voidhash.identify("user_123");For Stripe purchases, also put the ID on the Checkout Session as voidhash_distinct_id; see
Unlock the app after a web purchase. For a backend that reports
payments, pass it as distinctId; see Payment sources.
Call signOut() when the person signs out, and before another user signs in on the same device.
What gets merged
Before sign-in, each device is its own anonymous person. identify joins it to the account:
Before identify | Result |
|---|---|
| The user ID is new | The anonymous person becomes the account. |
| The user ID already has a person, for example from another device | The anonymous person merges into it. The older of the two survives. |
| The device is already identified as another user ID | No merge. The device switches users. |
A merge keeps everything: purchases, subscriptions and perks of both count for the survivor, events are attributed to it, and attributes combine with the newest value winning. So someone who bought anonymously on their phone keeps access after signing in to an account they created on the web.
What can't be merged
- Two identified people.
user_123anduser_456always stay separate. If one human has two accounts in your system, Voidhash has two people. Pick one account in your system; Voidhash has no call to join identified people. - An anonymous ID already claimed by another account. If a device's anonymous ID already merged
into one account, for example after restoring an old backup, signing in to a second account doesn't
move that history. The device switches to the new user, and the SDK reports the
PERSON_WRITE_REJECTEDdiagnostic. - Store accounts. A purchase belongs to the person who bought it, not to the Apple ID or Google account. Restoring on Android never finds an App Store purchase; it doesn't need to, because the perk already follows the person.
Restores across accounts
A restore can find a purchase that already grants access to another person, for example when two of your accounts share one Apple ID. The project's paid access sharing setting decides what happens:
| Mode | Result |
|---|---|
transfer (default) | Access moves to the person who restored. |
shared | Both people keep access. |
disabled | Access stays with the person who bought. |
Change paidAccessSharing.production with PATCH /api/v1/projects/{projectId}/settings, the MCP
tool update_project_settings, or voidhash settings set paid-access-sharing.production. See
Project settings.
Check the result
Open the person in People and search for the user ID: one profile should list purchases from
every store you sell through. If a purchase is missing, ask the MCP tool
explain_person_access or run voidhash person why user_123 premium; see
Why does this person have access?.
A purchase made while anonymous on a device that never signed in stays on that anonymous person
until it does.
Next steps
- People and identity
- Unlock the app after a web purchase
- Identify users in Swift, Kotlin, React Native or Web.
Something wrong or missing on this page? Tell us by email or on Discord.