Docs
Data Structure
User Profiles

User Profile: Demographic attributes for your users

Note: The following terms are used in this section:

  • "Profiles" is used to refer to both "User Profiles" and "Group Profiles"
  • "Profile Properties" is used to refer to both "User Profile Properties" and "Group Profile Properties"

Overview

User Profiles let you enrich events with demographic attributes (i.e. user properties) about the users that performed those events. User Profiles are optional. We recommend starting with events and adding user profiles only if needed.

A user profile has a set of user properties associated with a given user. Under the hood, Mixpanel stores user data for your project in a table wherein each row of user profile contain columns of user properties (e.g. Name, Email, Department) that can be updated:

Distinct IDNameEmailDepartment
123Alicealice@linear.appEngineering
456Bobbob@notion.soProduct
789Carolcarol@figma.comDesign

User profiles are joined onto your events based on their Distinct ID (Mixpanel's identifier for a user). This lets you join the events performed by a user with user properties describing them. Thus, it is very important that you use the same Distinct ID for both the events and user profile for the same user.

For more information about user profiles refer to the documentation on The Mixpanel Data Model.

Note: If you have Group Analytics as an add-on, this section also applies to Group Profiles.

Importing Profiles via API

You can create or update User Profiles in similar ways you track events: from our SDKs, via our HTTP Engage API (opens in a new tab), Warehouse Connectors, or via our integrations partners.

Similarly for Group Profiles, they can be created or updated using our SDKs, via our HTTP Groups API (opens in a new tab), Warehouse Connectors, or via our integration partners.

We recommend tracking profiles from as close as possible to the source of truth, which is usually your application database or your CRM. One typical approach (especially for Server-Side Tracking) is to run an hourly or daily script on your servers that pulls the list of profiles from your database and pushes them to Mixpanel.

Operators

The HTTP Engage API (opens in a new tab) and HTTP Groups API (opens in a new tab) share the same operators.

Setting profile property

  • $set - Sets a profile property or updates a profile property value (if it already exists).
  • $set_once - Sets a profile property only if they do not yet exist on Mixpanel. This ensures that the previous profile property value is not overwritten.

Updating numeric profile property

  • $add - Increments or decrements a numeric user profile property (not supported in group profiles). To increment, pass in a positive numeric value, and to decrement pass in a negative numeric value. If the property does not yet exist, it will set the value passed in as the initial value.

Updating list profile property

  • $union - Merges a given value or list into a List data type profile property and ensures there are no duplicate values.
  • $append - Appends a value to the end of a List data type user profile property (not supported in group profiles). Does not check for duplicate values.
  • $remove - Removes a value from a List data type profile property.

Removing profile properties

  • $unset - Removes a profile property from the profile.
  • $delete - Removes all profile properties from the profile.

Here's some sample code to get you started, utilizing the $set operator to update user profiles:

# Fill this out. You can get it from https://mixpanel.com/settings/project
PROJECT_TOKEN = ""
 
import json
import requests
 
 
def get_users_from_database():
    # Replace this with code that reads users from your database or CRM.
    # Note: $name and $email are optional, but useful properties that automatically populate certain parts of our UI when Mixpanel detects them.
    return [
        {"user_id": "123", "$name": "Alice", "$email": "alice@linear.app", "department": "engineering"},
        {"user_id": "456", "$name": "Bob", "$email": "bob@notion.so", "department": "product"},
        {"user_id": "789", "$name": "Carol", "$email": "carol@figma.com", "department": "design"}
    ]
 
def transform_to_mp_format(user):
    """Transform the above into Mixpanel's format"""
    # It's important to set this to the same distinct_id that you use when tracking events.
    # We recommend using the primary key of your users' table for this.
    distinct_id = user.pop("user_id")
 
    # Note: we set `$ip` to 0 here to tell Mixpanel not to look up the IP of this user.
    return {"$distinct_id": distinct_id, "$token": PROJECT_TOKEN, "$ip": "0", "$set": user}
 
 
users = get_users_from_database()
profiles = [transform_to_mp_format(u) for u in users]
 
# We recommend calling this API with batches of 200 user profiles to do this at scale.
resp = requests.post(
    "https://api.mixpanel.com/engage",
    params={"verbose": "2"},
    headers={"Content-Type": "application/json"},
    data=json.dumps(profiles)
)
 
print(resp.json())

Importing Profiles via the UI

To get started, click on Add/Edit Profile from the Users (opens in a new tab) page and follow the workflow below.

Note: For customers with Group Analytics make sure you first choose either User or the Group Key name depending on which type of profile you wish to import.

/Screen_Shot_2021-12-01_at_11.44.03_AM.png

Create/Update a Single Profile

Set an Identifier Column

The most important column is $distinct_id for user profiles (or $group_id for Group Profiles). The value needs to match the distinct_id property's value (or the value for the Group Key's Group ID) that you're sending on your events.

