VoidhashDocs
DevelopersHelp centerGuidesAPI reference
Dashboard
Guides
Launch
Go-live checklist
Make your first App Store purchase
Make your first Google Play purchase
Troubleshoot
Troubleshooting
Recover from incidents
SDK error codes
Purchase error codes
API error codes
FAQ
Recipes
Win back subscribers
Handle plan changes
Unlock the app after a web purchase
Link accounts across platforms
Handle refunds
Register devices for push
Migrate
Migrate to Voidhash
Migrate from RevenueCat
Migrate from Adapty
Migrate from Superwall
Run in observer mode
Privacy and hosting
Delete personal data
Self-hosting
Operate a self-hosted server

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 identifyResult
The user ID is newThe anonymous person becomes the account.
The user ID already has a person, for example from another deviceThe anonymous person merges into it. The older of the two survives.
The device is already identified as another user IDNo 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_123 and user_456 always 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_REJECTED diagnostic.
  • 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:

ModeResult
transfer (default)Access moves to the person who restored.
sharedBoth people keep access.
disabledAccess 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.

PreviousUnlock the app after a web purchaseNextHandle refunds

On this page

Choose the user IDIdentify on every platformWhat gets mergedWhat can't be mergedRestores across accountsCheck the resultNext steps