Skip to main content
An attribute is a context key your application passes to decide()plan, device_type, cart_value, user_id. Parameters are what the SDK gets back; attributes are what it sends in.
You can send any key without registering it. Registering an attribute tells Traffical its type and legal values, which is what makes the rest of the platform aware of it.

Why register attributes

Registration matters most for strictness: SDKs evaluate conditions with no coercion. A context value 42 never matches a condition value "42". The registry is where the dashboard and API learn which one to store.

Types and formats

format only applies to string attributes. Timestamps must be numbers in context — the SDK relational operators compare numbers only; the dashboard’s date picker converts to epoch milliseconds for you.
semver marks a version string so the dashboard can label it, but relational comparison (gte "2.0.0") is not supported: gt/gte/lt/lte compare numbers. Target versions with in or expose a numeric build number.

values

For format: enum, values is the list of legal values (1–500 entries). Each value can carry a label and description. A condition value outside the list is a validation finding. For format: country, values is optional: leave it empty to accept any ISO 3166-1 alpha-2 code, or list a subset. Condition values are upper-cased and checked against the code list.

range

For number attributes, range: [min, max] (with min < max) bounds the values a condition may use. A condition value outside the range is a validation finding.

identifier

identifier: true marks an attribute that may serve as a unit key or entity key — user_id, anonymous_id, merchant_id. Identifiers default to logging: never. Traffical registers one identifier attribute per entity definition automatically, so your project’s unit keys are in the registry from the start.

logging

Context is evaluated inside the SDK. Whether a value is also written to the decision events and exposure events the SDK sends is decided per attribute: Use never for anything you target on but must not store — identifiers, email addresses, anything personal. allowed is the usual choice. always suits low-cardinality segmentation keys you want on every event, such as device_type. Contextual bandits read their features from the same list, so an attribute’s logging also determines whether a model can learn from it. See the context logging allowlist.

breakdown

breakdown: true marks an attribute as a dimension to split measured results by. The flag is stored today; result breakdowns by attribute ship in a later release. Setting it now means nothing has to be re-registered when they do.

System attributes

Keys that start with $ are reserved for Traffical. They are registered in every project, and you can edit only their label, description, logging, and breakdown. You cannot declare your own $ keys.

$unit_key — the unit this layer buckets on

Every layer hashes one context field to assign buckets — user_id for one layer, merchant_id for a layer with a different entity. $unit_key always means “that field, whatever it is in this layer”. Traffical replaces it with the concrete field name when it builds the config bundle, so the SDK sees an ordinary condition and no SDK change is involved. The typical use is a test-users policy: a policy at the top of the layer with one 100% allocation carrying the overrides you want to see, and the condition
The policy wizard’s scope step has an Add test users button that inserts this condition. Because the test-users policy is a separate policy, its exposures never enter the experiment’s analysis. $unit_key supports eq, neq, in, and nin. Its values are coerced to the type of the layer’s entity key (integer entities compare as numbers, everything else as strings). ID lists ship in the config bundle in clear text, so keep them to a handful of developer IDs.
Condition editor showing the key picker grouped into System and Attributes, a typed enum value input, and an unregistered badge on one row

The condition editor with $unit_key under System and a registered enum attribute

$env — resolved per environment

$env is an enum of your project’s environment IDs. A condition on $env is resolved when the bundle is built for each environment, not in the SDK: if it holds for that environment the condition is dropped, if not the policy is left out of that environment’s bundle entirely. The SDK never has to send $env.
runs the policy in staging only. Supported operators: eq, neq, in, nin.

$country — set on server-side resolution

When you resolve through the /v1/resolve endpoint, Traffical fills in $country from the request’s origin (ISO 3166-1 alpha-2) if your context does not already carry one. A value you send yourself is never overwritten. In bundle mode the SDK evaluates locally and nothing is injected, so send $country yourself if you need it there.

Web and mobile device keys

The remaining system attributes are filled by the SDKs’ opt-in collectors — the auto-attributes plugin in the browser SDK, and the default device-info providers on iOS and React Native. Register nothing: the keys exist in every project. Which keys are actually sent depends on the platform: the browser plugin sends the browser, page, UTM, and locale keys; the mobile providers send $os, $os_version, $app_version, $device_model, $device_type, $locale, and $timezone. See each SDK page for the exact derivation.

Enforcement modes

Attributes never block traffic. Enforcement decides what happens when you save a policy whose conditions reference an unregistered key, use an operator the attribute’s type does not allow, or carry a value that fails validation. Set it under Settings → Attribute enforcement: Unregistered keys keep working end to end in every mode: the SDK evaluates them as before, and the registry is never consulted at resolution time. Coercion only applies to registered keys — with no declared type there is nothing to coerce to, so the value is stored as you entered it.

Discovering attributes from traffic

Projects on Traffical’s managed warehouse get a Seen in traffic, not registered panel on the Attributes page. Once a day, Traffical scans the context on decision and exposure events from the last 7 days and lists each top-level key with how many decisions carried it, its inferred type, and its most common values. Register… opens the add sheet pre-filled from those stats; Dismiss hides a key you do not want to register. Projects that bring their own warehouse have no discovery panel — register attributes manually or from config.yaml.
Attributes list showing registered rows with key, type, and logging, and the Seen in traffic, not registered panel with Register and Dismiss actions

The Attributes list with the discovery panel

In the dashboard

Open Attributes in the project sidebar, directly after Parameters. Add attribute opens a sheet with key, label, description, type, format, values, range, identifier, logging, breakdown, and training hints. System rows show a lock and allow only label, description, logging, and breakdown edits. Attributes pushed from config.yaml are synced and read-only in the dashboard, like parameters.

Config as code

Declare attributes in .traffical/config.yaml and push them with the CLI. traffical push sends attributes before parameters, property groups, and events, so anything validated later in the run already sees the registry.
Keys must match ^[A-Za-z_][A-Za-z0-9_.]*$ and be at most 128 characters. $ keys cannot be declared here: pull never writes them and push rejects them. See the configuration file reference for every field.

Typed context

traffical generate-types reads the project’s registry and emits a TrafficalContext interface alongside the parameter and event types:
Enum attributes become unions of their values; timestamps are number. The index signature keeps unregistered keys compiling, so the type catches typos and wrong enum values without banning ad-hoc keys:

Next steps

Policies

Every operator, strict typing, and the field lookup rule.

Configuration file

The attributes: block field by field.

Browser SDK

Collect browser, page, and UTM attributes automatically.

Optimization

Context logging and contextual bandits.