Add Additional Properties

After $distinct_id, you can add additional properties to the profile by pressing the "+ Add Property" button. Mixpanel will help autocomplete profile properties that you may want to set.

/Screen_Shot_2021-12-01_at_12.20.27_PM.png

We recommend using the $name (or $first_name, $last_name), $email, and $phone Reserved Profile Properties) if you're uploading a user's name, email, or phone. Mixpanel shows these properties by default in various parts of our UI and are used for Cohort Syncs as well.

Bulk Import from CSV

When preparing the CSV that you want to upload as profiles, you should not include column headers (e.g., $name, $email, etc.). Instead, you’ll identify column headers through the CSV upload wizard in the Mixpanel UI.

Note:

  • If you import profiles using $distinct_id (or $group_id) values that already exist, those profiles will be updated with the additional profile properties. On the other hand, if you upload a profile that has the same email address or the same name as another existing profile, but a different $distinct_id (or $group_id), you will be uploading duplicates - they will not be combined.
  • If you upload a CSV with new information for existing properties on existing profiles, the existing property values will be overwritten. If the new information is for new properties on existing profiles, it will be added as additional properties for the profiles.
  • The maximum size for your CSV should be 1M rows.

Upload Your CSV

Go to the Import from CSV tab and select your prepared CSV to begin the process.

Choose an Identifier Column

The most important column in your CSV is the $distinct_id for user profiles (or $group_id for Group Profiles). The value needs to match the distinct_id property's value (or the value for the Group Key's Group ID) that you're sending on your events.

The import module will preview the column values from your CSV on the right, corresponding to the property name you are currently defining.

If you do not assign an identifier column, Mixpanel will use your $email column as the $distinct_id (or $group_id) value; if you don’t have an $email column either, then the $distinct_id (or $group_id) value will be assigned randomly by default. Thus, it is highly recommended that you assign an identifier column to avoid unexpected results.

Choose Desired CSV Columns

You'll have the opportunity to look through all columns in the CSV to preview their values. In this step, you must uncheck all columns that you DO NOT wish to import. You must also choose the associated Mixpanel profile property that each CSV column will be associated with. When you're done selecting the columns, and mapping their associated properties, press the Import profiles button to proceed.

/Screen_Shot_2021-12-01_at_12.24.00_PM.png

Importing Historical Profile Values

Historical profiles layer on additional capabilities by capturing changes in each property over time instead of just the latest value.

See here for more on how to import (opens in a new tab) historical properties via Warehouse connectors.

Historical properties can be used anywhere that regular profile properties can be used.

For eg, when you apply breakdown by historical plan-type property, the property value will be picked based on the time of the event, instead of the current property value. image

When you hover over a historical property, the context menu that pops up will show that the property was sourced from a history table, as well as the name of the source. This means that the value of the property used in charts can vary over time. image

Deleting Profiles

User Profiles can be deleted either via the Users (opens in a new tab) page or programmatically via our Engage API (opens in a new tab). We also provide a people_delete method in the mixpanel-utils library here (opens in a new tab).

Similarly, Group Profiles can also be deleted either via the Users (opens in a new tab) page or programmatically via our Groups API (opens in a new tab).

FAQ

What should I send as a User Property vs an Event Property?

We recommend primarily using User Properties to track demographic attributes of the user, like their name, email, and domain. Most other properties are better tracked as Event Properties.

That said, User Properties are as flexible as any other properties in Mixpanel, so you can send arbitrary JSON.

How does Mixpanel join Events and User Profiles?

