POST - Set or update

The Custom Data API allows you to send custom data on specific custom user IDs (iOS/Android/Web) and improve your campaign targetings.

This is helpful when users can perform actions outside of the app (e.g. purchase, subscription, updated profile, etc). You can use the API to post, update data or remove data.

Request structure

The users data endpoint allows you to set user data either for one user, or for multiple users.

Important Note: Any data changed by calling this API will not be available in real time: Processing time can be required. See this section for more info.


The Custom Data API exposes two POST endpoints:

  • for a single update
  • for bulk updates

NOTE: YOUR_USER_ID is the Custom ID matching the ones you set using the SDKs.

Bulk updates allow you to update custom data for multiple users (up to 10,000) with one API call.

Here are two valid cURL examples.

Single update:

curl -H "Content-Type: application/json" -H "X-Authorization: BATCH_REST_API_KEY" -X POST -d "@payload.json" ""

Bulk update:

curl -H "Content-Type: application/json" -H "X-Authorization: BATCH_REST_API_KEY" -X POST -d "@payload.json" ""

The BATCH_API_KEY value is either your Live, Dev or SDK Batch API key from the settings page of your app within the dashboard (Settings → General): API Keys

Please note Batch manages each platform separately, so you will have to call the API twice with a different Dev/Live API key if you want to target iOS and Android.


In order to authenticate with the API, you need to provide your company REST API Key as the value of the X-Authorization header. You can find it in ⚙ Settings → General.

Insufficient privileges issue: You may see that error in the REST API key field. This happens because the REST API key is only visible to managers. Make sure the managers of the account share that key with you or ask them to grant you access through the team manager.

Post data

For a single update, the body of the request must contain a valid JSON payload describing the update operations to execute for the user's custom data.

Here is a how a complete JSON payload looks like:

  "overwrite": false,
  "values": {
    "u.nickname": "The Rock",
    "u.force": 42,
    "ut.hobbies": ["Lifting", "Wrestling", "Acting"],
    "u.is_subscribed": null,
    "date(u.last_subscription)": "2016-01-10T10:00:00.000",
    "date(u.last_purchase)": 1472656161,
    "ut.locations": { "$add": ["Paris"], "$remove": ["Berlin"] }

Let's see the parameters in detail.

overwriteBoolean - Optional
Instead of merging the data we already have for a user, the existing data will be *deleted* and replaced by the incoming data. Defaults to false
valuesObject - Required
An object containing all attributes and tags with their respective update operations

Using the tag operations $add and $remove when overwrite is set to true might not have the behaviour you would expect: $add will work but will append tags on an empty tag collection, clearing any previously set tag. $remove is simply ignored.

The values object

The values object details what operations to do on a set of attributes or tags. It has the following form:

  "<scope>.<attribute name>": <attribute value>,
  "<scope>.<attribute name>": <attribute value>,
  "<scope>.<attribute name>": <attribute value>,
  "<scope>.<attribute name>": <attribute value>,
  "<scope>.<tag name>": <tag update operation>

Only one operation per attribute or tag is allowed in one call to the API.

The scope

The scope determines what the key refers to: an attribute or tags:

  • u is for attributes
  • ut is for tags

Important note: Attributes/tags names are string. They should be made of letters, numbers or underscores ([a-z0-9_]). They can't be longer than 30 characters and cannot contain uppercase characters.

The attribute value

The value describes what you want to do on an attribute; either set or remove a value. The rules are as follow:

  • When the value is null, the attribute is removed.
  • Otherwise the attribute's value is inserted or updated.

The following types are supported in a value:

  • string. E.g: {"u.nickname": "Johnny"}
  • integer. E.g: {"u.age": 23}
  • boolean. E.g: {"u.is_subscribed": true}
  • float. E.g: {"u.level_progress": 45.09}

Additional types


We support dates, unfortunately JSON does not, thus we need extra information to know an attribute is actually a date. We do this via wrapping the key name in the date() function.

  "date(u.promo_starts)": 1451642400,
  "date(u.promo_ends)": "2021-01-01T04:00:00.000"

If you're using date() on a string, be sure to use the format YYYY-MM-ddTHH:mm:ss. Be aware that we will interpret the date as UTC in both cases.


URL type is also supported. You will need to wrap the key name in the url() function.

  "url(u.product_image)": "https://batchstore/product/4729/image.png",
  "url(u.product_deeplink)": "myapp://path/to/content"

You need to provide a valid URL, in the limit of 2048 characters:

  • A scheme is compulsory (myapp://, https://...)
  • :// is compulsory after the scheme

If the URL provided isn't valid, the API call will fail.

The tag update operation

The value describes what you want to do on a tag. The rules are as follow:

  • When the value is null, the tag is removed.
  • When the value is in array, the tag's content is replaced.
  • When the value is an object, that object must describe the update to do. See below for the description of that object.

Here is the description of a tag update object.

$addArray - Optional
The values to add to the tag
E.g.{"$add":["Paris","Berlin","San Francisco"]}
$removeArray - Optional
The values to remove from the tag
E.g.{"$remove":["Tokyo","London","New York"]}

Here is a complete example combining all possible operations:

  "ut.hobbies": ["Cooking", "Chess"],
  "ut.previous_locations": null,
  "ut.locations": { "$add": ["Paris", "London"], "$remove": ["Berlin"] }

Bulk post data

Bulk updates work basically the same way as a single update, except now you need to provide an array of objects of the following type:

idString - Required
The user id
updateObject - Required
The update operation as described for the single update above

Here is an example of a valid JSON payload:

    "id": "Vincent",
    "update": {
      "values": {
        "u.nickname": "Vincent",
        "u.age": 55
    "id": "Johnny",
    "update": {
      "overwrite": true,
      "values": {
        "u.nickname": "BeGood",
        "u.age": 30



If the POST to the API endpoint is successful you will receive an HTTP 200 confirmation and a unique token reprensenting the transaction.

{ "token": "fd576e9f-8b07-4844-91f9-ecfc2137c6f8" }

Please keep this token: it will be useful for upcoming features, and it will also help in getting faster support.


If the POST data does not meet the API requirements you will receive an actionable error message. Contact us at if you need further support.

  • AUTHENTICATION_INVALID (Http status code: 401, Error code: 10)
  • API_MISUSE (Http status code: 403, Error code: 12)
  • ROUTE_NOT_FOUND (Http status code: 404, Error code: 20)
  • MISSING_PARAMETER (Http status code: 400, Error code: 30)
  • MALFORMED_PARAMETER (Http status code: 400, Error code: 31)
  • MALFORMED_JSON_BODY (Http status code: 400, Error code: 32)
  • SERVER_ERROR (Http status code: 500, Error code: 1)
  • MAINTENANCE_ERROR (Http status code: 503, Error code: 2)

Processing time

Data you send using this API is processed almost instantly.

However, your userbase's global analytics may not be. This only affects the dashboard in two places: the Userbase page, and the visual query editor.

Since the dashboard's visual query editor depends on the same data that powers Userbase, you might see outdated or missing data in the autocompleted fields.
This issue will fix itself in a matter of hours: the userbase data is refreshed at worse once per 24H, but may be refreshed more often. Calling the API again will not have any effect whatsoever on the scheduled refresh.

Rest assured: once you actually run the campaign, the latest data will be used. Same goes for API-only usage, and the debug page.

You can see when the userbase data was last refreshed by hovering any User level section of your app's Userbase dashboard page.