Amba

Segment Operators

All 12 operators supported by the Amba segment rule evaluator, with examples of the fields each one works on.

This page lists every operator the segment rule evaluator supports, the fields each one is valid against, and the exact SQL that gets emitted. All identifiers are whitelisted — admin-authored rules cannot inject arbitrary SQL.

Operator reference

OperatorValid onExample
eqanyproperties.plan eq "premium"
neqanyproperties.plan neq "free"
gtnumeric / timestampproperties.total_xp gt 1000
gtenumeric / timestampproperties.streak_count gte 7
ltnumeric / timestampproperties.age lt 25
ltenumeric / timestampproperties.age lte 25
containsstring / text-castable fieldemail contains "@example.com"
not_containsstring / text-castable fieldemail not_contains "spam"
existsanyemail exists
not_existsanyemail not_exists
withindate column onlylast_seen_at within "7d"
not_withindate column onlylast_seen_at not_within "30d"

Field domains

The evaluator resolves field into one of four target surfaces. Anything outside the whitelists silently falls back to FALSE (the condition never matches) rather than raising — an admin typo in a rule won't take the workflow down.

Direct user fields

Whitelisted: id, external_id, anonymous_id, email, phone, display_name, first_seen_at, last_seen_at, created_at.

{ "field": "email", "op": "exists" }
{ "field": "last_seen_at", "op": "within", "value": "14d" }

Custom properties (properties.*)

Any path matching [a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*. Nested keys are safe to address with dot notation:

{ "field": "properties.plan", "op": "eq", "value": "premium" }
{ "field": "properties.user.level", "op": "gte", "value": 10 }

within / not_within are not supported on property fields — promote the value to a typed column if you need time-based filtering.

Entitlements (entitlements.*)

Whitelisted columns: entitlement_id, product_id, is_active, store, period_type, purchase_date, expiration_date.

{ "field": "entitlements.is_active", "op": "eq", "value": true }
{ "field": "entitlements.product_id", "op": "eq", "value": "premium_monthly" }

A user matches the clause if they hold any entitlement satisfying it.

Unknown fields

Treated as never-matching. No error is raised — the condition simply evaluates to false. This keeps a misconfigured rule from taking the whole segment evaluation down.

Duration literals (within / not_within)

Values are parsed as <number><unit>:

UnitMeaning
mminutes
hhours
ddays
wweeks

Examples: "15m", "24h", "7d", "2w". Invalid literals (bad unit, non-numeric) fall back to FALSE.

{ "field": "last_seen_at", "op": "within", "value": "7d" }
{ "field": "created_at", "op": "not_within", "value": "30d" }

within matches values from the last N <unit>; not_within matches values older than that.

contains / not_contains

Case-insensitive substring match. The value must be a string — a numeric value on a contains clause never matches.

{ "field": "properties.tags", "op": "contains", "value": "fitness" }
{ "field": "email", "op": "not_contains", "value": "@example.com" }

On entitlement fields the same substring check runs against each of the user's entitlements; a user matches if any one of them does.

exists / not_exists

On direct user fields: matches when the field is set (exists) or unset (not_exists).

On property paths: works the same way over nested property keys.

On entitlements: matches when the user has any entitlement with that field populated.

Composing rules

A rule is a tree of boolean groups. Each group has an operator (AND / OR) and a conditions array; entries in conditions are either leaf conditions or further nested groups. The evaluator wraps each group in parens, so operator precedence is explicit — you don't have to memorise that AND binds tighter than OR.

Flat (single group) rules are still the common case:

{
  "operator": "AND",
  "conditions": [
    { "field": "last_seen_at", "op": "within", "value": "7d" },
    { "field": "entitlements.is_active", "op": "eq", "value": true },
    { "field": "properties.streak_count", "op": "gte", "value": 5 }
  ]
}

Nested boolean groups

Mix groups to express things like "active iOS users AND (Pro OR Enterprise plan)":

{
  "operator": "AND",
  "conditions": [
    { "field": "last_seen_at", "op": "within", "value": "7d" },
    { "field": "properties.platform", "op": "eq", "value": "ios" },
    {
      "operator": "OR",
      "conditions": [
        { "field": "properties.plan", "op": "eq", "value": "pro" },
        { "field": "properties.plan", "op": "eq", "value": "enterprise" }
      ]
    }
  ]
}

Depth is capped at 5 (the top-level group counts as depth 1). Rules deeper than the cap are rejected with SEGMENT_RULES_TOO_DEEP. An empty inner AND group evaluates to TRUE; an empty inner OR group evaluates to FALSE — algebraic identity, so adding an empty branch never changes the truth value of an enclosing group of the same operator.

Evaluation cadence

Every 15 minutes, Amba re-evaluates every non-system segment and recomputes segment_memberships. Manual POST /admin/segments/:id/evaluate triggers a one-off immediate run against that segment only.

Next

On this page