Quickstart
Edition 3.1.1 Last verified 2026-07-19
Non-normative. This page is an informative orientation and onboarding aid. It adds no contract, defines no requirement, and is excluded from requirement extraction. The pseudocode below is illustrative; the binding contracts are the cited specification sections, requirement clauses, and machine registries. Where anything here appears to disagree with those canonical sources, they govern.
UIAF is an implementation specification: you build it into your platform. A conforming deployment is one that follows the specificationโs requirements. The minimal conforming slice below is the smallest build that still qualifies, and the reading order at the end covers everything beyond it.
The minimal conforming slice
Section titled โThe minimal conforming sliceโThe smallest conforming deployment is a same-origin cookie route (create), a consent-gated automatic session, a same-origin relay, and one payload that passes the shared reference validator. A relay is your own server route that receives payloads from the browser and forwards them to your endpoint. Recovery, cross-domain handoff, conversion/identify, and retry-drain refinements layer on top of this skeleton without changing it.
1. Server โ the cookie route, POST /api/uiaf/cookie
Section titled โ1. Server โ the cookie route, POST /api/uiaf/cookieโOnly the server creates UIDs (user identifiers). The route contract is closed: create is exactly {}, recover is exactly { "uiaf_recovery": "<credential>" }, and any UID anywhere in the body is a 400. The status map is exhaustive: 200 (issuance with Set-Cookie, or no-set without), 400, 403, 429, 5xx. No other status exists. See Endpoint Schema (UIAF-04-AUX-003, UIAF-04-AUX-008).
// PSEUDOCODE โ minimal create-capable cookie route (recover adds one closed body variant)route POST /api/uiaf/cookie: // Ingress authority: Origin is authoritative; Sec-Fetch-Site only corroborates. if originInvalid(request) OR secFetchSite(request) == "cross-site": return 403 // single observable denial if contentType(request) != "application/json": return 400 // strict JSON only var body = parseJsonStrict(readBody(request)) // duplicate-member-rejecting; non-object/parse failure => 400 if body != {}: return 400 // create body is EXACTLY {}; any member โ incl. any UID โ => 400 if rateLimited(request): return 429 // per-source rate limit
// An already-valid browser-held cookie is AUTHORITATIVE: no Set-Cookie, no replace, no refresh. var inbound = readValidUidCookie(request) // validated against the one canonical UID regex; malformed => absent if inbound != null: return json(200, { "uid": inbound, "recovery": currentBoundCredentialOrNull(inbound) }) // NO Set-Cookie
// Create: the base persistence predicate governs Set-Cookie (resolved consent + analytics allowed + policy). var consent = readServerConsentState(request) // the server's own authoritative consent/policy state if not basePersistencePredicate(consent, UIAF_CONFIG): return 403 // no Set-Cookie
var uid = mintUid() // CSPRNG UUIDv4 + "." + unix seconds; canonical form; SERVER-MINTED ONLY var credential = mintRecoveryCredential(uid) // base64url 22-128 chars, >=128 CSPRNG bits, server-bound to uid persist(uid, credential) // binding, expiry, revocation/rotation state; zero raw UID in logs response.setHeader("Set-Cookie", "uiaf_uid=" + uid + "; Path=/; Secure; SameSite=Lax; Max-Age=34560000") // + configured Domain if subdomain-sharing response.setHeader("Cache-Control", "no-store") return json(200, { "uid": uid, "recovery": credential }) // EXACTLY these members; uid is candidate-only until the client re-read2. Client โ identity, session, one automatic session
Section titled โ2. Client โ identity, session, one automatic sessionโThree rules carry the whole flow: the client never mints a UID and never puts one in a request body; every response UID is candidate-only until the mandatory post-response cookie re-read; and behavior branches on the effective consent vector, never a tier number (Identity Management, Implementation Guide; UIAF-02-COOKIE-001/002, UIAF-09-ID-001, UIAF-09-CONSENT-001, UIAF-09-WAKE-001).
// PSEUDOCODE โ first eligible document: identity -> session -> one automatic sessionasync function minimalClientSession(): // 1. Consent is the first authority (CMP-over-GCM; every signal unknown fails closed to denied). var consent = parseConsent(document, UIAF_CONFIG) // REAL API (document) if not automaticSessionAuthorized(consent): return // status resolved/not_applicable AND effective.analytics_storage allowed // AND documented analytics purpose โ else: no persist, no send, no session state
// 2. Identity: the browser-held uiaf_uid cookie is the ONLY authority. var cookieUid = readValidUidCookie() // canonical-regex validated read of the browser-held cookie var isNew = false if cookieUid == null: // No cookie: closed create call. (Full implementations wrap this boundary in the origin-wide // uiaf-identity-issuance Web Lock so at most one tab calls the route โ spec 09.) var resp = await fetch("/api/uiaf/cookie", { // REAL API (fetch) method: "POST", headers: { "Content-Type": "application/json" }, body: "{}" }) if resp.status != 200: return // 400/403/429/5xx: identity indeterminate; bounded retry, never a tight loop var issuance = parseJsonStrict(await resp.text())// exactly { uid, recovery } cookieUid = readValidUidCookie() // MANDATORY authoritative post-response re-read if cookieUid == null: return // unreadable => indeterminate: no persistence write, no send if issuance.recovery != null: mirrorGovernedPair(cookieUid, issuance.recovery) // atomic { uiaf_uid, uiaf_recovery } script-storage pair isNew = true var identity = { uid: cookieUid, session_id: null, session_seq: null, session_start: false, is_new: isNew, resolution_method: "cookie", confidence: "high" }
// 3. Session ownership: AWAIT the allocator once per document; identity resolution never manufactures it. var owned = await ensureSessionOwnership() // uiaf-session-alloc:<session_id> Web Lock, 250 ms deadline; // proven { session_id, owned: true } reused for the document lifetime; // coordination exhaustion degrades to owned: false (null-session emission)
// 4. Attribution from trusted navigation evidence (click IDs only when effective.ad_storage is allowed). var attribution = captureAttribution(location.href, navigationDescriptor()) // REAL API (location.href)
// 5. Re-read BOTH authorities immediately before freeze/send. consent = parseConsent(document, UIAF_CONFIG) if not automaticSessionAuthorized(consent): return if not authoritativeCookieMatches(identity): return // cookie diverged/disappeared => rebuild or drop; NEVER send
// 6. Sequence, reasons, one immutable freeze. if owned.owned: identity.session_id = owned.session_id var seq = allocateSeqSync(owned.session_id) // reads uiaf_session_state.next_seq, persists the increment, NO async yield identity.session_seq = seq identity.session_start = (seq == 0) var reasons = [] // exactly the coherent tuple โ no other vocabulary if identity.session_start: reasons.push("session_open") if identity.is_new: reasons.push("identity_created") if attribution.is_new_touch: reasons.push("attribution_touch") var frozen = assembleAndFreeze("session", identity, attribution, consent, reasons) // event_id = fresh UUIDv4; RFC 8785 (JCS) canonical bytes, <= 32768 bytes, frozen ONCE
// 7. Same-origin relay send. The frozen bytes are the unit of retry โ never re-serialized. var result = await postRelay(frozen) // 2xx => acknowledged; 4xx/unexpected final 3xx => terminal drop; // 5xx/network => durably enqueue the byte-identical body under the same event_id if result.acknowledged OR result.durablyEnqueued: writeDirtyBaseline(jcsProjection(identity, attribution, consent)) // canonical projection STRING, never a hash3. Server โ the same-origin relay
Section titled โ3. Server โ the same-origin relayโThe relay is the recommended delivery path. It lives on a deployment-chosen, neutral first-party path. Avoid tracker-shaped names: collect, _ga, _fbp, _gcl, track, analytics. Its validation pipeline runs in exactly this order (Implementation Guide ยงDelivery; UIAF-04-EP-007):
// PSEUDOCODE โ same-origin relay routeroute POST <deployment-chosen neutral path>: if contentLength(request) > 40960: return 413 // hard pre-buffering ceiling โ before any parsing if not sameOriginChecked(request): return 403 // Origin/Sec-Fetch-Site + CSRF + per-source rate limit var raw = readBody(request) // 1. Raw-byte preconditions FIRST: fatal UTF-8 decode, <= 32768 bytes, duplicate-member rejection, // JSON parse, schema/enum validation, RFC 8785 canonical-JCS byte equality โ before any object is trusted. // 2. Own-only canonicalization: force _meta.emitter = "client" for browser submissions // (a public/browser assertion of "server" is rejected). // 3. Semantic/reference validation of the canonicalized object (the shared reference validator). var payload = relayPipeline(raw) // any failure => 4xx terminal; nothing partially processed forward(payload, downstreamAuth) // server-added authentication; the browser holds no secrets return 204 // 2xx acknowledgement4. The payload โ one real 3.1.1 session
Section titled โ4. The payload โ one real 3.1.1 sessionโThis is what the flow above emits on a first-ever visit from a Google Ads click with full consent. It is copied byte-for-byte from the committed golden fixture docs-site/schema-tools/fixtures/valid/session-identity-created.json, which the shared reference validator accepts as-is:
{ "event": "session", "event_id": "3f6b1c2a-9d4e-4f7a-8b2c-1e5a7c9d3f04", "timestamp": "2026-07-19T14:30:00.000Z", "identity": { "uid": "f81d4fae-7dec-4ec9-a765-00a0c91e6bf6.1647291600", "session_id": "a3b8c9d0-1234-4678-9abc-def012345678", "session_seq": 0, "session_start": true, "is_new": true, "resolution_method": "cookie", "confidence": "high" }, "consent": { "signals": { "analytics_storage": "granted", "ad_storage": "granted", "ad_user_data": "granted", "ad_personalization": "granted" }, "status": "resolved", "effective": { "analytics_storage": "allowed", "ad_storage": "allowed", "ad_user_data": "allowed", "ad_personalization": "allowed" }, "gpc": { "detected": false, "applicable": false }, "source": "cmp_cookiebot", "state_updated_at": 1750000000, "tier": 1 }, "attribution": { "first_touch": { "touch_id": "a3b8c9d0-1234-4678-9abc-def012345678", "source": "google", "medium": "cpc", "campaign": "spring_sale", "term": null, "content": null, "click_ids": { "gclid": { "value": "Cj0KCQjw84anAbCd", "captured_at": 1750000000, "expires_at": 1790000000 } }, "referrer": "google.com", "landing_url": "example.com/products/shoes", "timestamp": 1750000000, "custom": {} }, "last_touch": { "touch_id": "a3b8c9d0-1234-4678-9abc-def012345678", "source": "google", "medium": "cpc", "campaign": "spring_sale", "term": null, "content": null, "click_ids": { "gclid": { "value": "Cj0KCQjw84anAbCd", "captured_at": 1750000000, "expires_at": 1790000000 } }, "referrer": "google.com", "landing_url": "example.com/products/shoes", "timestamp": 1750000000, "custom": {} }, "count": 1, "is_new_touch": true }, "page": { "url": "https://example.com/products/shoes", "path": "/products/shoes", "referrer": "https://google.com/", "title": "Shoes" }, "client": { "user_agent": "Mozilla/5.0", "language": "en-US", "viewport": "1920x1080", "screen": "1920x1080" }, "event_data": { "reasons": [ "session_open", "identity_created", "attribution_touch" ] }, "_meta": { "uiaf_version": "3.1.1", "data_quality": "full", "attribution_completeness": "full", "emitter": "client" }}Why each group has exactly this shape:
| Field path | Why this value |
|---|---|
event, event_id, timestamp | One of exactly three data-plane events (session/conversion/identify); a fresh UUIDv4 per logical event, immutable across retries; RFC 3339 UTC with milliseconds |
identity.uid | Server-minted canonical form <uuidv4>.<unix-seconds>, adopted from the authoritative cookie re-read โ never client-generated |
identity.session_seq, session_start | First allocation of the owned session โ 0 โ session_start: true |
identity.is_new, resolution_method, confidence | The coherence tuple (UIAF-04-ID-001): is_new: true โ non-null uid and resolution_method: "cookie"; fresh issuance โ confidence: "high" |
consent | Resolved via cmp_cookiebot; all four effective values allowed โ derived tier: 1 (serialized shorthand only โ nothing branches on it); state_updated_at is the selected recordโs material-change time; consent_record_id is omitted here, never serialized as null |
attribution | One touch: first_touch == last_touch, count: 1, is_new_touch: true; gclid captured because ad_storage is allowed, with captured_at/expires_at; landing_url is host + path, no query string |
page, client | Request context; url/path consistent, referrer the cross-site navigation referrer |
event_data.reasons | Exactly the coherent tuple for this state (UIAF-04-REASON-001): session_open (seq 0), identity_created (is_new), attribution_touch (is_new_touch) โ no other vocabulary |
_meta | uiaf_version: "3.1.1"; data_quality: "full" (all four effective values allowed, nothing stripped); attribution_completeness: "full" (click IDs present โ full); emitter: "client" (browser submission โ the relay forces this value) |
5. Conformance checklist for the slice
Section titled โ5. Conformance checklist for the sliceโ- Cookie route: closed create/recover bodies, exhaustive
200/400/403/429/5xxstatus map, valid-cookie no-set rule. See Endpoint Schema (UIAF-04-AUX-003, UIAF-04-AUX-008). - Identity: server-minted UID only, candidate-only responses, mandatory re-reads. See Identity Management (UIAF-02-COOKIE-001/002) and the Implementation Guide (UIAF-09-ID-001).
- Consent: every persist and send is gated on the effective vector; pending sends nothing. See Consent Integration, UIAF-09-CONSENT-001, UIAF-09-WAKE-001.
- Delivery: one freeze; retries byte-identical under the same
event_id; relay 413 pre-parse ceiling and exact pipeline order. See UIAF-04-RETRY-002, UIAF-04-EP-007. - Verification: validate every emission against the payload schema and the shared reference validator, then run the Test Scenarios and the Conformance policy.
The reading order
Section titled โThe reading orderโBeyond the slice, the shortest useful path through the full material:
- Understand the shape: Introduction. The website (client plus server integration) resolves identity, captures attribution, and delivers payloads. The endpoint validates, deduplicates, and orders. Exactly three data-plane events exist:
session,conversion,identify, in the event registry. - Wire identity: Identity Management. The server alone issues the identity cookie. The client re-reads the browser-held cookie as the authority after every endpoint response. Creation is consent- and policy-gated.
- Capture attribution: Attribution Capture. The normalization pipeline, the touch boundary from trusted navigation evidence, bounded touchpoints. While consent is pending, only the closed three-key pending context (source, medium, campaign) exists, in current-document memory only.
- Assemble and send payloads: Endpoint Schema. Validate everything you emit against the canonical payload schema. Freeze bytes before sending; retries resend the identical frozen body under the same
event_id. - Apply the consent overlay: Consent Integration. Observed signals, lifecycle, and effective permissions gate every storage write and every send. The default pending state sends nothing.
- Harden and verify: Data Handling and the Implementation Guide, then the Test Scenarios and the Conformance policy. The FAQ covers the questions that come up in practice.
Reference surfaces
Section titled โReference surfacesโ- Browser Landscape: what browsers actually permit
- Identity Resolution: cross-device and evidence rules
- Storage-key registry: every UIAF-owned key and its purge rule
- Enums registry: closed vocabularies, including the pending-context allowlist
- Changelog: payload-diff-first history