attribute:read); the values live on each user/company
object.
Naming
AcodeName created through the API must start with a letter and contain only
letters, digits, and underscores, 2–100 characters (snake_case is the
convention — signed_up_at, last_login_time). It is case-sensitive and unique
per scope. SDK ingestion is deliberately more lenient: an attribute key your app
sends that isn’t defined yet is auto-created with a type inferred from the
first value — so send a number as 42 (not "42") and dates as full ISO
timestamps; a wrongly inferred type can be corrected later while no stored value
conflicts.
Display names (shown in the Usertour UI) are configured separately — e.g.
signed_up_at can display as “Signed Up”.
Data types
Random bucketing
random_ab and random_number attributes exist for users and companies only.
Their values are not written by you — Usertour derives each one from the
attribute and the user (or company) id, so it is fixed the moment the attribute
is created, the same on every device, and the same after a data export and
import. Existing users and companies receive their values in the background
right after the attribute is created.
Use them in segments and content targeting:
- A/B test — target one flow at
experiment is Aand its variant atexperiment is B. - Canary rollout — target
rollout_percent <= 10on arandom_numberattribute withrandomMax: 100, then raise the bound over time; a user included at 10 stays included at 20.
randomMax are locked once the attribute exists, and writing to
the attribute is refused: the REST API answers 400, the SDK drops the key and
names it in the call’s result.
Best practices
- Use the most specific type — store dates as
datetime, flags asboolean(not strings). - Keep names concise but descriptive; avoid system/reserved names.
- Don’t store large blobs in attributes.