Set up People
Connect accounts or accepted form contacts to Analytics with separate permission and a trusted website backend.
The People feature is optional. You do not need it for cookieless page, source, device or event reports. Browser recognition can measure returning browsers, but it cannot discover an email address.
Start with Measurement and consent if you only need returning-browser reports or cohorts. This guide covers the additional integration for confirmed accounts and submitted contacts.
Your website already knows an account after its own sign-in, or a contact after accepting a form, for example through SiteOS Forms. People lets your website explicitly confirm that identity after the visitor separately permits it. A submitted email is not a verified account. SiteOS does not read form inputs automatically or obtain email from a visitor's browser.
1. Choose the data
Open Analytics → Settings → Collection & privacy for the intended Project and environment. In Measurement mode, select Visitor recognition, then under Accounts and submitted contacts choose Confirmed accounts, Accepted contact submissions or both. Select only the profile fields you need. An opaque identifier is enough; Email and Display name are optional, and accounts can also report Email verification. A company name is not a person's name.
The browser recognition lifetime and detailed history lifetime are separate. Increasing history retention does not recover expired data. Enabling these settings does not install the website integration.
2. Review the permission
For SiteOS Cookie, use Review changes → Prepare matching Cookie draft. Review the declared identity kinds, fields and lifetimes, publish Cookie, then apply the Analytics policy. When the review offers Publish Cookie and apply, you can complete those operations in the same dialog. Otherwise follow its Cookie editor link and return to Analytics.
Ask the visitor for a fresh identity choice after activation. The website can open Cookie preferences; it must not manufacture permission or treat submitting a form as agreement to analytics. With another consent manager, configure the distinct identity purpose and forward its original scoped permission records. Refusal must not prevent the form or the site's account login from working.
3. Connect your website backend
This step needs a developer or a coding agent. A serverless function is sufficient; you do not need another physical server. The backend must derive the account from your own authenticated session or the contact from a successful server-accepted submission. It must not sign whatever email or user ID arrives from browser JavaScript.
Create an Ed25519 signing key in your trusted server environment. Keep the private key there. Register only the public JWK in the same Analytics Project/environment using the SiteOS CLI:
Use your actual environment, not Production by assumption. The file contains publicKey and a bounded UTC expiresAt; inspect CLI help for the current contract. Never paste a private key into a snippet, GTM, chat or a repository.
Implement a same-origin endpoint such as /api/analytics/identity. It validates the JSON POST, request origin, exact SiteOS application/resource, challenge expiry and the website's trusted session or accepted-submission evidence. It returns a short-lived signed assertion with Cache-Control: no-store. The endpoint is not a general-purpose signing service. SiteOS independently checks active policy and current visitor permission.
Backend response contract
The SDK sends a JSON POST with X-SiteOS-Identity: 1, schemaVersion, audience, challenge, kind and operation. The operation is identify or confirm; account confirmation must resolve the same current authenticated website account, never infer it from a saved Analytics cookie. The sessionless contact example below signs initial identification only. Analytics itself validates an existing submitted-contact link on later visits; the website signer does not need a persistent contact session.
After validating that request and the trusted website evidence, return { "assertion": "<compact JWS>" }. Sign with Ed25519 over the unpadded base64url-encoded JSON header and payload, separated by a dot. Append the base64url signature as the third segment. The header contains only alg: "EdDSA", typ: "siteos-analytics-identity+jws" and the registered key ID as kid. The payload is:
This describes the signing payload, not a complete endpoint. Validate the audience against server configuration before echoing it. Echo the original challenge ID, nonce, recognition context ID and timestamps unchanged; reject expired challenges or lifetimes over 120 seconds. Derive the subject on your backend, not from the request. Use an opaque identifier of at most 128 characters that starts with a letter or digit and contains only ASCII letters, digits, _, ., : or -; do not use an email. Include only currently selected/permitted profile fields. A JWS signature does not encrypt those fields: use HTTPS POST bodies and exclude both assertions and proofs from logs.
Website installation
In your existing Analytics installation, enable recognition and set data-siteos-identity-endpoint="/api/analytics/identity". In GTM, use Website identity backend on the existing SiteOS Analytics tag. Do not install a second collector.
For accounts, after your website resolves its own session on each document:
For accepted contacts, when your backend has trustworthy contact-session evidence:
These calls do not accept an email or an account ID. Before changing accounts or contacts, await resetIdentity(). If cleanup returns false, do not link the next identity. Do not block logout or form delivery because analytics cleanup failed.
Forms without a login session
A form receipt ID alone is not authentication. Our landing integration uses an encrypted, two-minute proof created only after the form backend validates an accepted receipt. With a runtime exposing identityProofVersion === 1, it passes that opaque proof to the same-origin endpoint:
The proof is not a profile, is not sent in ordinary events, and must never be placed in cookies, localStorage, sessionStorage, URLs or logs. Keep it only in memory for that operation. Only use a proof returned by your own accepted-form backend; the signer must decrypt and validate it rather than trust browser-supplied fields.
Returning visits
After the initial trusted contact link, Analytics can continue that link in the same browser on a reload or later visit. It validates the existing recognition cookie and current separate contact permission against its server before sending linked activity. It does not ask the form for the email again or create another cookie. The original recognition deadline is not extended.
This means the browser that submitted the contact, not proof of who is currently using it or a verified email address. Account tracking still requires your website's authenticated session on every document. Shared browsers can change users: call resetIdentity() before linking another contact/account, and never use Analytics recognition to sign someone in or authorize access.
Expired, withdrawn or erased links cannot continue. Deleting the cookie or using another browser does not recover the contact. Existing linked history remains subject to retention and erasure rules; earlier anonymous activity is never joined retroactively.
Cross-domain visit continuity does not transfer a People identity or permission to another website. Each website still needs its own valid setup, trusted identity evidence and current visitor permission.
4. Verify before expecting People data
Use a local or dedicated test environment. Verify a successful form/sign-in with permission, refusal, withdrawal, expiry, reload and a switch to another account/contact. Confirm that forms work when Analytics is unavailable. Do not create real production submissions merely to test tracking.
The People tab lists confirmed retained profiles to Organization owners/admins; filter it by profile type. Open a profile to review its confirmed activity, use Export this page for a JSON file of the profile and up to 100 events, or Erase profile to erase it together with its linked history. The Overview People card shows only profiles with linked activity matching its period and filters. A newly confirmed contact with no subsequent linked activity can therefore be absent from Overview. Email is shown only when selected, permitted and actually supplied.
Seeing no rows does not necessarily mean a broken script: check the active policy, backend installation, registered key and fresh identity permission. CLI/MCP aggregate reports do not expose private People records.