Carillon docs

Tags

Add text, number, boolean and date attributes to devices and users, then filter audiences by type.

Tags describe a device or a user. Use them to build audiences. Notification tags are different: they categorize campaigns for message history and statistics.

Choose a scope and a type

Device tags belong to one installation. Set them through a mobile SDK or the device API. User tags belong to an external_id, within one app and live/test mode. Set them from your backend; all devices identified with that external ID use the same profile. A profile can exist before a device registers. See shared user tags.

Each scope has four independent maps:

MapValueExample
tagsText"plan": "premium"
number_tagsInteger or decimal number"total_spent": 49.95
boolean_tagsJSON boolean"has_subscription": false
date_tagsISO 8601 timestamp with a timezone"expires_at": "2026-10-01T12:00:00.000Z"

The same key may exist in several maps. tags.expires_at and date_tags.expires_at are independent: writing or removing one never changes the other. There is no type inference from strings. "12" is text, not a number; "false" is text, not a boolean.

Number tags accept integers and decimals, including negative values. NaN and infinities are rejected.

Date tags represent instants. The API validates them and stores canonical UTC timestamps with milliseconds. A date without a time or timezone is rejected. Birthdays and recurring calendar anniversaries are not supported as date-only types.

Set device tags with an SDK

These methods require SDK 0.4.0 or later. These methods queue changes and synchronize them with device registration. Pending changes survive restarts and network retries. Acknowledged tags are not replayed during unrelated metadata updates.

React Native

Carillon.setTag('plan', 'premium');
Carillon.setTagNumber('total_spent', 49.95);
Carillon.setTagBoolean('has_subscription', false);
Carillon.setTagDate('expires_at', new Date('2026-10-01T12:00:00Z'));

setTagDate requires a valid JavaScript Date; it does not accept a string or timestamp number. setTagNumber rejects NaN and infinities.

Swift

Carillon.setTag("plan", "premium")
Carillon.setTagNumber("total_spent", 49.95)
Carillon.setTagBoolean("has_subscription", false)
Carillon.setTagDate("expires_at", Date(timeIntervalSince1970: 1_790_856_000))

The date method takes Foundation Date. Numeric values must be finite.

Kotlin

Carillon.setTag("plan", "premium")
Carillon.setTagNumber("total_spent", 49.95)
Carillon.setTagBoolean("has_subscription", false)
Carillon.setTagDate("expires_at", java.util.Date(1_790_856_000_000L))

The date method takes java.util.Date. Numeric values must be finite.

All three SDKs provide removeTag, removeTagNumber, removeTagBoolean and removeTagDate, each taking the key. setTags merges a map of strings; null values (nil in Swift) remove text tags.

After synchronization, open Devices in the dashboard and select the device to inspect its Device tags and, when an external ID is linked, User tags. You can also read device tags through GET /v1/devices/{id}.

Write tags from your backend

Use a secret key with devices:write for device tags, or users:write for user tags. Mobile keys can only set device tags through their registration calls; they cannot write user profiles.

curl -X PATCH https://api.carillon.dev/v1/devices/DEVICE_ID \
  -H "Authorization: Bearer $CARILLON_SECRET_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "tags": { "plan": "premium" },
    "number_tags": { "purchase_count": 12 },
    "boolean_tags": { "has_subscription": false },
    "date_tags": { "expires_at": "2026-10-01T12:00:00Z" }
  }'

For a user, send the same body to PATCH /v1/users/usr_123/tags. It creates the profile if necessary. Both endpoints return 200 and the resulting maps. POST /v1/devices accepts the same optional maps when registering a device.

Only supplied keys change. Omitted maps and keys remain unchanged. A null entry removes one key from its map:

{ "date_tags": { "expires_at": null } }

A typed map set to null clears that entire type: { "number_tags": null }. Each map is limited to 50 keys and 4096 UTF-8 JSON bytes after merging. Keys contain 1–64 characters; text values contain at most 256 characters. Invalid types, timestamps or limits return 400. The whole request is atomic: if one map is invalid, no map is updated.

Backend tag patches do not refresh device activity or registration metadata. Deleting a user profile removes all its tag maps without deleting or detaching its devices.

Filter an audience

In the dashboard, choose Device tag or User tag, then choose a tag. The selector shows each key with its type in parentheses; selecting it sets the available comparisons automatically. Suggestions come from reachable live devices and their associated user profiles. You may also enter a key before any device has reported it.

TypeOperators
TextEquals, one of, none of
NumberEquals, greater than, at least, less than, at most, between
BooleanTrue or false
DateBefore, after, between, within the last/next N days, more than N days ago
Every typeIs set, is not set

A missing boolean is not false. A missing number is not zero. Value comparisons exclude missing typed tags; use exists: false to target their absence. Same-name values in other maps do not count.

Create or preview audiences using these filter fields:

ScopeTextNumberBooleanDate
Devicetagnumber_tagboolean_tagdate_tag
Useruser_taguser_number_taguser_boolean_taguser_date_tag
{
  "name": "Renewing subscribers",
  "definition": {
    "filters": [
      { "field": "user_boolean_tag", "key": "has_subscription", "value": true },
      { "field": "user_number_tag", "key": "purchase_count", "gte": 3 },
      { "field": "user_date_tag", "key": "expires_at", "within_next_days": 7 }
    ]
  }
}

Send this to POST /v1/apps/APP_ID/audiences using a management token. Preview its definition at POST /v1/apps/APP_ID/audiences/preview first. All filters must match.

Number filters accept exactly one of value, gt, gte, lt, lte, between: [start, end], or exists. Boolean filters accept value or exists. Date filters accept before, after, between: [start, end], within_last_days, within_next_days, older_than_days, or exists.

Ranges include both bounds; before/after and greater/less comparisons are strict. Relative windows use whole days of 24 hours, from 1 to 3650, evaluated when the audience is resolved. The last N days excludes future dates; the next N days excludes past dates. Saving an audience does not freeze the clock. These filters select recipients; they do not schedule a campaign.

Use tags through MCP

The MCP tools expose device_tags_read, device_tags_patch, user_tags_read and user_tags_patch for live data. Supply app_id, then device_id or external_id, and the maps to merge. Each call checks your organization membership. They never send notifications.

audience_preview and audience_create accept the same typed filters as the API. Preview an audience before saving or sending to it.

On this page