Segments
A segment is a saved rule over traits and event history, and the set of people it currently matches. Membership is recomputed the moment somebody is written, and again when a time window in the rule lapses.
{ "match": "all", "predicates": [ { "kind": "trait", "name": "plan", "op": "eq", "value": "free" }, { "kind": "event", "name": "signed_up", "op": "performed", "withinDays": 30 }, { "kind": "trait", "name": "unsubscribed", "op": "notExists" } ]}Every op and every rule that governs one is in the predicate reference.
Three kinds
Section titled “Three kinds”- Standalone: built here, in the dashboard or over the API. For exploring, counting, filtering the users list, and exporting to your BI tool. It starts no automation.
- Owned by an automation: created by a push, because an automation’s trigger inlined its predicate list (
trigger: { segment: { … } }). It is named after the automation and shown on the automation’s page. Its predicates live in your code, so it has no edit or delete action here: change the trigger and push again. Deleting the automation deletes it. - A file in your repo:
segments/loyal.json, holding the samematchandpredicatesthe API takes (plus optionaltagsanddescription), pushed with everything else. Named after the file, and any automation in the same repo enrolls from it with"trigger": { "segment": "loyal" }. Reach for it when two automations want the same audience; one automation’s own audience belongs in its trigger. Its predicates live in your repo too, so it has no edit or delete action here either: change the file and push again. A push adds and updates but never deletes, so removing the file leaves the segment where it is.
Only a segment your repo writes starts an automation; a standalone one starts nothing.
A segment name is unique across your organization, so a push is refused, naming both, when the name it wants is already a segment someone built here or another app’s file. Rename one. The segment an automation’s own trigger defines is named after the automation’s app and key (app_website/welcome), so it never collides with a file’s.
A segment belongs to one app, and so does everyone in it. The definition names no app: the segment’s own app is the one it evaluates, so both sides of a rule, the traits and the event history, read that app’s profiles and that app’s events and nothing else. An owned segment takes the app of the automation that declared it, a pushed file takes the app its repo pushes to, and a standalone one takes the app you create it under.
The same person using two of your products is two profiles, one per app, so a rule about “customers on the free plan” gives you one segment per app rather than one merged audience. Filter the segments list by app to see whose is whose.
What changes membership
Section titled “What changes membership”- Create: membership is computed over existing history immediately, so a segment built after a backfill catches up.
- Every write: an
identifyortrackre-evaluates that person against their own app’s segments. A batch import does too, quietly. - Time: a
withinDayswindow that lapses, or a date compared with now that flips, re-evaluates the person on its own, to the minute, with nothing written. See Windows lapse on their own. - Transitions: entering or leaving emits a
system.segment_entered/system.segment_exitedevent, which is what the timeline shows. Each carries asource:"write"for a live write,"clock"for a window that lapsed,"recompute"for a bulk computation or an import,"enable"for someone let in when an automation was turned on. Only"write"and"clock"start automations.
Editing a definition recomputes everybody and starts no automation. Why that is, and how to check a rule before you save it, is in Testing a segment.
Where next
Section titled “Where next”- Predicate reference: every kind, every op, and how values compare.
- Testing a segment: preview a definition, read the count, widen a rule safely.
- Automations: starting one when somebody enters a segment.