User Attributes

There are two types of attributes in Customer and Event attributes.

With Customer attributes, you’re sending us information about your users: things like first_name, is_account_manager or num_projects—any information that is important for your business. Event attributes are information that’s included in your event data, such as the information specific to a particular purchase.

Attributes can be a string, boolean or a number, and can be used to create data-driven segments or to include information in your emails. You will also be able to use these attributes in emails that you send by typing {{customer.first_name}} in your email. Any email can access a customer attribute, but event attributes are available only in event triggered emails.

Every customer attribute is stored under a customer object, so you can access any attribute with {{customer.ATTRIBUTE_NAME}}.

Every event attribute is stored under an event object, so to access those attributes in your event triggered emails you’ll use {{event.ATTRIBUTE_NAME}} (the actual word event, not your event name).

How do I send you user attribute data?

Pass customer attributes through the _cio.identify() function in the JavaScript snippet. Alternatively, you can send user attributes using the REST API.

Here’s an example of how to send custom user attributes:

<script type="text/javascript">
      id:         'userid_34', // must be unique per customer
      email:      '',
      created_at: 1333688268, // seconds since the epoch (January 1, 1970)

      // Custom user attributes
      first_name:  'Joe',
      plan_name:  'free',
      is_account_manager: true,
      num_projects:  15

Internal attributes

We reserve the use of all user attributes beginning with an underscore _ for internal use only. These attributes aren’t eligible for segmentation, searching, or triggering of campaigns.

For example: if you have a segment for “Americans” built on the attribute country being equal to “America”, that will work. If you instead use _country, you can still send us that attribute, but any customers with it will not be eligible for segmentation, no matter what its value.

Updating identifiers

If your workspace supports multiple identifiers—email, ID, etc—you can create a person without setting all of their identifiers. You might need to set or change these attribute values on people in your workspace after you add them.

You cannot update a person’s identifiers using a CSV.

You can set or update identifiers for people:

  • As a part of a campaign using Attribute Update actions.
  • By selecting individual profiles on the People page and going to the Attributes tab.
  • Using the API.

When using our API, if you haven’t set an identifier for a person, you can set the attribute as you normally would. If a person has an identifier value, and you want to update that identifier value using the API, you must reference them by their cio_id, prefixed by cio_; you can look up a customer to find their cio_id. For example:

  • if your workspace supports both id and email as identifiers, and a person has an email but does not have an id assigned, you can reference a person by their email address to assign them an id.
      curl --request PUT \
      --url \
      --header "Authorization: Basic $(echo -n site_id:api_key | base64)" \
      --header 'content-type: application/json' \
      --data '{"id":"12345"}'
  • If a person has both an email and id, you must reference them by their cio_id to update either their email or id. In this example, we’ll assume a person’s cio_id is 03000001.
      curl --request PUT \
      --url \
      --header "Authorization: Basic $(echo -n site_id:api_key | base64)" \
      --header 'content-type: application/json' \
      --data '{"email":""}'

Create a segment based on user attributes

Once you are sending us custom attributes, you’ll have a lot of flexibility in how you can use them to create data-driven segments. Here’s a simple example for the attribute is_account_manager:


You can also set the numeric value of an attribute:


In fact, there’s a great deal of flexibility in how you can define your segments:

Segmentation options
Segmentation options

You can also check whether an attribute is between two values. For example, if you want to isolate customers with an NPS score of 5-8 (inclusive), you can do so with the “is between” option in the attribute dropdown:


Create segment based on event attributes

If you’re including event data in your events, you’ll be able to segment based on that information. For example, if you’d like to know who bought a t-shirt:


You’ll be able to segment by one piece of event data in each condition.

Also, if you want to know who bought a t-shirt recently (within the last month, maybe), you can do that too. Click Refine and add your timeframe:


Important things to know

Reserved attributes has reserved attributes to support core functionality in the platform.

