Understanding user identification is fundamental to working with Iterable's API effectively. The steps for creating and identifying users vary depending on your project type and the way you identify users. This article describes how to identify and create users with Iterable's APIs for email-based, userID-based, and hybrid projects.
For more information about the relationship between project types and user identification, read Project Types and Unique Identifiers.
NOTE
This article covers most aspects of user identification and creation,
however, it doesn't cover how to manage unknown users (for example, users who
don't have an email address).
Iterable provides two different ways to manage unknown users:
# In this article
# Understanding user identification in API requests
Many of Iterable's API endpoints require you to specify a particular user (for example, to modify their user profile or fetch data about them). The way you identify users depends on your project type.
# Project types and user identification
To identify a user, provide a userId or an email in your API request body.
This field typically goes at the top level of your request, outside of
dataFields.
Your project type determines which fields you can use to identify users:
UserID-based projects identify users by
userId, and Iterable enforces the uniqueness of this field.Hybrid projects identify users by
emailand/oruserId, and Iterable enforces the uniqueness of both. However, you don't have to provide both fields to every user.Email-based projects identify users by
emailoruserId. However, Iterable only enforcesemailuniqueness, notuserId. (Email-based projects have limited availability. To learn more, read Project Type Availability.)
# Field validation and requirements
When you send an API request that includes an email or userId, Iterable
validates these fields regardless of your project type.
email: Iterable checks that the field is a valid email address format and converts the value to lowercase. Iterable does not check deliverability. To learn more, read Email Validation in Iterable.-
userId: Iterable rejects requests withuserIdvalues that don't meet certain requirements. To learn more, see UserID Validation in Iterable.Additionally, when identifying a user, the
userIdfield must be non-empty:Blank, null, or empty values for
userIdare not accepted in requests to identify users.API requests with a
userIdlookup field that is blank, null, or empty are rejected. Instead, if a user doesn't have auserIdvalue, such as in a hybrid project, use theemailfield to identify the user and don't include a blankuserIdfield in the API request.For email-based and hybrid projects, API requests that include
userIdwith a null value indataFieldswith intention to clear the data from a user profile are accepted.
# Precedence rules when both fields are provided
If you include both email and userId at the top level of an API request,
precedence rules apply based on your project type:
-
Email-based projects:
emailtakes precedence -
UserID-based projects: Only
userIdis valid;emailis treated as a regular data field -
Hybrid projects:
userIdtakes precedence
# Basic API request structure
Here's the standard structure for API requests that identify users:
{ "userId": "user1234567", // User identifier (outside dataFields) "dataFields": { // User profile updates go here "favoriteColor": "red" } }
Important guidelines:
Place user identifiers (
userIdoremail) at the top level of your request, outside ofdataFields.Place profile updates you'd like to make for that user inside the
dataFieldsobject.Do not include empty
userIdvalues to look up users in your API request. Iterable rejects blankuserIdwhen provided to locate a record. However, API requests for email-based and hybrid projects that includeuserIdwith a null value nested indataFields, with intention to clear the data from a user profile, are still accepted.Some requests require you to place
userIdoremailinside another object, rather than at the top level of your API request. For example, when callingPOST /api/commerce/updateCart, you need to placeuserIdoremailinside auserobject.Additionally, some requests use slightly different field names. For example,
POST /api/email/targetrequiresrecipientEmailandrecipientUserId, rather thanemailanduserId. For endpoint-specific details, consult our API Endpoints and Sample Payloads.
# Email-based projects
NOTE
Email-based projects have limited availability. To learn more, read Project Type Availability.
In email-based projects, you can pass email and/or userId in requests to
identify users. The behavior depends on which fields you provide:
If both fields are present,
emailis prioritized to identify the user, and theuserIdfield is updated/overwritten for most requests that usePUTorPOSTmethods.-
If
emailis passed and there is no user with that email address, Iterable creates a new user when using the following endpoints:POST /api/email/targetPOST /api/inApp/targetPOST /api/users/updatePOST /api/users/bulkUpdatePOST /api/users/updateSubscriptionsPOST /api/users/bulkUpdateSubscriptionsPOST /api/users/registerDeviceTokenPOST /api/users/registerBrowserTokenPOST /api/lists/subscribePOST /api/commerce/trackPurchasePOST /api/commerce/updateCartPATCH /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}/user/{userEmail}DELETE /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}/user/{userEmail}PATCH /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}/byUserId/{userId}DELETE /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}/byUserId/{userId}PUT /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}?action=subscribe
If only
userIdis passed (and notemail), and there is no matching user, Iterable returns an error. To avoid this and create a user without an email, include the parameterpreferUserIdwith a value oftrue. This creates the user with an auto-generated placeholder email address using the@placeholder.emaildomain. For more information about placeholder email addresses, read Handling Anonymous Users.If only
userIdis passed in a request to an email-based project, and multiple users share the sameuserIdbut have differentemailvalues, Iterable updates only one of the users. This occurs becauseuserIdis not enforced as unique in email-based projects. The API selects the first user returned in the query, but this selection is not consistent and may vary between requests.Tracking events for an unknown user does not create a new user.
# Email-based project behavior across Iterable
Lists must include an
emailcolumn.Hosted Signup Forms are available for static lists.
When previewing a template, use
emailto populate sample data.Journey triggers can be tested with
emailonly.Static list subscriptions are stored in the
emailListIdsfield.
NOTE
This is the only type of project where Iterable creates a iterableEndUserId
browser cookie (which will be deprecated at a future date). This may impact
your implementation of a subscription preference center
and when tracking conversions, purchases, and revenue.
# Identifying users in email-based projects
In email-based projects, email takes precedence when both email and
userId are provided. For example, this request to POST /api/users/update
looks up or creates a user with email address user@example.com, then sets
their favoriteColor to red:
{ "email": "user@example.com", "userId": "user1234567", "dataFields": { "favoriteColor": "red" } }
# Creating new users in email-based projects
To create a new user and assign them a unique email address in an email-based project, make a request to one of the various endpoints that can create new users in one of these ways:
- Update user data (individually or in bulk)
- Target users with email and in-app campaigns
- Update subscription information
- Update the shopping cart and track purchases
- Register device and browser tokens
For example, you can call POST /api/users/update with
a request body such as:
{ "email": "user@example.com", "dataFields": { "favoriteColor": "red" } }
For this request:
If your project doesn't yet have a user with an
emailaddress ofuser@example.com, Iterables creates one.Then, whether the user is new or already exists, Iterable sets their
favoriteColortored.
# Creating new users when email is unknown
To create a new user for someone with an unknown email address (in an
email-based project), provide a userId instead of an email. When you do
this, Iterable creates a new user with a placeholder email address using the
@placeholder.email domain.
To learn more about how to do this, read Handling Anonymous Users.
Once a placeholder email is assigned to a user, you can identify this user in
subsequent API calls by their userId, or by the placeholder email given to
them by Iterable.
# Assigning a userId to an existing user
In an email-based project, you can assign a userId to an existing user who is
already identified by email by making an API call to POST /api/users/update.
To learn more about how to do this, read Updating a User's Email Address or User ID.
# UserID-based projects
TIP
UserID-based is often the most sensible type of project to choose, because it:
- Is simple to use. You always identify users by
userId. - Allows you to match Iterable
userIdvalues with user identifiers you use in other systems. - Allows multiple users to share the same email address, which can sometimes be useful.
UserID-based projects identify users exclusively by userId. In these
projects, email is not a user identifier—it's treated like any other profile
field (such as favoriteColor). You can assign email addresses to users, but
you can't use email to look up or modify users in Iterable's web UI or when
making API calls.
Key considerations for userID-based projects:
The
userIdfield must always be present and unique for any endpoint that uses a unique identifier, including GDPR forget and unforget endpointsMultiple users can have the same
emailaddress since email uniqueness is not enforced-
If
userIdis passed and there is no matching user, Iterable creates a new user when using the following endpoints:POST /api/users/updateEmailPOST /api/events/trackPOST /api/events/trackBulkPOST /api/events/trackWebPushClickPOST /api/events/trackPushOpenPOST /api/events/trackInAppOpenPOST /api/events/trackInAppClickPOST /api/events/trackInAppDeliveryPOST /api/events/trackInAppClosePOST /api/workflows/triggerWorkflowPOST /api/email/targetPOST /api/inApp/targetPOST /api/users/updatePOST /api/users/bulkUpdatePOST /api/users/updateSubscriptionsPOST /api/users/bulkUpdateSubscriptionsPOST /api/users/registerDeviceTokenPOST /api/users/registerBrowserTokenPOST /api/lists/subscribePOST /api/commerce/trackPurchasePOST /api/commerce/updateCartPATCH /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}/user/{userEmail}DELETE /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}/user/{userEmail}PATCH /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}/byUserId/{userId}DELETE /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}/byUserId/{userId}PUT /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}?action=subscribe
When an API request includes the parameter
preferUserId, it's ignored.If you try to use
emailto identify a user when making an API call, the request returns an error. You can only identify users withuserId.You aren't required to provide an
emailfor every user you upload to Iterable. Placeholder email addresses aren't necessary.Iterable doesn't enforce
emailuniqueness. In other words, many users can have the same email address.Tracking events for an unknown user creates a new user.
# UserID-based project behavior across Iterable
When creating a new list, specify a
userIdcolumn, instead of anemailcolumn.Hosted Signup Forms are unavailable at this time.
When previewing a template, use
emailoruserIDto populate sample data.Journey triggers can be tested with
emailoruserID.Iterable doesn't set a
iterableEndUserIdbrowser cookie.-
To identify users when you create a custom subscription center, pass
userIdas a URL parameter using the following Handlebars in the hosted unsubscribe URL project setting:{{userId}} -
To identify users when tracking conversions, purchases, and revenue, add a URL parameter with a Key of userId and Value of:
{{userId}} When a user unsubscribes from a link in an email (
emailUnSubscribe,hostedUnsubscribeClick, oremailComplaintevent), Iterable attributes the unsubscribe to the user's uniqueuserId, not the email address that received the message. This is important when you have users who share an email address.Static list subscriptions are stored in the
userListIdsfield.-
When sending a proof to an unknown email address (including when sending a proof "to myself" for the first time), Iterable creates a new user and automatically assigns a
userIDwith the valueitbl_generated_(where the email address is part of theuserId).TIP
To look up users by email address in a userID-based project, use the segmentation tool and segment by the contact property
email.
# Identifying users in userID-based projects
In userID-based projects, userId is the only valid user identifier, and
uniqueness is enforced.
For this request to POST /api/users/update,
Iterable looks up or creates a user with userId of user1234567, then sets
their favoriteColor to red:
{ "email": "user@example.com", "userId": "user1234567", "dataFields": { "favoriteColor": "red" } }
Iterable also sets the user's email to user@example.com, as this is a field
included in the request body. However, since email is not a user identifier
in userID-based projects, the API does not verify its uniqueness. Multiple
users could have the same email address with different userId values.
# Creating new users in userID-based projects
In userID-based projects, when you make an API request that includes a userId
not yet used by your project, some endpoints create new users:
- Update user data (individually or in bulk)
- Target users with email and in-app campaigns
- Update subscription information
- Update the shopping cart and track purchases
- Register device and browser tokens
- Track events (individually or in bulk)
- Trigger workflows
For example, call POST /api/users/update, with a
request body such as:
{ "userId": "user1234567", "dataFields": { "favoriteColor": "red" } }
For this request:
- If there's no user with
userIdset touser1234567, Iterable creates one. - Whether the user is new or already exists, Iterable sets their
favoriteColortored.
# Assigning email in userID-based projects
You may assign an email to each user in a userID-based project, but it's
not a required field and isn't used to identify unique users.
NOTE
Since email is not a required field in userID-based projects, Iterable does
not automatically assign @placeholder.email addresses like it does in
email-based projects.
To do this, call POST /api/users/update, with a
request body such as:
{ "userId": "user1234567", "dataFields": { "email": "user@example.com" } }
For this request:
If there's no user with
userIdset touser1234567, Iterable creates one.-
Whether the user is new or already exists, Iterable sets their
emailtouser@example.com.NOTE
In userID-based projects, Iterable does not enforce
emailuniqueness. This allows you to give the sameemailto many users in the same project, which can sometimes be useful.
# Hybrid projects
Hybrid projects use both email and userId as unique identifiers. Key
behaviors include:
Use either
userIdoremail(but not both) to identify users in API requests.If you provide both fields,
userIdtakes precedence.Both
emailanduserIdmust be unique, and this policy is enforced.-
If
userIdand/oremailare passed and there is no matching user, Iterable creates a new one when using the following endpoints:POST /api/users/updateEmailPOST /api/events/trackPOST /api/events/trackBulkPOST /api/events/trackWebPushClickPOST /api/events/trackPushOpenPOST /api/events/trackInAppOpenPOST /api/events/trackInAppClickPOST /api/events/trackInAppDeliveryPOST /api/events/trackInAppClosePOST /api/workflows/triggerWorkflowPOST /api/email/targetPOST /api/inApp/targetPOST /api/users/updatePOST /api/users/bulkUpdatePOST /api/users/updateSubscriptionsPOST /api/users/bulkUpdateSubscriptionsPOST /api/users/registerDeviceTokenPOST /api/users/registerBrowserTokenPOST /api/lists/subscribePOST /api/commerce/trackPurchasePOST /api/commerce/updateCartPATCH /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}/user/{userEmail}DELETE /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}/user/{userEmail}PATCH /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}/byUserId/{userId}DELETE /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}/byUserId/{userId}PUT /api/subscriptions/{subscriptionGroup}/{subscriptionGroupId}?action=subscribe
If you are adding a user with an invalid
emailvalue, it is rejected even if it has auserIdincluded in the request.When an API request includes the parameter
preferUserId, it's ignored.You aren't required to provide an
emailfor every user you upload to Iterable—placeholder email addresses aren't necessary.You aren't required to provide a
userIdfor every user, however Iterable doesn't create one when the value is missing.To process a GDPR request to forget a user, you can use either
emailoruserIdwith thePOST /api/users/forgetendpoint.
# Hybrid project behavior across Iterable
When creating a new list, specify either a
emailoruserIdcolumn, at minimum, or upload a list with both columns.Hosted Signup Forms are available for static lists.
When previewing a template, use
emailoruserIDto populate sample data.Journey triggers can be tested with
emailoruserID.Iterable doesn't set a
iterableEndUserIdbrowser cookie.
To identify users when you create a custom subscription center
, pass userIdas a URL parameter using Handlebars ({{userId}}) in the hosted unsubscribeURL project setting. To identify users when tracking conversions, purchases, and revenue
, add a URL parameter with a Key of userIdand Value of{{userId}}.
Static list subscriptions are stored in the
userListIdsfield.When sending a proof to an unknown email address (including when sending a proof "to myself" for the first time), Iterable creates a new user.
# Identifying users in hybrid projects
In hybrid projects, both userId and email are valid unique identifiers, but
userId always takes precedence when both are provided.
For this request to POST /api/users/update,
Iterable finds or creates a user with userId of user1234567 and sets their
favoriteColor to red:
{ "email": "user@example.com", "userId": "user1234567", "dataFields": { "favoriteColor": "red" } }
Iterable also attempts to set the user's email to user@example.com (even
though it is provided outside of dataFields). Since hybrid projects enforce
email uniqueness, Iterable first checks if that email is already in use:
-
If no profile exists with that
email: The request succeeds, creating/updating the user with both identifiers. -
If a profile exists with that
email: The request fails with HTTP status code409—you can't reuse an email address that belongs to another user.
# Creating new users in hybrid projects
In hybrid projects, when you make an API request that references a non-existent
userId or email, some endpoints create new user profiles:
- Update user data (individually or in bulk)
- Target users with email and in-app campaigns
- Update subscription information
- Update the shopping cart and track purchases
- Register device and browser tokens
- Track events (individually or in bulk)
- Trigger workflows
For example, you can call POST /api/users/update
with a request body such as:
{ "email": "user@example.com", "dataFields": { "favoriteColor": "red" } }
For this request:
- If there's no user with an
emailofuser@example.com, Iterable creates one. - Whether the user is new or already exists, Iterable sets their
favoriteColortored.
Another example request:
{ "userId": "user1234567", "dataFields": { "favoriteColor": "red" } }
For this request:
- If there's no user with a
userIdofuser1234567, Iterable creates one. - Whether the user is new or already exists, Iterable sets their
favoriteColortored.
NOTE
In userID-based projects, Iterable's API ignores the preferUserId parameter
used in email-based projects for some endpoints.
# Want to learn more?
For more information about some of the topics in this article, check out these resources. Iterable Academy is open to everyone — you don't need to be an Iterable customer!
Iterable Academy
Support docs