Identifying Users (Simplified)
The information on this page is for projects on the Simplified ID Merge API. Learn more here.
Overview
Check your project’s ID management version
The information on this page is for projects using the Simplified ID Merge API. You can check your Identity Merge API by navigating to your project settings.
For projects using Original ID Merge API, please refer to this documentation here.
Learn more about the different ID Merge APIs here.
Mixpanel supports stitching user behavior pre-login (eg: traffic from your website, docs, blog) and post-login (once the user has signed up). This helps answer questions like:
- What % of site visitors end up signing up?
- How much of my Purchase revenue can I attribute to a particular campaign?
- What is the conversion rate of reading a particular blog post -> signing up?
This system is called ID Merge. In this guide, we walk through how to identify users in projects using the Simplified ID Merge API and exactly how it works under the hood.
Mechanism
The Simplified ID Merge API uses the $device_id
and $user_id
event properties to determine the distinct_id
that is set for your events.
distinct_id
The distinct_id
property (learn more here ) is the identifier property that Mixpanel uses to determine the uniqueness of your users.
$device_id
The $device_id
event property is automatically generated by our client-side SDK and then attached to all of the user’s events. All client-side events should contain a $device_id
.
If an event contains a $device_id
without a $user_id
, the value of the $device_id
will be set as the distinct_id
for that event.
We can consider the $device_id
as the anonymous ID for the user.
$user_id
Calling identify(<user_id>)
sets the user_id
value passed to the identify function as the $user_id
event property for the user’s events moving forward.
If an event contains a $user_id
, the value of the $user_id
will be set as the distinct_id
for that event.
When a $user_id
and $device_id
are present in the same event for the first time, a mapping is created to merge the $user_id
and $device_id
values together, forming an identity cluster. Any data sent with a distinct_id
set to any of the values in an ID cluster will be attributed back to the same user in Mixpanel.
Client-side Identity Management
If using our Web/Mobile SDKs or a CDP like Segment or Rudderstack, there are only 2 steps:
- Call
.identify(<user_id>)
when a user signs up or logs in. Pass in the user’s known identifier (eg: their ID from your database). - Call
.reset()
when a user logs out.
-
Any events prior to calling
.identify
are considered anonymous events. Mixpanel’s SDKs will generate a$device_id
to associate these events to the same anonymous user. By calling.identify(<user_id>)
when a user signs up or logs in, you’re telling Mixpanel that$device_id
belongs to a known user with IDuser_id
. -
Under the hood, Mixpanel will stitch the event streams of those users together. This works even if a user has multiple anonymous sessions (eg: on desktop and mobile). As long as you always call
.identify
when the user logs in, all of that activity will be stitched together. -
Calling
.reset
will clear the local storage (which contains the$user_id
and$device_id
), and generate a new$device_id
for the session. It is recommended to call.reset
when a user logout or times out of an authenticated session to prevent the unintentional merging of multiple users sharing one device.
Example User Flows
Let’s walk through a few user flows where ID Merge is useful, and when to call .identify()
and .reset()
to use ID Merge properly.
New User Signup
-
A user lands in your product on a new device and interacts with your product before signing up. Our SDK will assign the user a random
$device_id
and persist it. All events tracked at this point will send only a$device_id
.Event $device_id $user_id distinct_id (set by Mixpanel) Notes 1 D1 $device:D1 2 D1 $device:D1 -
The user returns later and signs up for your product. You call
.identify(U1)
. All events sent after this point are tracked with both the original$device_id
and the new$user_id
. Mixpanel will retroactively set the$user_id
on any prior events with the user’s$device_id
so that both event streams are joined.Event $device_id $user_id distinct_id (set by Mixpanel) Notes 1 D1 $device:D1⇒ U1Retroactively updated 2 D1 $device:D1⇒ U1Retroactively updated 3 D1 U1 U1 Links D1 ⇒ U1, D1 and U1 are inside one ID cluster
Returning User
-
The user from the previous flow returns, but is on a new device and has not logged in yet.
Event $device_id $user_id distinct_id (set by Mixpanel) Notes 1 D1 $device:D1⇒ U12 D1 $device:D1⇒ U13 D1 U1 U1 Links D1 ⇒ U1 4 D2 $device:D2 New device D2 5 D2 $device:D2 -
The user logs in. Call
.identify(U1)
to tell us that the user on this device is the same$user_id
we have seen before.Event $device_id $user_id distinct_id (set by Mixpanel) Notes 1 D1 $device:D1⇒ U12 D1 $device:D1⇒ U13 D1 U1 U1 Links D1 ⇒ U1 4 D2 $device:D2⇒ U1Retroactively updated 5 D2 $device:D2⇒ U1Retroactively updated 6 D2 U1 U1 Links D2 ⇒ U1, D1, D2, and U1 are inside one ID cluster
Multiple Users, One Device
-
A first user begins using a new device.
Event $device_id $user_id distinct_id (set by Mixpanel) Notes 1 D1 $device:D1 -
The user logs in. Call
.identify(U1)
, which links the$device_id
to their$user_id
.Event $device_id $user_id distinct_id (set by Mixpanel) Notes 1 D1 $device:D1⇒ U1Retroactively updated 2 D1 U1 U1 Links D1 ⇒ U1, D1 and U1 are inside one ID cluster -
The user logs out. At this point, you should call
.reset()
, or manually generate a new$device_id
if you are managing it yourself. A new user shows up and tracks events using this new$device_id
.Event $device_id $user_id distinct_id (set by Mixpanel) Notes 1 D1 $device:D1⇒ U12 D1 U1 U1 Links D1 ⇒ U1 3 D2 $device:D2 Reset generated new ID: D2 4 D2 $device:D2 -
This new user (U2) now logs in. Call
.identify(U2)
.Event $device_id $user_id distinct_id (set by Mixpanel) Notes 1 D1 $device:D1⇒ U12 D1 U1 U1 Links D1 ⇒ U1 3 D2 $device:D2⇒ U2Retroactively updated 4 D2 $device:D2⇒ U2Retroactively updated 5 D2 U2 U2 Links D2 ⇒ U2, D1, D2, and U1 are inside one ID cluster
Server-side Identity Management
Our server libraries normally require that you specify the distinct_id
value for each event. If you don’t know the user’s identity at the time the event is tracked, then they’re an anonymous user.
When using our Web or Mobile SDKs, Mixpanel will automatically generate an $device_id
that’s local to that user’s device, and set that value as the distinct_id
for the event. This ID will persist on all events tracked by that user on that device, until you call identify()
or reset()
.
If you’re tracking from servers, you’ll need to generate and manage the IDs yourself. We recommend not setting the distinct_id
directly; instead you should set the $device_id
and $user_id
and have our API determine the distinct_id
for you.
Step 1 - Generate an Anonymous ID
The key is to have an ID that is unique to each user and persists during that user’s session. We recommend generating a UUID and storing that value in a cookie. All common server frameworks provide a simple way to set and retrieve cookies per request.
Step 2 - Leverage Anonymous ID for anonymous events
Set the $device_id
event property to the anonymous ID you generated. You do not need to set the distinct_id
property since it will be assumed to $device_id
if there is no $user_id
present in the event.
Step 3 - Set the Authenticated ID once users log in
Once the user logs in, you know their true ID, you should leverage the new ID for the user.
Set the $user_id
property to the Authenticated ID and continue setting $device_id
to the Anonymous ID generated in step 1, including both the $user_id
and $device_id
in your events moving forward.
If Mixpanel receives an event with both $device_id
and $user_id
set, it will merge the two IDs together. This is essential to track pre-login and post-login behavior accurately. The distinct_id
will be assumed to the $user_id
.
If you choose to manually define the distinct_id
property, it should be the same value as the $user_id
.
Example Python
Here’s a pseudocode example using Django’s cookies and authentication. It assumes the client is setting and sending cookies:
import uuid
def track_to_mp(request, event_name, properties):
# This assumes you've previously set a cookie called "SESSION_ID" that is local to the user's session
# Set `$device_id` to that cookie's value
properties["$device_id"] = request.cookies.get('SESSION_ID')
# Set $user_id if the user is authenticated (logged in).
if request.user.is_authenticated():
properties["$user_id"] = request.user.username
# Note: leave the first argument blank here, since we're passing $device_id and $user_id as properties.
mp.track("", event_name, properties)
Best Practices
Call .identify
upon a registration/login or when an app is re-opened in a logged-in state
By calling .identify()
at these specific points in user journeys, you would be able to link the pre and post-login events to the same user on Mixpanel. Besides, calling .identify
when the users re-open the app in a logged-in state ensures that all events in the session are tracked with the user’s identifier such as user id.
Call .reset
upon logout or when an app leaves an authenticated-state
By calling .reset()
at logout or when a user enters an unauthenticated-state (such as timing out), you generate a new $device_id
for your user, ensuring that multiple users that are sharing a single device would not be incorrect considered as a single user tracking events with the same IDs.
Track the unique identifier as a super property and user property to assist in troubleshooting
You can track the user’s unique identifier as a super property via .register()
and user property via .people.set()
as soon as it is available in the app i.e. on a successful sign-up / login or when an app is re-opened in a logged in state. In the cases when ID Merge is not implemented properly, you can rely on these properties for troubleshooting purposes.
See the SDK reference on registering super properties and setting profile properties.
Avoid creating profiles for anonymous users
Avoid creating profiles for anonymous users. If possible, cache user profile properties update in cookie or local storage and only send them to Mixpanel after the user is identified (ie logged-in state).
QA your ID management implementation during the development phase
Here are a few things to look out for:
- Ensure that cross-platform, pre and post-registration events are linked to the same user on Mixpanel.
- Ensure that no duplicate profiles are created as the users go through the onboarding, registration, login, and cross-platform user journey.
- Ensure that all the user’s identifiers are stored in the same Identity Cluster and that all their events are displayed on a single profile on Mixpanel.
Keep a record of your ID management implementation
We encourage you to document your implementation (or create a diagram of the implementation). This will come in handy when you need to re-implement this on a new platform or troubleshoot ID management issue.
FAQ
What does Mixpanel recommend using as the $user_id
?
We recommend using an ID that is unique to each user and does not change, for example, a database ID. While using an identifier like email may be more convenient, keep in mind that you cannot merge 2 $user_ids
or change a $user_id
, so if the user changes their email, they will count as a separate user.
How long does it take for the $device_id
-> $user_id
mapping to take effect?
For debugging purposes, the Activity Feed view of a single user is updated in real-time (less than 1 minute delay). You can get to the Activity Feed by navigating to Users and selecting a given user.
It may take up to 24 hours for this mapping to propagate to all other parts of the system. This means that, in some cases, when analyzing a funnel that spans pre-login and post-login behavior in real-time, some may be shown as dropped-off, even though they’ve performed the conversion event.
How does this relate to User Profiles?
User Profiles are set directly on $distinct_id
s, not on $user_id
s or $device_id
s. We recommend waiting until after a user is identified before setting user profile properties.
It is possible to set user profile properties for unidentified users by sending the profile updates to $distinct_id=$device:<device-id>
. However, user profile properties are not preserved when $device_id
s are linked to $user_id
s, so any properties set before the IDs became linked will need to be set again using $distinct_id=<user-id>
once the user is identified.
Is it possible to merge two $user_id
s?
It is not possible to merge 2 $user_id
s together using the Simplified API. We don’t recommend doing this in general, as it adds complexity to your identity resolution strategy. Instead, we recommend having a single, unchanging $user_id
for each user and pointing all other IDs for that user to that single $user_id
.
How should I link identified IDs from 3rd-party systems?
Attribution providers (like Appsflyer, Adjust, and Branch) use Mixpanel’s SDK properly to set $device_id
to whichever ID they use for attribution.
For cohort syncs out to 3rd-party systems, we recommend designating a user property with the identifier of the user in that third-party system. More details are in our integrations docs; for example, see our doc on exporting cohorts to Braze. If those integrations are bidirectional (eg: they send events back to Mixpanel), it’s best to ensure that the user ID in both Mixpanel and the 3rd-party system is the same so that those events are sent to the correct user.
What is the status of Mixpanel’s legacy alias
method?
Prior to March 2020, the only way to connect users together was the .alias()
method. This was very limited and was not retroactive; this meant that if a user used two devices and then logged in, you would lose activity for the user from one of the devices.
If you set up Mixpanel prior to 2020, you may have implemented using the .alias()
method. Alias is still supported in its original state and we have preserved its documentation here, but if you want to revisit your identity management strategy, we recommend setting up a new Mixpanel project and using the best practices outlined in this guide.
Was this page useful?