Skip to main content

Lists vs segments: the two membership models

The Audience hub surfaces two ways to define who you can reach, and they look similar on the grid — both are targetable by campaigns, both export to CSV, both show a member count. They differ underneath: a list is a stored set of contact ids; a segment is a stored predicate. Membership in a list is an explicit row someone added. Membership in a segment is a derived result the platform recomputes as contact data moves. Pick the wrong one and you either re-send to a stale roster or freeze an audience you expected to keep updating. The two guides cover each in isolation — Static contact lists for the list model, Build CDP segments for the segment model — and the segment recompute model defines when a segment’s membership actually moves. This page is the frame between them: the one vocabulary that names the difference, the decision table that picks the right construct per use case, and the footguns that bite when the two are confused.

1. The two membership models

Phrase both in one vocabulary and the difference collapses to a single question — is membership stored or derived?
  • A list is a stored set of contact ids. Membership is an explicit row: a contact is on the list because someone (or an API call) added them, and they leave only when someone removes them. The list holds the membership; the membership does not change unless the list itself is edited. There is no recompute, no filter, no “current state” to drift — the list is the current state.
  • A segment is a stored predicate. Membership is a derived result: a contact is in the segment because, at the last recompute tick, running the segment’s filter against that contact’s profile returned true. The segment holds the rule, not the roster. The roster is materialized by running the rule, and it is re-run on the cadence the segment recompute model defines — a near-real-time per-contact pass on the event stream plus a scheduled batch backstop, with enriched profile traits refreshed daily.
The one-line restatement: a list answers “who did I add?”, a segment answers “who matches right now?” A list never goes stale on its own; a segment is designed to go stale and then refresh.

2. What each ships with

The two constructs come with different machinery, because they answer different questions.

The list model

  • Manual add, manual remove. Members arrive by search-and-pick in the dashboard, by direct identifier (phone, email, or contact id) over the Contacts API, by bulk add (POST /api/v1/contacts/lists/{id}/members/bulk, up to 1,000 ids per call), or by CSV import that attaches contacts to a list in one pass. Removal is a row-level action; the contact itself is untouched — only the grouping is gone.
  • Stable membership. Once added, a contact stays until removed. No background process touches the roster. This is the point and the discipline: a list built for a regulatory notice does not silently drop a contact who later unsubscribed — eligibility (consent, opt-outs, quiet hours) is still enforced at send time by the messaging pipeline, but membership is frozen until you touch it. Re-curate before reuse.
  • No recompute. There is nothing to recompute. The member count is a count of rows, not a count of predicate matches. The list’s freshness is exactly the freshness of the last add/remove you performed.
  • Ideal for fixed cohorts. Event invitees, a VIP group a success manager hand-picked, a suppression roster legal approved, a one-off re-engagement wave, a regulatory-notice recipient set that must not drift. See the static lists guide for the full workflow.

The segment model

  • A predicate over contact data. The segment’s filter references profile fields, computed traits, scores, and behavioral events — “contacts whose lifecycle_stage is active and total_orders ≥ 5”, or “contacts in the top churn-risk tier.” The filter is the source of truth; the materialized membership is a read over it.
  • Recomputed on a cadence. Membership is re-evaluated near-real-time per contact (the event-stream pass) and reconciled by a scheduled batch sweep; enriched profile traits the filter references are refreshed on a daily sweep. See the segment recompute model for the per-surface staleness table — the dashboard badge converges in ~1s, ad-audience syncs land in hours.
  • Reflects fresh state automatically. A contact that newly qualifies is entered; one that no longer qualifies is exited. A growing segment keeps working in a recurring campaign without anyone editing the campaign — this is the property a list does not have.
  • Ideal for standing rules. “Everyone who bought in the last 30 days”, “churn risk above 60%”, “active customers” — audiences that should keep themselves current. See the segments guide for building them, and the scoring pipeline for the scores a segment filter can read.

3. Decision table — which construct for which use case

Walk the table before you build. If the audience is a decision a human made (a hand-picked cohort, an approved roster), it is a list. If the audience is a rule that should keep itself current, it is a segment. The rule behind the table: if the answer to “who is in this audience?” changes between when you build it and when you send, and you want it to — use a segment. If it must not change — use a list.

4. How they interact

The two constructs are not walled off from each other. Three interactions matter, and the third is the one that bites.
  1. A segment can be materialized into a list (snapshotting). Export a segment’s current membership to CSV (GET /api/v1/contacts/segments/:id/export.csv), then import that CSV into a list — or, where the segments surface offers it, snapshot the current membership into a static list directly. The result is a list that holds the segment’s membership at the moment you materialized it. The snapshot does not inherit the segment’s recompute; it is a list from that point on, with all the list properties — stable, frozen, no recompute.
  2. A list can be one input to a segment predicate. A segment filter can reference list membership — “in segment active_buyers and not in list suppression_roster” combines a derived audience with a stored one. The segment recomputes; the list’s membership is read as-is at recompute time. This is how a standing rule and a hand-curated suppression set compose.
  3. A send can target either directly. Over the campaigns API, target a list with audience_type: "list" and the list id, or target a segment with its id. At send time the difference is when membership is frozen: a list resolves to the members it holds when the audience resolves (a fixed roster — contacts added after the send resolves are not swept in); a segment can re-evaluate its filter at send time, so a growing segment keeps working without anyone touching the campaign. See Campaign end-to-end for the send-time resolution.

