Track users
Use this endpoint to record custom events, purchases, and update user profile attributes.
Braze processes the data passed via API at face value and customers should only pass deltas (changing data) to minimize unnecessary data point consumption. To read more, refer to Data points.
To use this endpoint, you’ll need to generate an API key with the users.track
permission.
Rate limit
We apply a base speed limit of 50,000 requests per minute to this endpoint for all customers. Each /users/track
request can contain up to 75 event objects, 75 attribute objects, and 75 purchase objects. Each object (event, attribute, and purchase arrays) can update one user each. In total, this means a maximum of 225 users can be updated in a single call. In addition, a single user profile can be updated by multiple objects.
See our page on API rate limits for details, and reach out to your customer success manager if you need your limit increased.
Request body
1
2
Content-Type: application/json
Authorization: Bearer YOUR-REST-API-KEY
1
2
3
4
5
{
"attributes" : (optional, array of attributes object),
"events" : (optional, array of event object),
"purchases" : (optional, array of purchase object),
}
Customers using the API for server-to-server calls may need to allowlist rest.iad-01.braze.com
if they’re behind a firewall.
Request parameters
For each of the request components listed in the following table, one of external_id
, user_alias
, or braze_id
is required.
Parameter | Required | Data Type | Description |
---|---|---|---|
attributes |
Optional | Array of attributes objects | See user attributes object |
events |
Optional | Array of event objects | See events object |
purchases |
Optional | Array of purchase objects | See purchases object |
Example request body for event tracking
1
2
3
4
5
6
7
8
9
{
"events": [
{
"external_id": "string",
"name": "string",
"time": "string"
}
]
}
Example request for updating a user profile by email address
Updating a user profile by email address with this endpoint is currently in early access. Contact your Braze account manager if you’re interested in participating in the early access.
Using the /users/track
endpoint, you can update a user profile by email address. You’ll need to generate an API key with users.track
permissions to use this endpoint.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
curl --location --request POST 'https://rest.iad-01.braze.com/users/track' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR-API-KEY-HERE' \
--data-raw '{
"attributes": [
{
"email": "[email protected]",
"string_attribute": "fruit",
"boolean_attribute_1": true,
"integer_attribute": 25,
"array_attribute": [
"banana",
"apple"
]
}
],
"events": [
{
"email": "[email protected]",
"app_id": "your_app_identifier",
"name": "rented_movie",
"time": "2022-12-06T19:20:45+01:00",
"properties": {
"release": {
"studio": "FilmStudio",
"year": "2022"
},
"cast": [
{
"name": "Actor1"
},
{
"name": "Actor2"
}
]
}
},
{
"user_alias": {
"alias_name": "device123",
"alias_label": "my_device_identifier"
},
"app_id": "your_app_identifier",
"name": "rented_movie",
"time": "2013-07-16T19:20:50+01:00"
}
],
"purchases": [
{
"email": "[email protected]",
"app_id": "your_app_identifier",
"product_id": "product_name",
"currency": "USD",
"price": 12.12,
"quantity": 6,
"time": "2017-05-12T18:47:12Z",
"properties": {
"color": "red",
"monogram": "ABC",
"checkout_duration": 180,
"size": "Large",
"brand": "Backpack Locker"
}
}
]
}`
Example request for updating a user profile by phone number
Updating a user profile by phone number with this endpoint is currently in early access. Contact your Braze account manager if you’re interested in participating in the early access.
Using the /users/track
endpoint, you can update a user profile by phone number. You’ll need to generate an API key with users.track
permissions to use this endpoint. This endpoint only works if you include a valid phone number.
If you include a request with both email and phone, we will use the email as the identifer.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
curl --location --request POST 'https://rest.iad-01.braze.com/users/track' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR-API-KEY-HERE' \
--data-raw '{
"attributes": [
{
"phone": "+15043277269",
"string_attribute": "fruit",
"boolean_attribute_1": true,
"integer_attribute": 25,
"array_attribute": [
"banana",
"apple"
]
}
],
}`
Frequently asked questions
What happens when multiple profiles with the same email address are found?
If the external_id
exists, the most recently updated profile with an external ID will be prioritized for updates. If the external_id
doesn’t exist, the most recently updated profile will be prioritized for updates.
What happens if no profile with the email address currently exists?
A new profile will be created and an email-only user will be created. An alias will not be created. The email field will be set to [email protected], as noted in the example request for updating a user profile by email address.
Example request
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
curl --location --request POST 'https://rest.iad-01.braze.com/users/track' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR-API-KEY-HERE' \
--data-raw '{
"attributes": [
{
"external_id": "user_identifier",
"string_attribute": "fruit",
"boolean_attribute_1": true,
"integer_attribute": 25,
"array_attribute": [
"banana",
"apple"
]
}
],
"events": [
{
"external_id": "user_identifier",
"app_id": "your_app_identifier",
"name": "rented_movie",
"time": "2022-12-06T19:20:45+01:00",
"properties": {
"release": {
"studio": "FilmStudio",
"year": "2022"
},
"cast": [
{
"name": "Actor1"
},
{
"name": "Actor2"
}
]
}
},
{
"user_alias": {
"alias_name": "device123",
"alias_label": "my_device_identifier"
},
"app_id": "your_app_identifier",
"name": "rented_movie",
"time": "2013-07-16T19:20:50+01:00"
}
],
"purchases": [
{
"external_id": "user_identifier",
"app_id": "your_app_identifier",
"product_id": "product_name",
"currency": "USD",
"price": 12.12,
"quantity": 6,
"time": "2017-05-12T18:47:12Z",
"properties": {
"color": "red",
"monogram": "ABC",
"checkout_duration": 180,
"size": "Large",
"brand": "Backpack Locker"
}
}
]
}`
Example request to set subscription groups
This example shows how you can create a user and set their subscription group within the user attributes object.
Updating the subscription status with this endpoint will both update the user specified by their external_id
(such as User1) and update the subscription status of any users with the same email as that user (User1).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
curl --location --request POST 'https://rest.iad-01.braze.com/users/track' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR-API-KEY-HERE' \
--data-raw '{
"attributes": [
{
"external_id": "user_identifier",
"email": "[email protected]",
"email_subscribe": "subscribed",
"subscription_groups" : [{
"subscription_group_id": "subscription_group_identifier_1",
"subscription_state": "unsubscribed"
},
{
"subscription_group_id": "subscription_group_identifier_2",
"subscription_state": "subscribed"
},
{
"subscription_group_id": "subscription_group_identifier_3",
"subscription_state": "subscribed"
}
]
}
]
}'
Responses
When using any of the aforementioned API requests, you should receive one of the following three general responses:
Successful message
Successful messages will be met with the following response:
1
2
3
4
5
6
{
"message" : "success",
"attributes_processed" : (optional, integer), if attributes are included in the request, this will return an integer of the number of external_ids with attributes that were queued to be processed,
"events_processed" : (optional, integer), if events are included in the request, this will return an integer of the number of events that were queued to be processed,
"purchases_processed" : (optional, integer), if purchases are included in the request, this will return an integer of the number of purchases that were queued to be processed,
}
Successful message with non-fatal errors
If your message is successful but has non-fatal errors, such as one invalid event object out of a long list of events, then you will receive the following response:
1
2
3
4
5
6
7
8
{
"message" : "success",
"errors" : [
{
<minor error message>
}
]
}
For success messages, any data that was not affected by an error in the errors
array will still be processed.
Message with fatal errors
If your message has a fatal error, you will receive the following response:
1
2
3
4
5
6
7
8
{
"message" : <fatal error message>,
"errors" : [
{
<fatal error message>
}
]
}
Fatal error response codes
For status codes and associated error messages that will be returned if your request encounters a fatal error, reference Fatal errors & responses.
If you receive the error “provided external_id is blacklisted and disallowed”, your request may have included a “dummy user”. For more information, refer to Spam blocking.
Creating an alias-only user profile
You can use the /users/track
endpoint to create a new alias-only user by setting the _update_existing_only
key with a value of false
in the body of the request. If this value is omitted, the alias-only user profile will not be created. Using an alias-only user guarantees that one profile with that alias will exist. This is especially helpful when building a new integration as it prevents the creation of duplicate user profiles.
Example request to create an alias-only user
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
curl --location --request POST 'https://rest.iad-01.braze.com/users/track' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR-API-KEY-HERE' \
--data-raw '{
{
"attributes": [
{
"_update_existing_only": false,
"user_alias": {
"alias_name": "example_name",
"alias_label": "example_label"
},
"email": "[email protected]"
}
],
}
Importing legacy user data
You may submit data through the Braze API for a user who has not yet used your mobile app in order to generate a user profile. If the user subsequently uses the application all information following their identification via the SDK will be merged with the existing user profile you created via the API call. Any user behavior that is recorded anonymously by the SDK prior to identification will be lost upon merging with the existing API-generated user profile.
The segmentation tool will include these users regardless of whether they have engaged with the app. If you want to exclude users uploaded via the User API who have not yet engaged with the app, simply add the filter: Session Count > 0
.
Making bulk updates
If you have a use case where you need to make batch updates to the users/track
endpoint, we recommend adding the bulk update header so that Braze can properly identify, observe, and route your request.
Refer to the following sample request with the X-Braze-Bulk
header:
1
2
3
4
5
curl --location --request POST 'https://rest.iad-01.braze.com/users/track' \
--header 'Content-Type: application/json' \
--header 'X-Braze-Bulk: true' \
--header 'Authorization: Bearer YOUR-API-KEY-HERE' \
--data-raw '{ "attributes": [ ], "events": [ ], "purchases": [ ] }'
When the X-Braze-Bulk
header is present with any value, Braze will consider the request a bulk request. Set the value to true
. Currently, setting the value to false
does not disable the header—it will still be treated as if it were true.
Use cases
Consider the following use cases where you may use the bulk update header:
- A daily job where multiple users’ custom attributes are updated via the
/users/track
endpoint. - An ad-hoc user data backfill script which updates user information via the
/users/track
endpoint.