How Event Stitching works

Event Stitching builds an event profile graph from event records and the identifiers observed on those events.

The graph is deterministic: the same input data, identifier mappings, and policy produce the same stitching decisions. The goal is not to merge every event that shares any value. The goal is to connect events when the configured evidence is strong enough, while keeping weak or polluted identifiers from collapsing unrelated activity.

Mental model

Think of each event as evidence.

event
  β”œβ”€ user_id = 123
  β”œβ”€ email = [email protected]
  β”œβ”€ anonymous_id = anon_abc
  └─ session_id = sess_1

DinMo standardizes the identifier values, evaluates them in policy order, and assigns the event to a dinmo_stitched_profile_id when matching is safe.

The example profile IDs below are shortened for readability.

dinmo_stitched_profile_id: profile_001
  β”œβ”€ user_id: 123              active anchor
  β”œβ”€ email: [email protected]  active anchor
  β”œβ”€ anonymous_id: anon_abc    active
  └─ session_id: sess_1        active until its stitching lifetime expires

The profile is called Known when it has at least one active anchor identifier. It is called Anonymous when it only has weak identifiers.

Processing order

For each run, DinMo follows the same high-level flow:

  1. Select the next event window.

  2. Read events from the configured models.

  3. Extract identifier observations from mapped fields.

  4. Standardize values and remove blocked or expired values from matching.

  5. Evaluate identifiers from strongest to weakest priority.

  6. Attach events to existing profiles, create new profiles, or merge compatible profiles.

  7. Apply protections for unsafe or excessive identifier values.

  8. Publish attribution, profiles, identifier values, redirects, audit events, and run metrics.

Priority matters because a strong identifier can protect the graph from weaker evidence.

Example order:

Priority
Identifier
Typical role

1

User ID

Strong authenticated anchor.

2

Email

Strong anchor when standardized and governed.

3

Anonymous ID

Useful pre-login identifier.

4

Session ID

Short-lived activity context.

5

IP address

Weak signal, usually short-lived or audit-only.

Common outcomes

Each processed event and identifier value has an explainable outcome.

Outcome
What it means
Where to inspect it

Event stitched

The event was attached to a dinmo_stitched_profile_id.

identity_event_profile_attribution

Event excluded with no_matchable_identifier

The event had no usable identifier after standardization, blocked values, and stitching lifetime checks.

Attribution and run metrics

Event excluded with conflicted_identifier_value

The event depended on a quarantined identifier value.

Attribution, identifier values, and audit events

Event excluded with limit_conflict

Stitching the event would violate a configured identifier policy.

Attribution, policy, and audit events

Value blocked

The value is ignored for matching because it is a placeholder, test value, or known bad value.

Identifier values and audit events

Value expired

The value is past its stitching lifetime and no longer matches future events.

Identifier values

Value demoted

The value remains evidence but no longer participates in active matching.

Identifier values and audit events

Profile redirected

A profile merged into another surviving profile.

Redirects and profiles

Example 1: anonymous visitor becomes known

At first, the user browses anonymously.

Time
Event
Identifiers

t1

Page view

anonymous_id = anon_abc

t2

Product view

anonymous_id = anon_abc

DinMo creates an anonymous event profile:

Later, the user logs in.

Time
Event
Identifiers

t3

Login

user_id = 123, anonymous_id = anon_abc

The strong user_id becomes active on the same profile. The profile becomes Known.

Future events with user_id = 123 or with the still-active anonymous_id = anon_abc can attach to profile_001.

Example 2: one person uses two devices

The same user logs in on a laptop and then on a phone.

Time
Event
Identifiers

t1

Laptop login

user_id = 123, device_id = laptop_1

t2

Phone login

user_id = 123, device_id = phone_1

The strong user_id connects both devices to the same event profile.

This is expected. A strong anchor explains why the two device identifiers belong to the same event profile.

If Max unique values per profile is configured for device_id, DinMo keeps only a bounded number of active device IDs for the profile. Older device IDs can remain visible as audit evidence but stop creating new matches.

