Segments

Rule-based audiences over project user fields, attributes and tags, with nested and/or groups.

A segment is a saved, named condition tree. Target it with { "type": "segment", "segmentId": "seg_…" }. Membership is evaluated each time a user's feed loads (see read-time evaluation). Segments need the Growth plan and up (see plan features).

Shape

{
  "name": "Pro users in the beta",
  "description": "Pro plan and opted into the beta",
  "conditions": {
    "combinator": "and",
    "conditions": [
      { "field": "attributes.plan", "operator": "eq", "value": "pro" },
      { "field": "tags", "operator": "contains", "value": "beta" }
    ]
  }
}

A group has a combinator (and or or) and a list of conditions, each either a condition (field, operator, value) or another group.

Fields

FieldTypeNotes
tagsstring listSet from your backend only.
emailstring
namestring
localestringThe project user's locale, e.g. de-AT.
timezonestringAs set in the SDK's user profile or from your backend, e.g. Europe/Berlin. The SDKs don't detect it.
createdAtepoch msWhen the project user was first created: by their first SDK session, your backend, or a users notification sent to them.
attributes.<key>any attribute valueCustom attributes. Keys in conditions may use letters, digits, _, . and - (up to 64 characters).

Operators

OperatorMatches whenMissing value (null / not set)
eqequalno match
neqnot equalmatches
inequal to one of value (an array)no match
not_innot equal to any of valuematches
containsstring contains value, or list has an element equal to valueno match
not_containsthe opposite of containsmatches
starts_withstring starts with valueno match
ends_withstring ends with valueno match
gt, gte, lt, ltenumeric comparisonno match
existsthe field has a non-null valueno match
not_existsthe field is missing or nullmatches

Comparison rules:

  • String comparisons are case-insensitive (eq, in, contains, starts_with, ends_with).
  • Lists: when the field is a list (such as tags or a string-array attribute), eq and contains match if any element matches.
  • Numbers: if either side is a number, both are compared as numbers, so "42" equals 42. Booleans count as 1 and 0.
  • Dates: gt/gte/lt/lte convert strings to numbers, and strings that aren't numbers are parsed as dates. { "field": "createdAt", "operator": "gte", "value": "2026-01-01" } compares against midnight UTC on 1 January 2026.
  • Values can be a string (up to 1,024 characters), number, boolean, null or a list of up to 100 strings. in and not_in need a list.

Nesting and limits

LimitValue
Group nesting3 levels (the root group plus two levels of nested groups)
Conditions per segment50, counting groups and conditions at every level
Conditions per groupat least 1
Name1 to 100 characters
Descriptionup to 500 characters
Pro or Team users in Germany or Austria who joined this year
{
  "combinator": "and",
  "conditions": [
    { "field": "attributes.plan", "operator": "in", "value": ["pro", "team"] },
    {
      "combinator": "or",
      "conditions": [
        { "field": "locale", "operator": "starts_with", "value": "de" },
        { "field": "timezone", "operator": "in", "value": ["Europe/Berlin", "Europe/Vienna"] }
      ]
    },
    { "field": "createdAt", "operator": "gte", "value": "2026-01-01" }
  ]
}

Preview before saving

POST /v1/segments/preview evaluates a condition tree over up to 1,000 of the most recently active project users and returns how many matched, plus up to five examples. It's an estimate for sanity checks, not an exact count, and it doesn't write anything. It works on every plan, even without an active subscription.

curl https://api.notificationstream.com/v1/segments/preview \
  -H "Authorization: Bearer $NOTIFICATIONSTREAM_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"conditions":{"combinator":"and","conditions":[{"field":"attributes.plan","operator":"eq","value":"pro"}]}}'
{ "sampled": 1000, "matched": 132, "examples": [{ "userId": "user_123", "email": "ada@example.com", "name": "Ada Lovelace" }] }

Manage segments

EndpointPurpose
GET /v1/segmentsAll segments of the project, sorted by name (not paginated)
POST /v1/segmentsCreate
GET /v1/segments/{id}Read
PATCH /v1/segments/{id}Update name, description or conditions. Applies to already published notifications too.
DELETE /v1/segments/{id}Delete. Notifications that targeted it stop matching anyone.

Attributes can come from the client

The SDK may sync profile fields and attributes for its user, so a user can change their own attributes. Don't use attribute-based segments to gate confidential content. Use tags (server-only) or users audiences for that. See Security.