Segment filter reference
The filter syntax shared by dynamic segments, filtered campaign audiences, and workflow conditions
One filter format shows up in three places: dynamic segments, campaign audiences with audienceType: "FILTERED", and CONDITION steps inside workflows. Master it once and it carries over everywhere.
If you'd rather start with concepts than syntax, read the Segments concept page first.
How a filter is structured
Every filter consists of a top-level connector (AND or OR) plus a list of groups. Within a group, all conditions are joined with AND; the top-level connector then combines the groups.
An example makes it concrete: "subscribed users and on the Pro plan and (opened or clicked an email recently)".
{
"logic": "AND",
"groups": [
{
"filters": [
{ "field": "subscribed", "operator": "equals", "value": true },
{ "field": "data.plan", "operator": "equals", "value": "pro" }
]
},
{
"filters": [],
"conditions": {
"logic": "OR",
"groups": [
{ "filters": [{ "field": "email.opened", "operator": "triggeredWithin", "value": 14, "unit": "days" }] },
{ "filters": [{ "field": "email.clicked", "operator": "triggeredWithin", "value": 14, "unit": "days" }] }
]
}
}
]
}Nesting works by giving a group its own conditions — that's how you express "this AND (that OR this)" without collapsing the logic into one level. When you work in the dashboard, the segment builder assembles all of this visually.
Fields you can filter on
Each field value carries a namespace prefix that tells Bitelio which aspect of the contact the condition targets.
| Field pattern | Targets | Examples |
|---|---|---|
email | The contact's email address | email |
subscribed | The contact's subscription state | subscribed |
createdAt, updatedAt | Built-in contact timestamps | createdAt |
data.<path> | Custom contact data — supports nested paths | data.plan, data.profile.tier |
event.<eventName> | Custom events tracked via /v1/track | event.signed_up |
email.<activity> | Email engagement: sent, delivered, opened, clicked, bounced, complained | email.opened |
segment.<segmentId> | Membership of another segment | segment.cuid_of_other_segment |
Operators
Which operators apply depends on the kind of field you're filtering.
Text fields
For email and any data.<key> that holds a string.
| Operator | What it does |
|---|---|
equals | Exact match — ignores case on email, case-sensitive on data.*. |
notEquals | The inverse of equals. |
contains | Substring match, ignoring case. |
notContains | The inverse of contains. |
Yes/no fields
For subscribed and any data.<key> that holds true or false.
| Operator | What it does |
|---|---|
equals | Match true or false. |
notEquals | The inverse. |
Dates and timestamps
For createdAt, updatedAt, and any data.<key> that holds an ISO 8601 date string.
| Operator | What it does |
|---|---|
equals / notEquals | Timestamp match. A date-only value (YYYY-MM-DD) matches anywhere within that UTC day. |
greaterThan / lessThan | Strictly after / strictly before. |
greaterThanOrEqual / lessThanOrEqual | The inclusive versions. |
within | Falls inside the last N units. Requires unit: "days" / "hours" / "minutes". |
olderThan | Lies more than N units in the past. Requires unit. |
On custom date fields (data.<key>), within and olderThan require the value to be stored as an ISO 8601 string (e.g. "2026-05-06T12:00:00Z"). Unix timestamps or other formats will compare incorrectly.
Numbers
Any numeric data.<key> supports: equals, notEquals, greaterThan, lessThan, greaterThanOrEqual, lessThanOrEqual. No unit is involved.
Field existence
Works on any data.<key>, whatever its value type.
| Operator | What it does |
|---|---|
exists | The key is set on the contact with a non-null value. |
notExists | The key is absent, or explicitly null. |
Events and email activity
The same operator set serves both event.<eventName> (custom events) and email.<activity> (email engagement).
| Operator | What it does |
|---|---|
triggered | The event has occurred for this contact at least once, at any point. |
notTriggered | The event has never occurred for this contact. |
triggeredWithin | Occurred at least once within the last N units. Requires unit. |
triggeredOlderThan | Has occurred, but not within the last N units. Requires unit. |
notTriggeredWithin | No occurrence in the last N units — contacts who never triggered it also match. Requires unit. |
Segment membership
For segment.<segmentId>, where <segmentId> is the ID of another segment in your project.
| Operator | What it does |
|---|---|
memberOfSegment | The contact currently belongs to the referenced segment. |
notMemberOfSegment | The contact does not belong to it. |
Quick reference: what to pass with each operator
- Take a
value:equals,notEquals,contains,notContains,greaterThan,lessThan,greaterThanOrEqual,lessThanOrEqual,within,olderThan,triggeredWithin,triggeredOlderThan,notTriggeredWithin. - Take a
unit("days","hours", or"minutes"):within,olderThan,triggeredWithin,triggeredOlderThan,notTriggeredWithin. - Take nothing else:
exists,notExists,triggered,notTriggered,memberOfSegment,notMemberOfSegment.
Examples
Engaged users on the Pro plan
Subscribed Pro-plan users who opened or clicked any email in the last 14 days but haven't clicked anything in the last 30 days.
{
"logic": "AND",
"groups": [
{
"filters": [
{ "field": "subscribed", "operator": "equals", "value": true },
{ "field": "data.plan", "operator": "equals", "value": "pro" }
]
},
{
"filters": [],
"conditions": {
"logic": "OR",
"groups": [
{ "filters": [{ "field": "email.opened", "operator": "triggeredWithin", "value": 14, "unit": "days" }] },
{ "filters": [{ "field": "email.clicked", "operator": "triggeredWithin", "value": 14, "unit": "days" }] }
]
}
},
{
"filters": [
{ "field": "email.clicked", "operator": "notTriggeredWithin", "value": 30, "unit": "days" }
]
}
]
}New trial users without a purchase
Subscribed contacts created in the last 7 days who haven't yet triggered a purchase event.
{
"logic": "AND",
"groups": [
{
"filters": [
{ "field": "subscribed", "operator": "equals", "value": true },
{ "field": "createdAt", "operator": "within", "value": 7, "unit": "days" },
{ "field": "event.purchase", "operator": "notTriggered" }
]
}
]
}Power users above a tier
Members of the power-users segment whose lifetime value is at least 500.
{
"logic": "AND",
"groups": [
{
"filters": [
{ "field": "segment.<powerUsersSegmentId>", "operator": "memberOfSegment" },
{ "field": "data.lifetimeValue", "operator": "greaterThanOrEqual", "value": 500 }
]
}
]
}