User Attributes
UpdatedAttributes represent the things you know about your audience—their name, preferences, email address, etc.
How it works
Attributes are data points about people in your audience: things like first_name
, is_account_manager
or num_projects
—any information that is important for your business.
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.
Attributes are stored in the customer
object, so you can access any attribute with {{customer.ATTRIBUTE_NAME}}
.
Avoid storing sensitive information in Customer.io
You should limit the personal data you store to what you’ll use in Customer.io. You should not store sensitive data passwords and other tokens in Customer.io. While we take every effort to protect you and your customers’ data, limiting the data you share outside your backend systems limits potential security concerns and helps you respect your customers’ privacy.
When troubleshooting support tickets, you can grant Customer.io support access to your workspace for a limited time. When you grant access, Customer.io support personnel can see your audience’s attributes and the data you store.
Attribute names are case sensitive
Before you map out the attributes that you want to store, you should know that attribute names are case sensitive. So, if you send an attribute for some people called first_name
and attribute called First_name
for other people, you’ll have two different attributes in your workspace.
This can make it hard to personalize messages with liquidA syntax that supports variables, letting you personalize messages for your audience. For example, if you want to reference a person’s first name, you might use the variable {{customer.first_name}}
. or add the right people to segmentsA group of people who match a series of conditions. People enter and exit the segment automatically when they match or stop matching conditions.—because not everybody will have the same attribute.
As you get started, make sure that you use a consistent naming scheme for attributes so that it’s easy to target attributes in segments or with liquid. You can use the data index to identify inconsistencies in your attribute names.
We also recommend that you avoid using spaces, periods or special characters in attribute names, because it can make it hard to reference your attributes with liquidA syntax that supports variables, letting you personalize messages for your audience. For example, if you want to reference a person’s first name, you might use the variable {{customer.first_name}}
..
How do I send attribute data?
You can pass customer attributes whenver you identifyThe Customer.io operation that adds or updates a person. When you identify a person, Customer.io either adds a person if they don’t exist in your workspace, or updates them if they do. Before you identify someone (by their email address or an ID), you can track them anonymously. someone. We’ve provided examples using the identify
function for our JavaScript integrations below, but you can use any of our source integrations or our API to send attribute data.
analytics.identify('userid_34', {
first_name: 'joe',
email: 'joe@example.com'
created_at: 1339438758, // strongly recommended when you first identify someone
plan_name: 'free',
is_account_manager: true,
num_projects: 15
});
_cio.identify({
id: 'userid_34', // must be unique per customer
email: 'customer@example.com',
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.
Identifiers
The values that identify a unique person are called Identifiers; typically, these are id
and email
. In most cases, you can treat these values as attributes.
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. Like other attributes, unless they are already set.
If an identifier is already set, you can change it:
- Using a Create or update person action in a campaign or on the People page.
- Identifying a person by cio_idAn identifier for a person that is automatically generated by Customer.io and cannot be changed. This identifier provides a complete, unbroken record of a person across changes to their other identifiers (id, email, etc). in a CSV or API request.
- You can change an
email
using anid
through the API or any integration if you enable the Allow updates to email using ID setting in your workspace.
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:
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
Customer.io 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. |
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 | Valid RFC 5322 email addresses. | |
cio_id | A unique, immutable identifier set by Customer.io, set automatically when you add a person. | Created by Customer.io | string |
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 | unix epoch |
_created_in_customerio_at | The date-time when a person was added in Customer.io. This value can be different from created_at . In the API, this value is represented by the timestamp for the cio_id attribute. | Created by Customer.io | 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 |
Customer.io has also reserved these object and relationship attributes:
Attribute | Purpose | Required | Data Format |
---|---|---|---|
cio_object_id | A unique, immutable identifier for objects provided by Customer.io. If this does not yet exist in your workspace, we create a new object. | When importing by cio_object_id | |
object_id | A unique identifier for objects. If the object_id does not yet exist, we create a new object. | When importing by object_id | Our default id limit is set to 150 characters. All valid UTF characters are allowed. |
objectId | String | An analog for object_id in some Customer.io integrations. | |
relationship | Used to reference relationships to objects. Cannot be used as the name of an object attribute. | To reference relationships in liquid | |
_relationship | Used in relationship-triggered campaigns to reference audience members who did not trigger the campaign. Cannot be used as the name of a customer attribute. | To reference relationships in liquid | |
created_at | Unix timestamp when the object was first created. Used when listing objects in the UI, for example. | No | Unix timestamp |
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
You can store attributes as any JSON data type, including arrays, objects, and complex arrays of objects. You should store attributes in formats true to their type: you should store boolean values as booleans (e.g. true
instead of "true"
), and numbers as numbers, not strings (e.g. 42
instead of "42"
).
You’ll access attributes in segmentsA group of people who match a series of conditions. People enter and exit the segment automatically when they match or stop matching conditions., filters, liquidA syntax that supports variables, letting you personalize messages for your audience. For example, if you want to reference a person’s first name, you might use the variable {{customer.first_name}}
., and so on using JSON dot notation. For example, if you store your customer’s address as an object with a property called city
, you could access the city in liquid using {{ customer.address.city }}
.
If you store an attribute containing an array of address objects, you might access the city for the first address with {{ customer.address[0].city }}
. Remember, arrays are zero-indexed.
In segments, you can use array notation without an index to loop over the entire array. For example, if you wanted to find any address in an array of address objects matching a specific city, you could use customer.address[].city
. If you only wanted to use the first address object, you would keep the index, using customer.address[0].city
. See complex values in segments for more information.
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 https://track-eu.customer.io
SENT FIRST
curl -i https://track.customer.io/api/v1/customers/test-user-id \
-X PUT \
-u site-id:api-key \
-d _timestamp=1522081942 \
-d Attr1='attr1_val3_sent1st_timestamp=1522081942(newer)'
SENT SECOND
curl -i https://track.customer.io/api/v1/customers/test-user-id \
-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:
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:
- 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
- Using our CSV import feature to overwrite the attribute data with empty values.
- Using an Attribute Update in a campaign to remove the attribute.
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 win@customer.io with examples so we can investigate.
Mobile device attributes
Devices have their own attributesA key-value pair that you associate with a person or an object—like a person’s name, the date they were created in your workspace, or a company’s billing date etc. Use attributes to target people and personalize messages. Attributes are analogous to traits in Data Pipelines.. We collect last_status
automatically. We also set a last_used
attribute based on either the timestamp
in your request to add or update a device, or the time of the request itself. When you add or update a device using our SDKs, we’ll set the platform
automatically for you; otherwise, you must send the platform
with each request to our API.
If you use our SDKs, you’ll automatically collect additional device attributes by default. Whether or not you use our SDKs, you can also set custom attributes for each device—similar to attributes you set for people, but specific to each mobile device token.
When you go to a person’s Devices tab, you’ll see each device’s PLATFORM, DEVICE LAST USED and LAST RESULT attributes. Click a device to reveal additional information and attributes attached to it.
You can use device attributes anywhere you would otherwise use a person’s other attributes—True/False branches, Action Conditions, or segmentsA segment is a group of people in your audience that you want to target with campaigns, messages, etc. You can join groups of people manually, or by attribues and event data.. But you cannot use device attributes with Liquid today.
Collect custom device attributes
When you identify or update a device, you can pass an attributes
object containing additional attributes specific to a device. If you use our SDKs, we capture a number of predefined attributes automatically—unless you disable automatic attribute collection.
You can segment and filter audience members based on these attributes. However, device tokens can change—sometimes based on user behavior, like when a person uninstalls and reinstalls your app, and sometimes based on your messaging service (FCM or APNs). When you set attributes on a device, consider wether you need to retain an attribute past the life of the device token, and if an attribute is truly relevant to the device.
The following attributes are automatically collected by alpha versions of the SDK, set automatically by Customer.io, or available to our APIs. If you disable automatic attribute collection in the SDK, we’ll stop automatically collecting properties other than platform
, last_used
, and last_status
.
- id stringRequired The device token.
-
- _last_status stringThe delivery status of the last message sent to the device—sent, bounced, or suppressed. An empty string indicates that that the device hasn’t received a push yet.
Accepted values:
,
bounced
,sent
,suppressed
- app_version stringThe version of your app that a customer uses. You might target app versions to let people know when they need to update, or expose them to new features when they do.
- cio_sdk_version stringThe version of the Customer.io SDK in the app.
- device_locale stringThe four-letter IETF language code for the device. For example,
en-MX
(indicating an app in Spanish formatted for a user in Mexico) ores-ES
(indicating an app in Spanish formatted for a user in Spain). - device_model stringThe model of the device a person uses.
- device_os stringThe operating system, including the version, on the device.
- push_enabled stringIf
"true"
, the device is opted-in and can receive push notifications.Accepted values:
true
,false
- Custom Device Attributes* stringCustom properties that you want to associate with the device.
- last_used integer (unix timestamp)The
timestamp
when you last identified this device. If you don’t pass a timestamp when you add or update a device, we use the time of the request itself. Our SDKs identify a device when a person launches their app. - platform stringRequired The device/messaging platform.
Accepted values:
ios
,android