Identity¶
Introduction¶
A user interacting with your Product carries two identities, and they are deliberately separate:
- A per-app account: A per-Product account derived for each user. This is the identity your Product signs and transacts with.
- Proof of Personhood: A tier, a per-app alias, and sometimes an earned name, which together attest that the user is a unique human without revealing who they are.
Keeping them apart is what lets the platform give your Product a stable account, and optional proof that the user is a real person, without turning every Product into a tracking surface.
A related name that is not a user identity comes up constantly: your Product's own .dot address, the name users type to reach it. It shares a namespace with the names the personhood gateway issues, which makes the two easy to confuse, so it is covered in Your Product's .dot Address below.
The Per-App Account¶
When a user opens your Product, the Host derives a product account for that user, scoped to your Product. The same user opening app-a.dot and app-b.dot gets a different account in each, derived deterministically from the user's identity and the Product's .dot identifier.
The account has two address forms, both derived from the same public key:
- SS58: The Substrate address, used across Polkadot chains.
- H160: The EVM-style address, used for
pallet-revivecontracts on Polkadot Hub.
Derivation follows a junction path of ["product", productId, derivationIndex] applied with sr25519 soft derivation, where productId is normally your .dot name. Because soft derivation is composable on public keys, the CLI, a web Host, or any external client can compute the same address the mobile wallet derives privately, without ever seeing the secret key.
Your Product obtains this account through the signer package (getProductAccount) and signs with it; every approval routes to the user's phone. See Sign and Submit Transactions for the working flow.
Why per-app derivation
If every Product saw the same account for a user, any two Products could compare accounts and correlate the user across them. Per-Product derivation makes that impossible by default: different Products see different, unlinkable addresses for the same person. Sharing an account across your own Products is possible, but it requires an explicit permission grant; it is never the default. The same reasoning governs the sandbox model in the TrUAPI reference.
Proof of Personhood¶
Proof of Personhood is a separate signal that a user is a unique human. It always has a tier and a per-app alias, and it sometimes has an earned name:
- A tier: The strength of the proof, from none, through an attested proof of a unique device, to full personhood, proven in the Polkadot App. The Proof of Personhood reference names the tiers.
- A per-app alias: A Ring-VRF-derived identifier that is deterministic for a given user and Product, and unlinkable across Products.
- An earned name: The human-readable name the personhood gateway issues to a user who has proved a tier, such as
joseph.42.
An alias is never an account address, and — like the per-app account — it is scoped per Product so it cannot be used to correlate a user across Products. Cross-Product alias linking requires an explicit consent step. Use personhood to gate features on verified-human status (for example, one action per person) without learning who the user is.
The Earned Name¶
An earned name is the one part of a user's identity that is human-readable and stable across Products. The personhood gateway issues it rather than the public registration path, which gives it properties a name bought with a deposit does not have: it is soulbound, so it never transfers, and it is not free-form, because the gateway decides the shape it issues.
Read it with getUserId from the signer package, which returns it as primaryUsername. A user with no personhood tier has no earned name, so treat it as optional and always have a fallback. For the call and its caveats, see Show a Display Name.
One name, several labels
These docs call this the earned name, the term the dotNS reference uses for a name the gateway grants. A name that identifies a person is a personhood name and one that identifies a proved device is a device name; the SDK returns either as primaryUsername.
An earned name and a Product address can be coupled
A user's identities and your Product's address are separate by design, but not always independent in practice: the gateway issues an earned name into dotNS naming, so the name is also a dotNS name of the same text. Do not assume the two can never be linked.
Usernames in Your Product¶
There is no built-in primitive for an in-app username, so most Products need to choose a display identity themselves. Until a primitive exists, the recommended pattern keeps you aligned with the platform's identity model rather than inventing a parallel one:
- Prefer the earned name where you have it. When the user holds any personhood tier, read the username the platform already associates with them (through the
signerpackage'sgetUserId) and use it as the display name. This reuses an identity the user already has instead of minting a new one. See Show a Display Name for the call and its caveats. - Otherwise, let the user set a per-Product display name and store it in local storage (device-local) or cloud storage (shared), keyed to their per-app account. Keep it scoped to your Product so it does not become a cross-Product identifier.
- Do not treat a display name as identity. Authorization and uniqueness come from the per-app account and Proof of Personhood; a display name is a label on top of them.
Following this pattern means Products converge on the same approach instead of each reinventing usernames, which eases any future migration to a platform primitive.
Your Product's .dot Address¶
A .dot name is registered with dotNS and resolves to a content record: the CID of a published Product bundle. Ownership of a name is held by a Polkadot Hub account, but the name is not an account and cannot sign.
Transferability depends on how the name was acquired. A name anyone registered by paying the deposit can be transferred. A name earned through the personhood gateway, the route that grants device and personhood names, cannot move: it identifies the person or device that earned it, and it stays with them. Most names point at content rather than at a user, but a gateway name identifies an identity (a personhood name names a person, and a device name names a unique device its holder proved), so a client that needs to tell the kinds apart should read isPopIssued(label) on the PoP controller rather than inspect the string. See PopRules and Pricing.
A name is how users reach your Product; it is not how your Product identifies a user. The confusion is that both live in the same namespace: a name registered by paying the deposit points at content, while a name earned through the gateway points at a person or a device.
How They Fit Together¶
- Users find your Product by its
.dotaddress, which identifies your Product rather than them. - Your Product acts as the user through the per-app account, signing on the user's phone.
- Your Product optionally gates features on Proof of Personhood, reading a tier and a per-app alias rather than a real-world identity, and displays the user's earned name when there is one.
None of these reveals the user's root key. The per-app account and the personhood alias stay scoped to your Product unless the user explicitly grants cross-Product linking. The earned name is the exception: it is stable across Products by design, which is why reading it goes through getUserId and a permission prompt.
Where to Go Next¶
-
Guide Sign and Submit Transactions
Derive and sign with the per-app account in your Product.
-
Learn Proof of Personhood
The Ring-VRF mechanism, tiers, and per-app aliases in depth.
-
Learn The Sandbox Model
How the Host isolates each Product and derives its per-domain account.
| Created: September 2, 2026