Computed traits
A computed trait manufactures a new fact and stamps it onto a contact. You author a predicate over contact facts — LTV, last seen, lifecycle stage, opt-in flags — and every contact that matches gets the rule’soutput_tag applied to their profile. That tag then behaves like any other attribute: segmentable, personalizable, exportable.
The CDP audiences guide covers the API in brief. This page covers the dedicated Audience → Computed traits screen in the dashboard, the rule DSL in full, and the day-to-day operations behind it.
Deterministic rules, not AI suggestions
The platform carries three ways to derive traits. Pick deliberately, because the behavior differs:- Computed traits (this page) — a deterministic JSON predicate you author. Evaluation is a pure function: the same facts and the same predicate produce the same verdict every time. There is no LLM call in the evaluation path, so running a rule costs nothing per-contact.
- AI traits — an LLM fills a fixed set of score columns (churn, LTV, lifecycle, next-best-action). Useful when the signal can not be expressed as a comparison against recorded facts.
- Tag autopilot — an LLM proposes open-ended tag chips from free form language. A discovery surface, not a targeting primitive.
Permissions
The Audience → Computed traits screen is visible to owner, admin, and developer roles. A member with any other role (analyst, marketer, user) sees a gate message instead of the list. The same boundary exists on the API — list, evaluate, and preview calls accept owner/admin/developer/analyst/marketer, but create, update, delete, and run require owner/admin/developer. The screen-level gate is a courtesy so members without write access ever see an empty, non-functional list.The screen’s five states, and why they matter
The page is an exemplar of covering every state a list can be in, which is what makes it usable after you’ve authored more than a handful of rules:- Loading — skeleton rows match the table density, so the layout does not jump once data lands.
- Empty — a quiet inline message with a Create your first trait button — not an unbroken table.
- Error — an inline alert with a Retry button bound to re-fetch; a transient failure does not strand you.
- Permission gate — covered above.
- No matches — the toolbar search filters by name, description, and output tag; when a search excludes everything, a filtered empty state offers to clear the query instead of implying you have no traits at all.
Author a rule in the dashboard
Open Audience → Computed traits and press Create trait. The editor sheet has two halves. On the left you define the rule itself:- Name and optional Description — the WHY behind the rule for the next operator.
- Output tag — lowercase kebab-case, 1–64 characters (for example
high-value-active). This is the identifier stamped onto matching contacts, so it must be unique across your tenant. - Predicate — the rule’s JSON body. A starter predicate is pre-filled so you are editing a working baseline, not staring at a blank area. The DSL accepts nested
all_of/any_of/notcombinators over leaf comparisons; the editor shows the exact leaf shape inline. - Enabled — a disabled rule persists but no longer evaluates; tags it already stamped stay in place.
The DSL vocabulary
A predicate tree is made of leaf comparisons nested under combinators. Depth is capped at 8 levels and total leaves at 32, which keeps worst-case evaluation a known constant.
A leaf looks like this:
all_of (AND), any_of (OR), and not:
- Missing facts never match. A fact that is absent or the wrong type evaluates every leaf to
false— except a deliberateexists/not_existscheck. Absence cannot creep into your audience by accident. - Versioned DSL. The predicate shape is pinned to a DSL version. Saved rules validate against it at read time, so an old rule is never silently misread by an upgraded evaluator.
predicted_ltv, churn_risk_score, lifecycle_stage, engagement_score, last_seen_at, created_at, total_revenue, email_optin, sms_optin — and any custom field key is fair game; the vocabulary is open.
The API surface
Everything the screen does, the API does. Owner/admin/developer for writes; the read plus evaluate endpoints accept analyst and marketer as well.
Updates are partial — send only the fields you are changing, and every field is individually optional. Property edits are idempotent by nature: repeating the same payload leaves the rule in the same state. A duplicate
output_tag comes back 409; a malformed predicate is 422 with one error message per issue; a predicate that exceeds the depth or leaf budget is 400 with the reason inline.
The preview endpoint takes a flat fact bag in the body and returns the boolean verdict without writing anything:
How assignments stay in sync
Creating a rule does not stamp it immediately. Two paths move tags onto contacts:- A scheduled evaluator sweeps enabled rules periodically and reconciles each assignment set, adding the tag to new matches and removing it from contacts that no longer match — so membership tracks the current data, not the data at first run.
- Run now (the row action in the dashboard, or
POST .../:id/run) applies a rule on demand, with the same add-and-remove reconciliation but bounded per run. The response reportsevaluated,matched,tag_added,tag_removed, and acappedflag that tells you the run hit its per-run ceiling for large tenants. Whencappedis true the response tells you some contacts were not reached — re-run to continue the sweep.
Where the stamped tags are used
Once a rule materializes, itsoutput_tag is just another attribute. Segments filter on it (tag equals high-value-active), journeys branch on it, exports include it, and personalization slots read it. That is the point of the whole surface: a deterministic way to upconvert your raw facts into one stable, addressable, budget-friendly label — and to do it with the same rigor as the segment definitions in the CDP audiences guide.