Identity resolution
A visitor browses on their phone, converts on a laptop a week later, and gives you an email at checkout. Those are three anonymous IDs and one human. Identity resolution is the step that works that out — and it’s what lets a conversion carry the click ID from a visit that happened days earlier.
Identifiers
Every event is broken down into the identifiers it carries. Fifteen kinds participate:
anonymous_id, user_id, email, phone, device_id, fbclid, gclid,
ttclid, li_fat_id, msclkid, crm_contact_id, epik, rdt_cid,
sc_click_id, twclid
Email and phone are normalized before matching, using the same rules as
PII hashing — so Ada@Example.com and ada@example.com are one
identifier, not two.
Matching
The extracted identifiers are looked up against your identity graph, and the number of people they hit decides what happens:
Merging into the oldest is deliberate. The oldest record has the longest history, so keeping it preserves the earliest touchpoints — which is exactly what first-touch and time-decay attribution depend on. The losing records’ identifiers are relinked and their rollups absorbed, so nothing is discarded.
Merges happen when a single event bridges two previously separate identifier sets — the classic case being a logged-in checkout on a device that had only ever been anonymous.
What identify() does
identify() attaches known traits to the current person:
Two things follow. A user_id marks the person identified, and the traits
become available for hashing and delivery on subsequent events — improving
match quality at every destination.
identify() only emits an event when something actually changed. Calling it on
every page render is harmless — repeated identifies with identical data are
skipped rather than billed as volume.
Click backfill
Ad platforms match conversions best when the conversion carries the click ID from the ad that produced it. But the click happens on a landing page, and the conversion often happens days later on a page with no query string at all.
So every click ID seen on a landing page is stored against the person with a per-platform expiry. When a conversion event arrives carrying no click IDs, unexpired clicks for that person are backfilled — most recent wins per platform.
Backfill is skipped entirely if the conversion already carries any click ID. The click the visitor actually arrived on is always more truthful than one reconstructed from history.
Expiry windows
Each platform’s window matches its own attribution policy — sending a click ID older than the platform accepts just produces an unmatched conversion.
Meta’s seven days is the tightest window by a wide margin. If your sales cycle
runs longer than a week, a Meta-attributed conversion frequently arrives after
its fbclid has expired — collect email and phone so there’s still
something to match on.
Backfill only triggers on conversion events. See the taxonomy for which names qualify.
gbraid and wbraid
Both are captured and stored, and both count for attribution — but neither is ever used to stitch identity.
They’re Google’s privacy-aggregated iOS click IDs, and aggregation is the
point: a single value can represent many users. Treating one as an identifier
would merge unrelated people into a single record, which is a far worse failure
than a missed match. gclid has no such problem and is used normally.
Person segments
Resolved people are labelled with segments you can filter and report on:
identified— auser_idhas been seen for this person.paying— the person has a purchase in their history.anonymous_high_intent— not yet identified, but showing intent-tier activity. See the taxonomy.consent_denied— the person’s consent state blocks delivery. See Consent & privacy.