Reach out with questions, bugs, or suggestions. We'll respond ASAP. Your message is sent! We'll respond via email shortly.

User Identities and Properties

Heap empowers you to use the rich information about your users to build enhanced reports, and better understand how they interact with your site or app.

There are two primary APIs for enriching user data in Heap. The identify API allows you to identify users with a unique identifier and maintain user histories across sessions and devices under a single profile. The addUserProperties API allows you to attach custom properties to your users, whether they are identified, or still anonymous.


All examples in this document refer to the client-side identify, and addUserProperties APIs.

Anonymous Users

When a person interacts with your site or app, Heap generates a random unique user ID and stores it in a cookie, or on iOS, in NSUserDefaults. In Heap, these people will appear in the List view as "User 123456" where the 123456 is their user ID, we refer to these users as anonymous users throughout this document.

Identified Users

You can use the identify API to attach your own unique identifier to a user. The identify API takes a single case-sensitive string value as an argument. For example: heap.identify('alice1234').

If you use the same identity for another user, their past sessions and event activity will be merged into the existing Heap user with that identity.

User Properties

The addUserProperties API can be used to attach properties to users' profiles. Heap sets some of these properties automatically, like Initial City, Initial Referrer, and Initial Landing Page. You can set any property, with any value, as long as those values are a string or an integer.

Some practical properties to use include: payment plan, marketing segment, or A/B experiment. Once set, these properties can be used in reports to group by and filter against. You don't need to use a unique identifier to add new properties since Heap already maintains a unique user ID associated with the user. See here for some specific examples.

When and Where to Call identify and addUserProperties

The identify and addUserProperties APIs can be called at any time, and as many times as needed. The typical place for an identify call that includes a unique identifier is on any post-login, or post-signup page. When setting properties, it's OK to call the addUserProperties API on any page.


Anonymous to New Identity

Let's say we have an internal user ID from our own database, and we want to identify a user based on that ID, we can do that like this:


Now their profile in the List view will look like this:

Anonymous to Existing Identity

In the last example, we identified a user with the unique user ID of 12345. Let's say that this person visits your site from their mobile device for the first time. Heap will generate a new, random, unique user ID, in this case it's 1565941335949135. In Heap's list view, this visitor looks like this:

When this person logs in, and you recognize that their internal user ID is 12345, and call identify like this:


The previous user's profile with the random user ID of 1565941335949135 is merged, along with its previous sessions and events into the Heap profile of the identified user with the identity of 12345.

Identified User to New Identity

In some rare scenarios, a person who we already identified visits your site and is identified with a new ID. A person, let's call her Kate, creates an account on your site, then, her friend Jack uses the same browser to create an account.

The identify calls will look the same as in the previous examples. Before the identify call is made, all the sessions, page views, and event data for this person will be associated with Kate's existing identity in Heap.

After identify is called when Jack signs up, all session, page view, and event data from that point on, will appear in a new profile associated with Jack. To understand what happens if Kate returns and logs in, see the next example.

Identified User to Existing Identity

In the previous example, we described how, after Kate was identified, Jack visited the site from the same computer. Jack was identified and a new Heap profile was created.

What happens if Kate returns to the site on the same browser after Jack was using it?

When this happens, all of Kate's session, page view, and event data associated with the current session appear in Jack's Heap profile, since he was the last one to be identified. When Kate logs in, and is identified, only data from that point on now appear with the existing data already in Kate's profile.

Uses of Properties

A/B Testing

Optimizely Experiments

If you're running experiments through Optimizely, it's easy to send over experiment information to Heap using the addUserProperties API. Sending experiment data to Heap can help you see more granular information about conversions and usage. If you're using Segment you can skip this entirely, and go to your Optimizely integration and check the box next to Send experiment data to other tools (as an identify call).

This example assumes you've already installed Optimizely and have started running experiments.

We can use Optimizely's API to send the names of all the active experiments, along with their variations to Heap. Optimizely stores all the necessary information in the optimizely object, described in more detail here:

Active Experiment IDs

optimizely.activeExperiments is an array with the list of active experiment IDs, it looks like this: ["8675309", "72680"]

Experiment Names

Optimizely provides an object called which lets you map an experiment ID to more detailed information about the experiment, but all we need to know is that there is also a property called name, so, for example, using the experiment ID from above, 8675309, we can find out the name for that experiment with["8675309"].name

Variation IDs

Each experiment can have a number of variations. Just like experiments, they are referenced by their variation ID, which can be mapped to a variation name. We're using names for this example because it will make the data easier to understand when it's in Heap. We can read variation names directly with the experiment IDs from above, but in case you're curious, the variation IDs are available in optimizely.variationMap

Variation Names

The names of the experiments and variations are defined initially by you in the Optimizely dashboard. This example uses the API to read those names. To get the variation name for one of the active experiments, you can use optimizely.variationNamesMap["8675309"]

Bringing it All Together

If you're using Optimizely Classic, use this code block:

// Create an object to store experiment names and variations
var props = {}