Example 3: two users share a weak identifier

Two different people use the same shared device or browser.

Time
Event
Identifiers

t1

Alice login

user_id = alice, cookie_id = shared_cookie

t2

Bob login

user_id = bob, cookie_id = shared_cookie

The user_id values are strong anchors and identify different people. DinMo should not collapse Alice and Bob into one event profile only because they share a cookie.

Expected graph:

If the shared cookie touches too many profiles, Max profiles per value quarantines it. The value remains explainable in audit, but it no longer matches future events.

Example 4: weak-only event on a shared value

Now imagine a later event arrives with only the shared cookie:

Time
Event
Identifiers

t3

Page view

cookie_id = shared_cookie

If shared_cookie is already quarantined, the event is excluded with reason = conflicted_identifier_value.

If it is not quarantined but the value is weak and ambiguous, the attribution depends on the current active graph and policy. This is why weak identifiers need clear protections:

  • lower priority than anchors

  • finite stitching lifetime

  • Max profiles per value

  • blocked values for placeholders and known bad values

Do not rely on weak-only events from shared identifiers as high-confidence person-level attribution.

Example 5: account switching on the same browser

A browser can legitimately be used by more than one person.

Time
Event
Identifiers

t1

Anonymous page view

cookie_id = browser_1

t2

Alice login

user_id = alice, cookie_id = browser_1

t3

Bob login

user_id = bob, cookie_id = browser_1

t4

Anonymous page view

cookie_id = browser_1

The cookie is useful evidence, but it should not be trusted more than authenticated anchors.

If the cookie crosses Max profiles per value, DinMo quarantines it. The later weak-only event can then be excluded with reason = conflicted_identifier_value instead of being forced onto Alice or Bob.

This protects the graph from account switching, family devices, kiosks, call-center devices, and other shared-browser patterns.

Example 6: bad placeholder value

A tracking implementation emits the same placeholder value on many events.

Time
Event
Identifiers

t1

Page view

email = [email protected], anonymous_id = anon_1

t2

Purchase

email = [email protected], anonymous_id = anon_2

t3

Signup

email = [email protected], anonymous_id = anon_3

If [email protected] is treated as a real email, it can connect unrelated activity.

Add it to blocked values. Then it remains useful as audit evidence, but it is ignored for matching.

Example 7: value-level quarantine vs active-value compaction

Event Stitching has two different protections that are easy to confuse.

Max profiles per value

This asks: β€œIs this one value touching too many profiles?”

Example:

If the limit is 3 and the value touches 4 profiles, DinMo quarantines the value. It is no longer used for future matching.

Max unique values per profile

This asks: β€œIs this one profile keeping too many active values of the same identifier?”

Example:

If the limit is 3, DinMo keeps the most recent active device IDs and demotes older ones from active matching.

This does not mean the old device value is globally bad. It means the profile has reached its active-value capacity for that identifier.

Profile merges and stable IDs

Sometimes new evidence connects two event profiles safely.

Before
New evidence
Result

profile_001 has anonymous_id = anon_abc

Later event has anonymous_id = anon_abc and user_id = 123

profile_001 becomes known through user_id = 123.

profile_001 has one device, profile_002 has another device

Later event shows the same strong user_id on both

One profile survives and the other redirects to it.

When a merge happens, always use resolved_dinmo_stitched_profile_id for downstream joins. Redirects preserve the history of older profile IDs.

What to monitor

After each run, monitor:

Signal
Why it matters

Stitch rate

How much processed activity is attached to event profiles.

Known profile share

How much of the active graph is reachable through anchors.

Exclusion reasons

Whether events are excluded for coverage, quality, or policy reasons.

Conflicted values

Whether weak identifiers are creating unsafe graph connections.

Active conflicts

Should normally be zero after protections are applied.

Demoted values

Shows values kept as evidence but removed from active matching.

Use Review and monitor Event Stitching for the UI workflow and Investigate Event Stitching results for warehouse queries.

Last updated