The snapshot-then-diverge footgun

The footgun lives in interaction #1. Materializing a segment to a list freezes membership. If you built the audience as a segment because it should keep updating, and then you materialize it to a list for a one-time convenience (a CSV for a downstream tool, a static copy for an export), the list does not track the segment — it holds the snapshot. A contact who qualifies tomorrow is not in the list; a contact who exits tomorrow is still in the list. The fix is a usage rule, not a setting: if you expect the audience to keep updating, stay on the segment. Materialize to a list only when the one-time copy is the point — a regulatory notice whose recipients must not drift, a legal send that needs a frozen, auditable roster, a one-off export. For a recurring campaign, target the segment directly; for a send whose recipients must be frozen, materialize once and use the list. The worked example below walks both lifecycles.

5. Scale and cost notes

The two constructs scale differently, and the cost model is worth naming before you pick on size alone.
  • A list is O(rows stored). Member count is a row count; cost is the storage of the membership rows and the add/remove traffic you generate. A list of 1M contacts is 1M rows that do nothing until you touch them. There is no recompute spend, no per-send fan-out beyond resolving the roster.
  • A segment’s cost follows the predicate complexity and the recompute cadence. A filter over a single profile field is cheap; a filter over behavioral event counts, computed traits, and scores costs the evaluation of each at every recompute tick. The real-time per-contact pass is bounded to the one contact an event binds to, but the scheduled batch sweep re-evaluates the tenant’s full auto-refresh set — a complex predicate across a large population is the expensive shape. See the segment recompute model for the cadence that drives the sweep.
  • Very large segments fan out per-send. A send that targets a segment re-evaluates the filter at send time, and a journey that triggers on segment entry or exit enrolls every contact that crosses — the journey enrollment fan-out page defines the per-journey entry rate limit that bounds that blast radius. A list send resolves a fixed roster and does not re-evaluate; the fan-out difference is the send-time re-evaluation, not the membership size alone.
The short version: a list’s cost is storage and edit traffic; a segment’s cost is predicate evaluation × recompute frequency × population, plus the send-time fan-out when a send or journey re-evaluates the filter. A very large, frequently-recomputed segment is the shape to budget — a very large, hand-curated list is just a large list.

6. Worked example — a “last-90-day buyers” audience

Two sends need the same logical audience — contacts who bought in the last 90 days — but they answer different questions, so they take different constructs.

Build it as a segment (for a weekly recurring campaign)

The campaign runs every Monday and must reach whoever matches this week — new buyers enter as their purchases land, and buyers whose last purchase ages past 90 days exit. Build it once as a segment:
The segment recomputes on the cadence the recompute model defines — the event-stream pass moves a contact the moment a new purchase lands, the batch sweep reconciles, and the weekly campaign re-evaluates the filter at each send. You build it once and it stays fresh for the life of the campaign. Target the segment directly with the campaign; do not materialize it, or you freeze the very freshness you built the segment for. A legal notice must go to the buyer population as it stood at approval time, and the recipient set must not drift between legal sign-off and delivery — a contact who buys tomorrow is not a recipient, and a contact who exits tomorrow still is. Materialize the segment to a list once:
The list is a static snapshot of the segment at the moment you exported it. It does not track the segment; a contact who qualifies tomorrow is not in the list, and that is the point — the legal send’s recipients are fixed at approval and do not move. Target the list with audience_type: "list" for the notice send.

Contrast the two lifecycles

The same logical audience, two constructs, two lifecycles — and the footgun is exactly the difference between the two rows: materialize the segment to a list and the left column becomes the right column. Stay on the segment for the weekly campaign; materialize once for the legal notice.

Cross-references

  • Segment recompute model — when a segment’s membership actually moves, and the per-surface staleness table.
  • CDP streaming destinations — streaming the membership-crossing events that drive a segment to a Kafka topic or Kinesis stream.
  • Journey enrollment fan-out — the entry rate limit that bounds the blast radius when a journey triggers on segment entry or exit.
  • Contact scoring pipeline — the daily scores a segment filter can read, and the on-demand pass for freshly imported contacts.
  • Ad-audience incrementality — the holdout and lift measurement for a segment activated to a paid-media audience.
  • Build CDP segments — the guide for building the segment whose lifecycle this page contrasts.
  • Static contact lists — the guide for the list model this page contrasts.
  • Audience hub — the tile map where Lists and the segment surfaces sit side by side on the grid.