DocsTracking MethodsID ManagementIdentifying Users

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:

  1. 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).
  2. 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 ID user_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

  1. 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_iddistinct_id (set by Mixpanel)Notes
    1D1$device:D1
    2D1$device:D1
  2. 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_iddistinct_id (set by Mixpanel)Notes
    1D1$device:D1U1Retroactively updated
    2D1$device:D1U1Retroactively updated
    3D1U1U1Links D1 ⇒ U1, D1 and U1 are inside one ID cluster

Returning User

  1. The user from the previous flow returns, but is on a new device and has not logged in yet.

    Event$device_id$user_iddistinct_id (set by Mixpanel)Notes
    1D1$device:D1U1
    2D1$device:D1U1
    3D1U1U1Links D1 ⇒ U1
    4D2$device:D2New device D2
    5D2$device:D2
  2. 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_iddistinct_id (set by Mixpanel)Notes
    1D1$device:D1U1
    2D1$device:D1U1
    3D1U1U1Links D1 ⇒ U1
    4D2$device:D2U1Retroactively updated
    5D2$device:D2U1Retroactively updated
    6D2U1U1Links D2 ⇒ U1, D1, D2, and U1 are inside one ID cluster

Multiple Users, One Device

  1. A first user begins using a new device.

    Event$device_id$user_iddistinct_id (set by Mixpanel)Notes
    1D1$device:D1
  2. The user logs in. Call .identify(U1), which links the $device_id to their $user_id.

    Event$device_id$user_iddistinct_id (set by Mixpanel)Notes
    1D1$device:D1U1Retroactively updated
    2D1U1U1Links D1 ⇒ U1, D1 and U1 are inside one ID cluster
  3. 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_iddistinct_id (set by Mixpanel)Notes
    1D1$device:D1U1
    2D1U1U1Links D1 ⇒ U1
    3D2$device:D2Reset generated new ID: D2
    4D2$device:D2
  4. This new user (U2) now logs in. Call .identify(U2).

    Event$device_id$user_iddistinct_id (set by Mixpanel)Notes
    1D1$device:D1U1
    2D1U1U1Links D1 ⇒ U1
    3D2$device:D2U2Retroactively updated
    4D2$device:D2U2Retroactively updated
    5D2U2U2Links 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_ids, not on $user_ids or $device_ids. 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_ids are linked to $user_ids, 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_ids?

It is not possible to merge 2 $user_ids 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?