Segments
A segment is a saved predicate list over your data: traits (from profiles in Postgres) and event history (from ClickHouse), combined with all or any. Membership is recomputed synchronously on every identify/track write, and on every backfill write, so an entry is visible to journeys immediately.
Definitions
Section titled “Definitions”{ "match": "all", "appId": ["app_storefront-dev", "app_storefront"], "predicates": [ { "kind": "trait", "name": "plan", "op": "eq", "value": "free" }, { "kind": "event", "name": "signed_up", "op": "performed", "withinDays": 30 }, { "kind": "trait", "name": "unsubscribed", "op": "notExists" } ]}match:all(default) orany. Deliberately flat: one list, no nested groups.appId: optional; scopes the event side of the definition, as one app id or a list of them. Traits merge across apps, so the trait side is never app-scoped. Omit it to span apps. There is deliberately no filter on the source an event arrived through: a definition naming a pipe that is later archived would parse and evaluate empty forever.
Trait predicates
Section titled “Trait predicates”Ops: eq, neq, gt, gte, lt, lte, contains, exists, notExists. The last two read no value; every other op requires one.
Comparison coerces form-friendly values before comparing: "150" matches 150 numerically, " TRUE " matches true for eq/neq (trimmed, case-insensitive), and contains is membership against array traits and substring against strings. Ordering never coerces booleans.
Event predicates
Section titled “Event predicates”Ops: performed, notPerformed, with atLeast (default 1) and optional withinDays, a rolling window relative to evaluation time; absent means all history. Merged anonymous events count (see Identity merging).
Environments
Section titled “Environments”A definition is shared, membership is not. Beside the definition, a segment carries an environments set saying where it works:
cow segments create --name "free trialers" --environments development \ --definition '{"match":"all","predicates":[…]}'It defaults to both, and listing one is how you try a cohort in development before it touches production users. Membership is computed per environment, and only in the environments the segment declares, so a development-only segment never gains a production member.
An app id lives in exactly one environment, so the appId filter is an environment filter as well: name both of a product’s app ids and the definition matches it whichever environment it is evaluated in, name one and it matches there only. See Environments.
Lifecycle
Section titled “Lifecycle”- Create: membership is computed over existing history immediately, in every environment the segment declares, so a segment built after a backfill catches up and those entries fire.
- Widen: adding an environment computes membership over that environment’s existing history the same way, so entries fire there for data that predates the change. Removing one drops its membership rows.
- On write: every profile or event write recomputes the affected segments declared for that profile’s environment.
- Transitions: entering or leaving emits
system.segment_entered/system.segment_exitedsystem events into ClickHouse. They are first-class journey triggers:{ segment: "trialers" }indefineJourneyrides the same path as a raw event.
Preview before you save
Section titled “Preview before you save”POST /v1/segments/preview runs a not-yet-saved definition over existing profiles and returns the match count plus a small sample of member userIds:
cow segments preview --match all \ --predicates '[{"kind": "trait", "name": "plan", "op": "eq", "value": "free"}]'The scan is bounded (1,000 profiles per call, rate-limited per org); when the cap is hit the count is reported as truncated, a floor rather than the exact number. The saved segment’s memberCount is always exact.
Time-decaying states are journeys, not predicates
Section titled “Time-decaying states are journeys, not predicates”“Active in the last 30 days” evaluated by the wall clock is deliberately not an evaluator feature. Express it as a per-user journey with a durable timer that sets and unsets a trait, then point a segment at that trait. See Journey composition and the activity-decay template.