Mixpanel stores Events and User Profiles in two separate tables under the hood. These two tables are joined at query-time, rather than ingestion-time. This means that when you make a report in our UI that uses User Profiles, we run a query that joins the Events table with the User Profiles table. This has two implications:

  • If you track User Profiles after you track events, they'll still join retroactively with all past events. This means that you don't need to worry about tracking Events and User Profiles in lockstep with each other. As long as they have the same values for Distinct ID, they'll join with each other.
  • All Events join with the latest state of a User Profile, rather than its state at a point in time. If there are aspects of a user's state that change over time (for example, their plan type), we recommend tracking that as a property on their events, so that you can analyze that change over time.

How can I update User Properties?

User Profiles are mutable; Mixpanel only stores the latest value of each profile property. We have methods to update profile properties via our HTTP API (opens in a new tab).

Why are empty profiles created when I import profiles from a CSV?

This may occur if you set the incorrect column from your CSV as the $distinct_id during your import. You can see which column was erroneously set as the $distinct_id by checking the distinct_id value set on these empty profiles. As a best practice, always check the sample values shown in the import module for each selected profile property.

How do I bulk delete profiles?

We recommend deleting profiles programmatically via our Engage API (opens in a new tab). We also provide a people_delete method in the mixpanel-utils library here (opens in a new tab).

What are the limits of User Properties?

Each User Profile can contain up to 2000 properties. User property names can be at most 255 characters in length (longer names are truncated). User property values are limited based on data type, refer to these limits under Supported Data Types.

Attempts to add more than 2000 user properties for a user profile will fail. You can remove User Properties using the $unset (opens in a new tab) engage operation if you find yourself close to the 2000 per profile limit.

How can I send User Profiles if I use Segment?

Mixpanel is 100% compatible with Segment; just follow Segment's best practices. If you call the analytics.identify() (opens in a new tab) method, Segment will create a User Profile in Mixpanel. You can learn more about our integration in Segment's docs (opens in a new tab).

What does the "Updated at" ($last_seen) property mean?

User Profiles are mutable, which means new ones can be added and existing ones can be updated or deleted. Mixpanel automatically maintains an "Updated at" ($last_seen) property, which contains the last timestamp that a user profile was updated. "Updated at" does not change if the user does a new event; it only changes when the profile is updated. "Updated at" also does not change for profile updates made via the UI or if the $ignore_time parameter is set to true (see example from PHP SDK).

Where can I learn more about Group Profiles?

You can get an overview of how Group Profiles relate to Mixpanel's Data Model under the section Group Level Behaviours and Demographics in our tutorials. A more detailed explanation of Group Profiles is documented under our Group Analytics page.

How are end times applied to the historical property?

The end time will be inferred from the next event sent with a higher Start Timestamp. If you do not have an updated value for a property and simply want it to become inactive at a certain timestamp, please set up your DWH table to set undefined for the property at the time that it becomes inactive/expires.

How do I set the initial set of profile properties for the user?

Historical profile properties can only be imported through a Warehouse Connector sync. For more information about the connectors and which are supported, see our docs (opens in a new tab). There is currently no other method to import historical profile properties or set defaults. To set initial values, please ensure that your warehouse table has the rows covering the historical period you want to analyze.

What if I have the same property name sent as a regular profile property as well as a historic property?

If a regular profile property shares a name with an historic property, the two properties will be treated as distinct and separate entities (they will not be de-dupped).

What if I have the same property name sent through multiple WH syncs?

If both syncs are regular user tables and they refer to the same Distinct ID(s), they will be de-dupped and only the latest value will be retained. If both syncs are historical user tables, we will have a warning popup if the conflict can be detected at sync creation time and you will have the option of renaming one of the columns. If one sync is for regular user table and the other for a historical one, see here (link to previous question).

I deleted my historical user table Warehouse sync and data but there are still empty user profiles!

All the historical props will be deleted from the profile but the profile itself remains, along with any non-historical properties. This is to prevent accidentally deleting profile data sent through API/UI/CSV that might have been merged into the profile data sent via the Warehouse sync. To delete profiles yourself, please use this guide (opens in a new tab).

What is the frequency of updates that are supported?

The feature supports updates at the rate of about one change per day for each user. It is meant to cover use-cases like plan type changes, MRR etc which are slowly changing dimensions. It is not intended for more frequent changes like game score updates.

Was this page useful?