Attribute Purpose Required Data Format
id A unique identifier for people. If the id does not yet exist, we create a new person. When importing by id Our default id limit is set to 150 characters. All valid utf characters are allowed.
email A person’s email address. If your workspace uses email as a unique identifier (the default setting for new workspaces), and the email address does not yet exist, we create a new person. The TO line of your email templates is prefilled with this attribute. When importing by email We support valid RFC 5322 email addresses.
created_at Recommended. Holds the date when a profile was created. This value lets you to take advantage of timestamp operators in segments and helps you determine the age of a person’s profile. Optional We support:
- unix epoch
- unix epoch
unsubscribed Determines whether a person is subscribed or unsubscribed from your campaigns and newsletters. (reference) Optional We support any case of true (i.e. TRUE, true, tRUe, etc.) or ‘1’ to represent unsubscribed. Any other value is considered “false”, or subscribed.
mobile_ad_id Used to record either Apple’s Advertising Identifier (IDFA) or Android’s Advertising ID (AAID). This id can improve match accuracy in Google or Facebook Ads when using Ad Audiences. Optional Apple’s Advertising Identifier (IDFA) or Android’s Advertising ID (AAID)
email_sha256 To keep your data secure, you can hash your customer email using the SHA256 algorithm before sending it to your account. This field is only used in Ad Audiences and cannot be used to send messages. Optional Valid encoded sha256
mobile_ad_id_sha256 To keep your data secure, you can hash the mobilead_id using the SHA256 algorithm before sending it to your account. _This field is only used in Ad Audiences. Optional Valid encoded sha256

Using attributes in messages:

Customer attributes come from the user’s profile and are available in any message type. They are pulled into your message content by using Liquid code like {{ customer.attribute_name}} in your message templates.

Event attributes come from the data you include in the events you send and are only available in event-triggered campaigns. They are pulled into your message content by using Liquid code like {{ event.attribute_name}} in your message templates.

Attribute data types:

Currently, attribute values in are only simple strings, booleans or numbers.

We do, however, make your strings available as arrays or JSON objects inside your email templates for convenience (if they are correctly formatted as such), but we do not currently distinguish them as being different data types such as arrays and dictionaries, etc. You can use Liquid templating in your email templates to output values from your JSON values like: {{ }} but you cannot access these nested values in the same manner when segmenting or filtering.

Formatting your attributes:

Let booleans be booleans, not strings. For example:

Good: is_account_manager: true
Bad: is_account_manager: 'true'

The boolean (true/false) shouldn’t have quotation marks around it.

Also, let numbers be numbers, not strings:

Good: num_projects: 15
Bad: num_projects: '15'

Chronology of attribute updates:

Attribute updates (identify() API calls) are processed in the order we receive them. However, due to various network conditions, we can’t guarantee that we will receive them in the order you send them. To ensure your attributes end up with the values you intend, you’ll want to add an additional attribute to each API call named _timestamp. The _timestamp value should be a UNIX timestamp that represents the date and time the update was made.

When we receive multiple attribute updates for the same user:

  • If the updates do not include a _timestamp value, the attribute values in the last update we process will prevail.
  • If the updates include a _timestamp value, the attribute values in the update having the newest _timestamp will prevail.
  • If the updates include the same _timestamp value, the attribute values in the first update will prevail. Values for existing attributes sent in subsequent updates will be ignored. Values for attributes sent in subsequent updates - that were not sent in the first update - will not be ignored. They will be added if they do not already exist. If they do already exist, they will be updated so long as the _timestamp value for this call is newer than the timestamp of the last update those attributes were a part of.

Please note that this is accurate down to the second. If requests are sent within microseconds of each other, there is still the potential that they could be out of order.

Here is an example set of API calls for our US region containing a _timestamp value. If your account is in the EU region, make sure you use the URL.


curl -i \
-X PUT \
-u site-id:api-key \
-d _timestamp=1522081942 \
-d Attr1='attr1_val3_sent1st_timestamp=1522081942(newer)'


curl -i \
-X PUT \
-u site-id:api-key \
-d _timestamp=1522081941 \
-d Attr1='attr1_val1_sent2nd_timestamp=1522081941(older)' \
-d Attr2='attr2_val2_sent2nd_timestamp=1522081941(older)'

And here is the final outcome:

Final outcome.
Final outcome.

Notice we did not drop the second request with the older _timestamp value. Instead, we still processed the second request but only updated the attribute (Attr2) that did not already exist from a call that had a newer _timestamp value.

Removing attributes:

To remove unwanted attributes you’ll need to remove the attribute from all profiles. As soon as no one in your Peoples list is using the attribute, it will be effectively removed. You can remove the attribute from profiles in bulk by:

  1. Using our API to update every profile in your account to have a null/empty string ("") as their value for the unwanted attribute names, or
  2. Using our CSV import feature to overwrite the attribute data with empty values.
  3. Using an Attribute Update in a campaign to remove the attribute. Read more on how here.

If any of the deleted attributes belong to profiles that have been deleted, they may take 24 hours or more to completely disappear from your account.

If you notice they still persist even longer, please reach out to with examples so we can investigate.

Copied to clipboard!