I have a question regarding the Identifying Users (Simplified) mechanism. From my understanding, Mixpanel uses user_id together with $device_id to map and merge user identities. What happens if a single user is associated with multiple $device_id values?
Great question! Under the Simplified ID Merge API, a single user can be associated with multiple $device_id values, and Mixpanel handles this gracefully.
How It Works
Each time an event is sent containing both a $device_id and a $user_id for the first time, Mixpanel creates (or expands) an identity cluster that links those two IDs together. [Identifying Users (Simplified)] Crucially, there is no limit on the number of $device_ids that can be merged into a single $user_id. All of those device IDs end up in the same identity cluster, and all events associated with any of those IDs are attributed to the same user. [Identity Merge APIs]
Practical Example
Consider a returning user who accesses your product from two different devices:
Device 1 (D1): User browses anonymously, then logs in โ .identify(U1) is called โ D1 and U1 are linked.
Device 2 (D2): The same user browses anonymously on a new device, then logs in again โ .identify(U1) is called โ D2 is added to the existing cluster.
The resulting identity cluster contains D1, D2, and U1, and all events from any of these IDs resolve to the same user in Mixpanel. [Example User Flows]
The Canonical distinct_id
Regardless of how many $device_ids are in the cluster, the canonical distinct_id is always set to the $user_id in the Simplified API. You can use any ID in the cluster for data ingestion, but only the canonical distinct_id (i.e., the $user_id) can be used in queries and exports. [Canonical Distinct ID]
Key Takeaway
The Simplified ID Merge API is specifically designed to support this multi-device scenario. As long as you call .identify(<user_id>) whenever a user logs in on any device, all their anonymous activity across all devices will be stitched together under one user profile. [Client-side Identity Management]
โน๏ธย Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.
kapa.ai We are currently working on a Mixpanel project migration and would like to better understand the correct approach for identity handling. Our old project was NOT using the Simplified ID Merge system. Historically, a single user_id may have been associated with many different $device_id values over time. This happened because of scenarios such as:
users logging in across multiple devices
app reinstalls generating new $device_id
different platforms (web/mobile)
anonymous activity before login
Now we are rebuilding and re-importing historical events into a new Mixpanel project. Our main question is: When migrating historical events into a new project that uses Simplified ID Merge, do we need to also migrate ALL historical $device_id values associated with each user_id? e.g. user_id = "12345" associated device ids: - device_a - device_b - device_c When importing historical events:
Should old events preserve their original $device_id values?
Or can we safely send only the user_id for all events?
If multiple $device_id values are required, what is the recommended migration strategy?
We are concerned about:
fragmented user profiles
duplicated users
broken historical funnels/journeys
anonymous-to-authenticated event stitching
Additionally:
Is there a recommended order for importing anonymous vs authenticated events?
Should we generate explicit $identify events during migration?
Are there any best practices specifically for migrating from a legacy/non-simplified identity setup into Simplified ID Merge?
This is an excellent and detailed question. Here's a structured breakdown based on what the Mixpanel documentation covers:
Do You Need to Migrate All Historical $device_id Values?
Short answer: Yes, preserving original $device_id values on historical events is the recommended approach โ but with important nuances.
How Simplified ID Merge Stitches Identities
Identity merging in Simplified ID Merge is triggered by a single event that contains both $device_id and $user_id. Once such an event is ingested, Mixpanel links those two IDs into an identity cluster. All past and future events associated with either ID are then attributed to the same user. [Migrating to Simplified ID Merge] This means:
If you import historical events for device_a, device_b, and device_c with their original $device_id values, and you also send at least one event containing both $device_id: device_a + $user_id: 12345 (and similarly for device_b and device_c), Mixpanel will merge all of them into one identity cluster.
There is no limit on the number of $device_id values that can be merged under a single $user_id in Simplified ID Merge. [Migrating to Simplified ID Merge]
Should Old Events Preserve Their Original $device_id Values?
Yes, where possible. If your historical events already contain $device_id and $user_id properties (e.g., if you were using Mixpanel Client-Side SDKs previously), those events can be imported directly into the new Simplified ID Merge project without transformation. [Migrating to Simplified ID Merge] If your historical events do not contain these reserved properties (e.g., server-side implementation without them), you will need to transform the events before importing โ deriving $device_id and $user_id from other properties or from ID mappings maintained in your system. [Migrating to Simplified ID Merge]
Can You Safely Send Only $user_id for All Events?
You can, but only for authenticated events where the user was already identified. For anonymous events (pre-login), sending only $user_id would lose the anonymous-to-authenticated stitching entirely, breaking historical funnels and pre-signup attribution. For backward compatibility, Simplified ID Merge does support events sent with only a distinct_id (no $device_id/$user_id):
A distinct_id without the $device: prefix is treated as a $user_id.
A distinct_id with the $device: prefix is treated as a $device_id.
However, the recommended approach is to explicitly include $device_id and $user_id on events. [Migrating to Simplified ID Merge]
What If Historical Events Don't Have Both Properties?
If your historical events lack $device_id/$user_id mappings, the documentation recommends:
Instrument a dummy event that includes both $device_id and $user_id based on your ID mappings and send that to the new project to enable identity merging. You can choose any name for the dummy event except $identify, $create_alias, and $merge. [Migrating to Simplified ID Merge]
So for your example, you would send three such dummy events:
{ $device_id: "device_a", $user_id: "12345" }
{ $device_id: "device_b", $user_id: "12345" }
{ $device_id: "device_c", $user_id: "12345" }
This is sufficient to trigger identity merging for all three device IDs.
Should You Generate $identify Events During Migration?
No. The documentation explicitly states:
You should not send $identify, $create_alias, and $merge events since they will be ignored in Simplified ID Merge projects and will not trigger identity merging. [Migrating to Simplified ID Merge]
Use regular events (or dummy events) with both $device_id and $user_id instead.
Is There a Recommended Import Order?
The documentation does not specify a strict ordering of anonymous vs. authenticated events for import. Since Simplified ID Merge supports retroactive identity merging, the order is less critical โ once a linking event (containing both $device_id and $user_id) is ingested, Mixpanel will stitch past events regardless of when they were imported. However, note that identity merging can take up to 24 hours to be fully reflected in all reports. [Migrating to Simplified ID Merge]
Key Best Practices Summary
Concern | Recommendation |
Fragmented profiles | Preserve original $device_id on events; send dummy linking events for each $device_id โ $user_id pair |
Duplicate users | Include $insert_id on all imported events for deduplication [Backfilling Historical Data] |
Broken funnels | Ensure anonymous events carry their original $device_id so they can be stitched |
$identify events | Do not send them โ they are ignored in Simplified ID Merge |
Validation | Sample key users and compare their event timelines between old and new projects [Validating Identity Management] |
Testing | Test with a subset of historical data in a dev environment before full production import [Data Migration Approach] |
โน๏ธย Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.
If you send a $identify event to a project using the Simplified ID Merge system, it will simply be ignored โ it will not trigger any identity merging. The documentation is explicit on this:
"You should not send $identify, $create_alias, and $merge events since they will be ignored in Simplified ID Merge projects and will not trigger identity merging." [Sending Live Data]
So the practical consequence is: no identity stitching will occur from that event, and your anonymous and identified events will remain unlinked.
What to do instead
To trigger identity merging in a Simplified ID Merge project, send a regular event (or a dummy event with any name you choose, e.g. "login") that includes both $device_id and $user_id properties:
{
"event": "login",
"properties": {
"token": "{{token}}",
"$device_id": "device_a",
"$user_id": "12345"
}
}A single such event is sufficient to trigger the merge. Just make sure not to name the dummy event $identify, $create_alias, or $merge, as those are ignored. [Backfilling Historical Data]
โน๏ธย Tip: Mention @kapa.ai in the thread for follow-ups or DM the app for 1-to-1 help.