for (idx in optimizely.activeExperiments) {
    props[[optimizely.activeExperiments[idx]].name] = optimizely.variationNamesMap[optimizely.activeExperiments[idx]];


If you're using Optimizely X, use this code block:

// Create an object to store experiment names and variations
var props = {}

// This covers both A/B Experiments and Peresonalization
var camState = optimizely.get("state").getCampaignStates({"isActive": true});

    for (x in camState) {
        if(camState.isInCampaignHoldback != true){
            props[camState[x].id] = camState[x];

            props[camState[x].id] = "Campaign Hold Back";

If we have two experiments running, called Experiment #1 and Experiment #2, and the visitor was in Variation A and Variation B respectively, the resulting props object would look like this:

{"Experiment #1": "Variation A", "Experiment #2": "Variation B"}

Since heap.addUserProperties takes an object as its only parameter, this maps directly. Once this data is in Heap, it will look like this in a user's profile in the List view, and a funnel:

Visual Website Optimizer (VWO)

VWO is another popular A/B testing platform and integration with Heap works similarly to the example given above. The code below converts VWO experiment data into an object which gets passed to heap.addUserProperties. It assumes you have already installed VWO on your site.

Put this code on every page you're running experiments, after both the VWO snippet and the Heap snippet.

var _vis_opt_queue = window._vis_opt_queue || [], _vis_counter = 0, heap = window.heap || [];
_vis_opt_queue.push(function() {
    try {
        if(!_vis_counter) {
            var _vis_data = {},_vis_combination,_vis_id,_vis_l=0;
            for(;_vis_l<_vwo_exp_ids.length;_vis_l++) {
                _vis_id = _vwo_exp_ids[_vis_l];
                if(_vwo_exp[_vis_id].ready) {
                    _vis_combination = _vis_opt_readCookie('_vis_opt_exp_'+_vis_id+'_combi');
                    if(typeof(_vwo_exp[_vis_id].combination_chosen) != "undefined")
                        _vis_combination = _vwo_exp[_vis_id].combination_chosen;
                    if(typeof(_vwo_exp[_vis_id].comb_n[_vis_combination]) != "undefined") {
                        _vis_data['VWO-Test-ID-'+_vis_id] = _vwo_exp[_vis_id].comb_n[_vis_combination];
            // Use the _vis_data object created above to fetch the data,
            // key of the object is the Test ID and the value is Variation Name
            if(_vis_counter) {
    catch(err) {};

In your List view, your VWO experiment data will look something like this:

Account Plan

Many products include some sort of tiered pricing plans. Using heap.addUserProperties to attach this information to your visitors' Heap profiles can help you understand usage between different segments.

Heap's own pricing tiers include Free, Startup, Premium, and Enterprise. We use the addUserProperties API ourselves to measure the success of different product features depending on the account tier.

Example When someone visits Heap, we pull their account tier from our database and inject that into an identify call like this:

heap.addUserProperties({plan: "Startup"})

This lets us build powerful reports, like this graph report, showing sign ups split by the plan.

Identify Pitfalls

Using a Non-Unique Identifier

A common assumption is that a unique identifier attached via identify is required in order for the addUserProperties API to attach properties to a user. In cases where a unique identifier isn't available, we've seen people include a specific name, like guest, or Anonymous User.

This can cause catastrophic behavior with how Heap merges user profiles. You can call addUserProperties at any time, whether or not the user has been given a unique identity.


Let's say that you have a marketing campaign, and you want to associate it with a visitor when they visit your landing page. They aren't logged in, so you don't have a unique identifier.

Don't Do This

heap.addUserProperties({campaign: 'Campaign Name'});

What this will do, is merge all visitors into a single user profile called guest. This will break any metrics that rely on user flow, or the unique user count.


heap.addUserProperties({campaign: 'Campaign Name'})

Now, the campaign property will be associated with the anonymous user, using the value of the JavaScript variable campaign.

Adding an Anonymous Unique Identifier of Your Own

Some tools require a unique identifier to be provided in order to add user-level properties. This leads people to adding their own unique identifier to all visitors. Heap automatically assigns each user a user ID so you are not required to call identify to add user-level properties. Assigning an identity to a user when it is not required can lead to undesirable, or unexpected behavior.

In the earlier section Identified User to New Identity, we covered what happens when an identified user is identified again with a different identity. Heap does not allow you change an already applied identity or assign multiple identities to the same user. If you call identify with an anonymized identity, for example, a uuid or random hash, this will be their permanent identity in Heap. If you call the identify API at another time for the same user with a different identity, such as an internal user ID or username, this will create a new user in Heap, splitting this users into two identified users, one with the random uuid containing all the historical events, and another with the user ID or username which has events going forward.

Since Heap automatically creates a randomized unique identifier, it's not necessary for you to send your own identifier unless you are certain it is a unique, permanent identifier for the user. If you want to add properties to a user using addUserProperties, you can do so without providing a unique identifier. Calling heap.addUserProperties({property: 'value'}) will add this property to the anonymous user's Heap profile automatically.

Limitations of Server-Side Identify

Heap's server-side identify API allows you to set user-level properties without having them tied to an existing session. This is useful when you want to back-fill certain values that may not have been available at the time someone was visiting your site, or using your app.

The server-side API only takes a single identity parameter as its first argument. The client-side API acts within the context of a session, and because of this, uses a known Heap user ID when attaching properties. Since that user ID is not readily available when using the server-side API call, it's up to you to know the user's identity when applying properties.

The server-side API call can only be used to create new Heap users with a specific identity in Heap, and to add properties to a known identity. It cannot be used to merge, or "alias" two different users into the same Heap profile.