Docs
Identifying Users

Identifying Users (Original)

⚠️

The information on this page is for projects on the Original ID Merge API. Learn more here.

Overview

⚠️

Check your project's ID management version

The information on this page are for projects using the Original ID Merge API. You can check your Identity Merge API by navigating to your project settings (opens in a new tab).

For projects using Simplified 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 Original ID Merge API and exactly how it works under the hood.

Mechanism

The Original ID Merge API uses three special events to link various user identifiers and sets the distinct_id for your events; these events are namely: $identify, $create_alias, and $merge.

$identify

The $identify event is used to link an Anonymous ID and your chosen User ID together. This event is triggered when you call .identify(<user_id>) using our Web/Mobile SDKs, it sends the $identify event to your project containing $identified_id set to the user_id in the function, and $anon_id set to the $device_id ($device_id are automatically generated by the client-side SDK) of the current user.

You can also manually ingest the event server-side. Learn more about this in our API reference here (opens in a new tab).

Upon receiving this event, a mapping is created to merge the $anon_id and $identified_id together to form an Identity Cluster.

//example identify event payload
{
"event": "$identify",
      "properties": {
          "$identified_id": "<user_id>",
          "$anon_id": "<device_id>",
          "token": "YOUR_PROJECT_TOKEN"
      }
}

The $identify event will only merge an $anon_id that is in UUIDv4 format (anonymous ID format generated by Mixpanel and Segment) and only if the $anon_id was not previously merged to another $identified_id.

$create_alias

The $create_alias event is used to link two non-anonymous Distinct IDs. It creates an “alias” to another Distinct ID already present in the identity cluster and adds the same alias ID into the same cluster.

This is triggered when calling .alias using the client-side SDKs.

Multiple alias ID can point to the same Distinct ID, aliases can be daisy-chained; but the same alias ID cannot point to multiple different Distinct IDs. Not all server-side SDKs support alias() method.

This is a legacy function for projects not using ID Merge. Learn more about the alias function here (opens in a new tab).

Here is a technical definition of the $create_alias event in our API reference (opens in a new tab).

$merge

The $merge event allows you to merge any 2 identifiers together. Unlike the $identify events, there are no payload requirements. As long as the merging of 2 IDs does not lead to an ID cluster that exceeds 500 IDs, it will be successful.

This event cannot be triggered using any SDK methods; it can only be processed when sent via the /import API directly. Learn more in our API reference here (opens in a new tab).

//example merge event payload

{
    "event": "$merge",
    "properties": {
      "$distinct_ids": [
        "user_id_1",
        "user_id_2"
      ]
    }
}

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.
⚠️

Calling .reset() frequently can result to reaching the cluster limit within a short time. A best practice would be to only call reset() if there is a definite intent to change user on the same device, example clicking on “Sign-up” button instead of “Login”.

  • Any events prior to calling .identify are considered anonymous events. Mixpanel's SDKs will generate a $device_id and set that to distinct_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. A best practice would be to only call .reset() if there is a definite intent to change user on the same device, example clicking on “Sign-up” button instead of “Login”.

⚠️

The distinct_id is programatically selected by Mixpanel, using one of the IDs inside of an identity cluster, based on the most optimal merging process. This means that the canonical distinct_id could be set to a $device_id or your chosen user_id. This is not user-configurable. You can use any of the IDs in the cluster for ingestion, but only the canonical distinct_id can be used in queries and exports.

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 (D1) and persists it. All events tracked at this point will have distinct_id set to the $device_id value (D1).

  2. The user returns later and signs up for your product. You call .identify(U1). Mixpanel adds U1 and D1 to the same identity cluster. Moving forward, any events tracked using either U1 or D1 will resolve to the same user. Mixpanel will set U1 or D1 as the distinct_id moving forward. This is programatically determined by Mixpanel and is not user-configurable.

Returning User

  1. The user from the previous flow returns, but is on a new device and has not logged in yet. Our SDKs assign the user a random $device_id (D2) and persists it. All events tracked at this point will have distinct_id set to the $device_id value (D2).

  2. The user logs in and a call to .identify(U1) is made to tell us that the user on this device is the same user we have seen before. Mixpanel adds D2 to the identity cluster previous created (D1+U1). Moving forward, any events tracked using distinct_id U1, D1, or D2 will resolve to the same user.

Multiple Users, One Device

  1. A first user begins using a new device. Our SDK will assign the user a random $device_id (D1) and persists it. All events tracked at this point will have distinct_id set to the $device_id value (D1).

  2. The user logs in and a call to .identify(U1) is made, which links the D1 and U1 to the same identity cluster.

  3. The user logs out. At this point, any events triggered will still be linked to U1. We don't call .reset() at this point since we do not know if this is the same user or a totally different user. Not calling .reset() at this point also prevents hitting the 500 ID cluster limit should the same user log back in there will be be new $device_id to link into the cluster.

  4. A different new user shows up and clicks "Sign-up" button on the same device. Before triggering any event we call .reset() to force the clearing of distinct_id and to generate a new random $device_id (D2). This would help us to link any anonymous events as part of the sign-up flow to the new user instead of the previous logged out user.

  5. This new user (U2) now completes sign-up and logs in as a separate user. Call .identify(U2) which will now link D2 and U2 to form one cluster. D1 and U1 remains as a separate 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 a $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 and set it as the distinct_id directly

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 UUIDv4 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 distinct_id event property to the anonymous ID you generated. You do not need to set the $device_id property explicitly; although recommended should you want to track users using multiple or sharing devices.

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.

Merge the IDs together by sending the $identify event.

//example identify event payload
{
"event": "$identify",
      "properties": {
          "$identified_id": "<TRUE_USER_ID>",
          "$anon_id": "<ID_FROM_STEP_1>",
          "token": "<YOUR_PROJECT_TOKEN>"
      }
}

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 only when there is an explicit intent to change to a new user (ie clicking on Sign-up button)

By calling .reset() only when there is an explicit intent to change to a new user, allows you to link any anonymous events, that may be important as part of a user journey, to the new user instead of the previously logged out user. This would also avoid unnecessarily hitting the 500 ID cluster limit when the same previous user simply logs back in since no new $device_id is generated.

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

Why is my user's distinct_id set to the anonymous device ID even after I identify them using my own user ID?

The canonical distinct_id is selected by Mixpanel using any of the IDs inside of a cluster. This means that even after identifying your user, Mixpanel may choose your user ID or one of the other IDs inside of the cluster (such as the device ID) to serve as the displayed ID for the user. This is random and not user-configurable.

Any IDs inside of the cluster can be used for ingestion and will resolve to the same user in Mixpanel, but only the canonical distinct_id can be used in queries and exports..

As a best practice, please set your chosen user ID as a separate user profile property and event property so that you can always query and see your own chosen user ID.

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 an ID merge 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. We recommend waiting until after a user is identified before setting user profile properties.

Is it possible to merge two Identified IDs?

It is possible using the $merge API event (opens in a new tab), which allows merging of any 2 ID clusters as long as it does not exceed 500 total IDs.

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 (opens in a new tab), 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?