Audience event query filter
Search and aggregate audience events with a structured JSON filter. Group by event type, filter on parameters, run date histograms and sum metrics across the last N days.
The Event Query Filter is a structured JSON filter posted to /project/{project}/event/search (and related event endpoints) to find events by type, parameters, creation date or any native event attribute. It shares the overall shape of the Audience query filter but is specific to the event collection — the condition grammar is narrower and the aggregation surface is richer (date histograms, sums, metrics).
Quickstart
All create events from the last 30 days
{
"version": "0.0.1",
"root": {
"type": "group",
"join": "and",
"children": [
{
"type": "event_condition",
"key": "event-type",
"operator": "matches-string",
"values": ["create"]
},
{
"type": "event_condition",
"key": "created-at",
"operator": "range-date-relative",
"values": {
"lowerOffset": -30,
"upperOffset": null,
"lowerExcludeEquals": false,
"upperExcludeEquals": false,
"lowerRounding": false,
"upperRounding": false,
"lowerOffsetPeriod": "day",
"upperOffsetPeriod": "day"
}
}
]
},
"limit": 10,
"offset": 0
}Ecommerce orders between €100 and €200
{
"version": "0.0.1",
"root": {
"type": "group",
"join": "and",
"children": [
{
"type": "event_condition",
"key": "event-type",
"operator": "matches-string",
"values": ["ecommerce_order_create"]
},
{
"type": "event_condition",
"key": "ecommerce_order_create.order-euro-amount",
"operator": "range-number",
"values": {
"lowerNumber": 100.0,
"upperNumber": 200.0
}
}
]
},
"limit": 10,
"offset": 0
}Basic concepts
Filter structure
root— the main filter condition, typically agroupof event conditions.limit— maximum number of results to return.offset— number of results to skip.sortField— field to sort by (optional).sortAsc— sort direction:truefor ascending,falsefor descending (optional).
Condition types
event_condition— filter by a native event attribute or an event parameter.group— combine multiple conditions with AND/OR logic (join: "and" | "or").
Native event attributes
Available directly as key in an event_condition:
| Attribute | Meaning |
|---|---|
bucket | Bucket number. |
received-at | When the event was received. |
created-at | When the event was created. |
event-source | Source of the event. |
event-type | Type of event (e.g. create, update, ecommerce_order_create). |
audience-id | ID of the audience contact. |
audience-ids | Multiple audience contact IDs. |
audience-ds-ids | Audience datasource IDs. |
audience-categories | Audience categories. |
audience-target-groups | Audience target groups. |
ds-contact-id | Datasource contact ID. |
ds-id | Datasource ID. |
ds-event-id | Datasource event ID. |
Event parameters
Filter by event-specific parameters by prefixing the key with the event type. Examples:
create.source— thesourceparameter ofcreateevents.ecommerce_order_create.order-euro-amount— theorder-euro-amountparameter ofecommerce_order_createevents.
Parameter keys are auto-resolved based on the event type configuration of the project.
Common patterns
By event type and source
{
"version": "0.0.1",
"root": {
"type": "group",
"join": "and",
"children": [
{
"type": "event_condition",
"key": "event-type",
"operator": "matches-string",
"values": ["create"]
},
{
"type": "event_condition",
"key": "create.source",
"operator": "matches-string",
"values": ["datasource|_instasent"]
}
]
},
"limit": 10,
"offset": 0,
"sortField": "create.source",
"sortAsc": true
}Date range
{
"version": "0.0.1",
"root": {
"type": "group",
"children": [
{
"type": "event_condition",
"key": "created-at",
"operator": "range-date-relative",
"values": {
"lowerOffset": -30,
"upperOffset": null,
"lowerExcludeEquals": false,
"upperExcludeEquals": false,
"lowerRounding": false,
"upperRounding": false,
"lowerOffsetPeriod": "day",
"upperOffsetPeriod": "day"
}
}
]
},
"limit": 10,
"offset": 0
}Events for specific contacts
{
"version": "0.0.1",
"root": {
"type": "group",
"children": [
{
"type": "event_condition",
"key": "audience-id",
"operator": "matches-string",
"values": ["0aCcUIewHALKk9jpaS9QaazifbmUr8fB"]
}
]
},
"limit": 100,
"offset": 0
}Additional filter options
Top-level filters that narrow the result set without going through root:
| Field | Effect |
|---|---|
filterAudienceIds | Restrict to specific audience contact IDs. |
filterEventIds | Restrict to specific event IDs. |
filterEventIdsNot | Exclude specific event IDs. |
filterDatasourceIds | Restrict to specific datasource IDs. |
filterAudienceDatasourceIds | Restrict events for contacts from specific datasources. |
filterSamplingPercent | Retrieve only a percentage of results (0–100, default: 100). |
filterBucketMin | Minimum bucket number (0–100, default: 0). |
filterBucketMax | Maximum bucket number (0–100, default: 100). |
Example:
{
"version": "0.0.1",
"limit": 100,
"offset": 0,
"root": {
"type": "group",
"children": [
{
"type": "event_condition",
"key": "event-type",
"operator": "matches-string",
"values": ["create"]
}
]
},
"filterSamplingPercent": 33,
"filterAudienceIds": ["0aCcUIewHALKk9jpaS9QaazifbmUr8fB"],
"filterEventIdsNot": ["S9QaazifbmUr8fB0aCcUIewHALKk9jpa"]
}Cursor-based pagination
For large traverses, use cursor pagination instead of offset/limit. A cursor keeps a consistent snapshot of the data across requests.
How it works
- First request — run a query without a cursor. The response includes a
cursorstring. - Subsequent requests — pass the
cursorfrom the previous response to continue. - End of results — when
cursorisnull, there are no more results.
Cursor format
The cursor is a base64-encoded string containing a snapshot identifier, position information and a keep-alive setting. You do not need to parse or modify it — just pass it back as-is.
Using cursors
// First request
{
"version": "0.0.1",
"root": {
"type": "group",
"children": [
{
"type": "event_condition",
"key": "event-type",
"operator": "matches-string",
"values": ["create"]
}
]
},
"limit": 100
}
// Response includes: { "cursor": "eyJwb2ludEluVGltZUlkIjoiLi4uIn0=", ... }
// Next request — just pass the cursor
{
"cursor": "eyJwb2ludEluVGltZUlkIjoiLi4uIn0="
}Aggregations
Aggregations analyse and summarise the filtered events. All configuration goes inside params; use the @ prefix to reference event parameters — they are auto-resolved.
Date histogram
Group events by time intervals:
{
"version": "0.0.1",
"limit": 0,
"offset": 0,
"aggregations": {
"eventsByDay": {
"type": "date_histogram",
"params": {
"field": "@created-at",
"calendar_interval": "1d",
"format": "yyyy-MM-dd",
"time_zone": "UTC"
}
}
}
}Date histogram with nested aggregations
Calculate metrics for each time period:
{
"version": "0.0.1",
"limit": 0,
"offset": 0,
"aggregations": {
"salesByDate": {
"type": "date_histogram",
"params": {
"field": "@ecommerce_order_create.created-at",
"calendar_interval": "1d",
"format": "yyyy-MM-dd (EEE)",
"time_zone": "Europe/Madrid"
},
"aggs": {
"totalSales": {
"type": "sum",
"params": { "field": "@ecommerce_order_create.order-euro-amount" }
},
"orderCount": {
"type": "sum",
"params": { "field": "@ecommerce_order_create.product-count" }
}
}
}
}
}Fixed interval vs calendar interval
calendar_interval— calendar-aware intervals (1d,1w,1M,1y).fixed_interval— fixed time intervals (1h,6h,30m).
{
"version": "0.0.1",
"limit": 0,
"offset": 0,
"aggregations": {
"salesBy6HourInterval": {
"type": "date_histogram",
"params": {
"field": "@ecommerce_order_create.created-at",
"fixed_interval": "6h",
"format": "HH:00",
"time_zone": "UTC"
},
"aggs": {
"salesAmount": {
"type": "sum",
"params": { "field": "@ecommerce_order_create.order-euro-amount" }
}
}
}
}
}Terms aggregation
Group events by unique values in a field:
{
"version": "0.0.1",
"limit": 0,
"offset": 0,
"aggregations": {
"eventTypes": {
"type": "terms",
"params": {
"field": "@event-type",
"size": 10
}
}
}
}Terms with nested aggregations
Detailed metrics per category:
{
"version": "0.0.1",
"limit": 0,
"offset": 0,
"aggregations": {
"topProducts": {
"type": "terms",
"params": {
"field": "@ecommerce_order_create.product-name",
"size": 5,
"missing": "unknown",
"order": { "salesCount": "desc" }
},
"aggs": {
"salesCount": {
"type": "sum",
"params": { "field": "@ecommerce_order_create.product-count" }
},
"salesEuroAmount": {
"type": "sum",
"params": { "field": "@ecommerce_order_create.product-price-euro" }
}
}
}
}
}Sum aggregation
Calculate totals across matching events:
{
"version": "0.0.1",
"limit": 0,
"offset": 0,
"aggregations": {
"totalRevenue": {
"type": "sum",
"params": { "field": "@ecommerce_order_create.order-euro-amount" }
}
}
}Complete sales analysis
Sales patterns across multiple dimensions:
{
"version": "0.0.1",
"limit": 0,
"offset": 0,
"root": {
"type": "group",
"children": [
{
"type": "event_condition",
"key": "event-type",
"operator": "matches-string",
"values": ["ecommerce_order_create"]
},
{
"type": "event_condition",
"key": "created-at",
"operator": "range-date-relative",
"values": {
"lowerOffset": -21,
"upperOffset": 0,
"lowerOffsetPeriod": "day",
"upperOffsetPeriod": "day"
}
}
]
},
"aggregations": {
"totalSalesAmount": {
"type": "sum",
"params": { "field": "@ecommerce_order_create.order-euro-amount" }
},
"salesByDate": {
"type": "date_histogram",
"params": {
"field": "@ecommerce_order_create.created-at",
"calendar_interval": "1d",
"format": "yyyy-MM-dd (EEE)",
"time_zone": "UTC"
},
"aggs": {
"salesCount": {
"type": "sum",
"params": { "field": "@ecommerce_order_create.product-count" }
},
"salesEuroAmount": {
"type": "sum",
"params": { "field": "@ecommerce_order_create.order-euro-amount" }
}
}
},
"topProducts": {
"type": "terms",
"params": {
"field": "@ecommerce_order_create.product-name",
"size": 10,
"missing": "unknown",
"order": { "salesCount": "desc" }
},
"aggs": {
"salesCount": {
"type": "sum",
"params": { "field": "@ecommerce_order_create.product-count" }
},
"salesEuroAmount": {
"type": "sum",
"params": { "field": "@ecommerce_order_create.product-price-euro" }
}
}
}
}
}Listing event types in a project
{
"version": "0.0.1",
"limit": 0,
"aggregations": {
"total": {
"type": "terms",
"params": {
"field": "@event-type",
"size": 100
}
}
}
}Range aggregations
Group events into ranges:
{
"version": "0.0.1",
"limit": 0,
"offset": 0,
"aggregations": {
"contactsByBucketRange": {
"type": "range",
"params": {
"field": "@bucket",
"ranges": [
{ "from": 0, "to": 33 },
{ "from": 33, "to": 66 },
{ "from": 66, "to": 100 }
]
}
}
}
}Operators reference
Every condition node has the shape:
{
"type": "event_condition",
"key": "<event attribute or parameter>",
"operator": "<operator name>",
"values": "<values — shape depends on the operator>"
}The subsections below describe, for each operator, the exact shape of values and any behavioural notes. About key:
- A native event attribute (e.g.
event-type,created-at,received-at,audience-id,ds-id). - An event parameter, scoped by event type:
<event-type>.<parameter>— e.g.ecommerce_order_create.order-euro-amount,create.source. Parameters are resolved against the event-type configuration of the project, and their data type drives which operators are valid.
| Family | Operators |
|---|---|
| Generic | match-all, match-none, exists, exists-not |
| Boolean | matches-bool |
| String | contains, contains-not, startswith, startswith-not, endswith, endswith-not, matches-string, matches-string-not |
| Numeric | matches-number, matches-number-not, range-number, range-number-not |
| Date | matches-date, range-date, range-date-not, range-date-relative, range-date-anniversary, range-date-dayversary, range-date-timeversary |
| Geographic | geopoint-distance |
Conventions used below:
- Negation. Every operator with a
-notsuffix takes the samevaluesas its positive counterpart and inverts the match. A missing field is not matched by the positive operator and is matched by the negated one — i.e. negation is "not (positive match)", which includes events where the field is absent. - Multi-value fields +
&&prefix. For array-valued fields, string and numeric "list" operators default to OR semantics across the provided values. Passing"&&"as the first element ofvaluesswitches to AND — all values must be present."||"(the default) is also accepted explicitly.
Generic
These work regardless of the field's data type.
match-all
Matches every event. Used internally. values is ignored.
match-none
Matches no events. Used internally. values is ignored.
exists
The field is present on the event (non-null, and non-empty for array fields).
{ "type": "event_condition", "key": "ecommerce_order_create.coupon-code", "operator": "exists", "values": [] }exists-not
The field is missing or null.
Boolean
matches-bool
Exact boolean match. values must be an array with exactly one element: [true] or [false].
{ "type": "event_condition", "key": "ecommerce_order_create.is-first-order", "operator": "matches-bool", "values": [true] }String
Apply to fields of type STRING, KEYWORD and TEXT. All string operators accept an array of strings; the first element may optionally be "&&" or "||" to set the combination mode for multi-value fields (default || / OR).
| Operator | Behaviour | Case | Min length |
|---|---|---|---|
contains | Substring match (*value*) | Case-insensitive | 2 chars |
contains-not | Inverse of contains | Case-insensitive | 2 chars |
startswith | Prefix match (value*) | Case-insensitive | 1 char |
startswith-not | Inverse of startswith | Case-insensitive | 1 char |
endswith | Suffix match (*value) | Case-insensitive | 1 char |
endswith-not | Inverse of endswith | Case-insensitive | 1 char |
matches-string | Exact value match | Case-sensitive | 1 char |
matches-string-not | Inverse of matches-string | Case-sensitive | 1 char |
Max value length for contains / contains-not: 128 chars.
OR across multiple values (default):
{ "type": "event_condition", "key": "event-type", "operator": "matches-string", "values": ["create", "update"] }AND across multiple values (for multi-value fields such as audience-target-groups):
{
"type": "event_condition",
"key": "audience-target-groups",
"operator": "matches-string",
"values": ["&&", "vip", "newsletter"]
}Numeric
Apply to fields of type INT and DECIMAL.
matches-number / matches-number-not
Exact match against one or more numbers. Same && / || semantics as the string operators.
{
"type": "event_condition",
"key": "ecommerce_order_create.product-count",
"operator": "matches-number",
"values": [1, 2, 3]
}range-number / range-number-not
Range query. values is an object, not an array:
{
"type": "event_condition",
"key": "ecommerce_order_create.order-euro-amount",
"operator": "range-number",
"values": {
"lowerNumber": 100,
"upperNumber": 200,
"lowerExcludeEquals": false,
"upperExcludeEquals": false
}
}| Field | Type | Default | Meaning |
|---|---|---|---|
lowerNumber | number | null | null | Lower bound. null = unbounded below. |
upperNumber | number | null | null | Upper bound. null = unbounded above. |
lowerExcludeEquals | bool | false | If true, lower bound is exclusive (gt); otherwise inclusive (gte). |
upperExcludeEquals | bool | false | If true, upper bound is exclusive (lt); otherwise inclusive (lte). |
Both bounds null on range-number matches everything (and nothing on range-number-not).
Date
Apply to fields of type DATE. All date operators honour the project timezone.
matches-date
Exact day match. Internally expanded to [00:00:00, 23:59:59] in the project timezone.
{
"type": "event_condition",
"key": "created-at",
"operator": "matches-date",
"values": { "date": "2026-04-22" }
}| Field | Type | Notes |
|---|---|---|
date | string (YYYY-MM-DD) | Required. Exactly one. |
range-date / range-date-not
Absolute date range.
{
"type": "event_condition",
"key": "created-at",
"operator": "range-date",
"values": {
"lowerDate": "2026-01-01",
"upperDate": "2026-03-31",
"lowerExcludeEquals": false,
"upperExcludeEquals": false,
"lowerRounding": true,
"upperRounding": true
}
}| Field | Type | Default | Meaning |
|---|---|---|---|
lowerDate | ISO date/datetime | null | null | Lower bound. null = unbounded below. |
upperDate | ISO date/datetime | null | null | Upper bound. null = unbounded above. |
lowerExcludeEquals | bool | false | Exclude equality on lower bound (gt vs gte). |
upperExcludeEquals | bool | false | Exclude equality on upper bound (lt vs lte). |
lowerRounding | bool | false | If true, rounds the lower bound to the start of its day (/d). |
upperRounding | bool | false | If true, rounds the upper bound to the end of its day (/d). |
range-date-relative / range-date-relative-not
Range expressed relative to now.
{
"type": "event_condition",
"key": "created-at",
"operator": "range-date-relative",
"values": {
"lowerOffset": -30,
"upperOffset": 0,
"lowerOffsetPeriod": "day",
"upperOffsetPeriod": "day",
"lowerExcludeEquals": false,
"upperExcludeEquals": false,
"lowerRounding": false,
"upperRounding": false
}
}| Field | Type | Default | Meaning |
|---|---|---|---|
lowerOffset | int | null | null | Signed offset from now. Negative = past, positive = future. null = unbounded. |
upperOffset | int | null | null | Signed offset from now. |
lowerOffsetPeriod | enum | "day" | Unit of lowerOffset. One of: min, hour, day, week, month, year. |
upperOffsetPeriod | enum | "day" | Unit of upperOffset. Same options. |
lowerExcludeEquals | bool | false | Same semantics as range-date. |
upperExcludeEquals | bool | false | Same semantics as range-date. |
lowerRounding | bool | false | Rounds the bound to the start of the period. |
upperRounding | bool | false | Rounds the bound to the end of the period. |
range-date-anniversary
Matches date anniversaries independent of year (e.g. "happened in the next 7 days of the year", "falls between Jan 25 and Dec 01"). Only available on DATE fields backed by the anniversary index (event created-at and custom date parameters that opt in).
// Relative mode — N days before/after today's anniversary
{
"values": {
"mode": "relative",
"lowerOffsetDays": 0,
"upperOffsetDays": 7
}
}
// Absolute mode — month-day range (format MMDD)
{
"values": {
"mode": "absolute",
"lowerDate": "0125",
"upperDate": "1201"
}
}| Field | Type | Required when | Notes |
|---|---|---|---|
mode | "relative" | "absolute" | always | Default "relative". |
lowerOffsetDays | int | mode = relative | Signed. Negative = before, positive = after. gte. |
upperOffsetDays | int | mode = relative | Signed. Exclusive upper (lt). Default 1. |
lowerDate | string (MMDD) | mode = absolute | e.g. "0125" = Jan 25. |
upperDate | string (MMDD) | mode = absolute | Inverted ranges wrap around the year boundary. |
range-date-dayversary
Matches a weekday + hour-of-day window. Only valid on created-at. Use it for recurring weekly schedules — e.g. "orders on Friday evenings".
{
"type": "event_condition",
"key": "created-at",
"operator": "range-date-dayversary",
"values": { "lowerDay": "518", "upperDay": "523" }
}| Field | Type | Format | Example |
|---|---|---|---|
lowerDay | string | DHH — 1 digit weekday (1 = Monday … 7 = Sunday) + 2 digit hour (00–23) | "518" = Friday 18:00, gte. |
upperDay | string | same | "523" = Friday 23:00, lte. |
If the lower day/hour is greater than the upper (e.g. Friday → Monday), the range wraps across the week boundary automatically.
range-date-timeversary
Matches a time-of-day window independent of the date.
// Relative mode — N minutes around the current time
{
"values": {
"mode": "relative",
"lowerOffsetMinutes": -15,
"upperOffsetMinutes": 15
}
}
// Absolute mode — HH:MM range (format HHMM or HH:MM — colons are stripped)
{
"values": {
"mode": "absolute",
"lowerTime": "0900",
"upperTime": "1800"
}
}| Field | Type | Required when | Notes |
|---|---|---|---|
mode | "relative" | "absolute" | always | Default "relative". |
lowerOffsetMinutes | int | mode = relative | Signed, gte. |
upperOffsetMinutes | int | mode = relative | Signed, lt. Default 1. |
lowerTime | string (HHMM) | mode = absolute | 24h. "0900" = 09:00. |
upperTime | string (HHMM) | mode = absolute | Inverted ranges wrap across midnight. |
Geographic
geopoint-distance
Matches events within a radius of a (longitude, latitude) point. Only applies to geopoint fields (custom event parameters configured as geopoint).
{
"type": "event_condition",
"key": "store_visit.location",
"operator": "geopoint-distance",
"values": {
"longitude": -3.7038,
"latitude": 40.4168,
"distance": 25
}
}| Field | Type | Required | Notes |
|---|---|---|---|
longitude | decimal | yes | WGS-84 longitude. |
latitude | decimal | yes | WGS-84 latitude. |
distance | decimal | yes | Radius. Default unit is kilometres. |
All three fields are required; missing any raises a validation error.
values shape — quick reference
| Operator | values shape |
|---|---|
match-all, match-none | ignored |
exists, exists-not | [] |
matches-bool | [true] or [false] |
contains(-not), startswith(-not), endswith(-not), matches-string(-not) | string[], optional leading "&&" / `" |
matches-number(-not) | number[], optional leading "&&" / `" |
range-number(-not) | { lowerNumber, upperNumber, lowerExcludeEquals?, upperExcludeEquals? } |
matches-date | { date: "YYYY-MM-DD" } |
range-date(-not) | { lowerDate, upperDate, lowerExcludeEquals?, upperExcludeEquals?, lowerRounding?, upperRounding? } |
range-date-relative(-not) | { lowerOffset, upperOffset, lowerOffsetPeriod, upperOffsetPeriod, lower/upperExcludeEquals?, lower/upperRounding? } |
range-date-anniversary | { mode: "relative", lowerOffsetDays, upperOffsetDays } or { mode: "absolute", lowerDate: "MMDD", upperDate: "MMDD" } |
range-date-dayversary | { lowerDay: "DHH", upperDay: "DHH" } (only on created-at) |
range-date-timeversary | { mode: "relative", lowerOffsetMinutes, upperOffsetMinutes } or { mode: "absolute", lowerTime: "HHMM", upperTime: "HHMM" } |
geopoint-distance | { longitude, latitude, distance } |
Date histogram parameters
| Parameter | Type | Description | Example values |
|---|---|---|---|
field | string | Date field to aggregate on. | @created-at, @ecommerce_order_create.created-at |
calendar_interval | string | Calendar-aware intervals. | 1d, 1w, 1M, 1y |
fixed_interval | string | Fixed time intervals. | 1h, 6h, 30m, 1d |
format | string | Date format for bucket keys. | yyyy-MM-dd, HH:00, E |
time_zone | string | Timezone for date calculations. | UTC, Europe/Madrid, America/New_York |
offset | string | Time offset for bucket boundaries. | +1h, -30m |
min_doc_count | integer | Minimum document count per bucket. | 0, 1 |
extended_bounds | object | Extend bounds beyond data range. | {"min":"2024-01-01","max":"2024-12-31"} |
Terms aggregation parameters
| Parameter | Type | Description | Example values |
|---|---|---|---|
field | string | Field to group by. | @product-name, @event-type, @audience-categories |
size | integer | Number of top terms to return. | 5, 10, 100 |
missing | string | Label for documents with missing values. | "unknown", "N/A" |
order | object | Sort order for terms. | {"salesCount":"desc"}, {"_count":"asc"} |
min_doc_count | integer | Minimum document count per term. | 1, 5 |
include | array/string | Include only specific terms. | ["product1","product2"] |
exclude | array/string | Exclude specific terms. | ["excluded1","excluded2"] |
What's next
- Audience query filter — the contact-side filter, with segment and group_event conditions.
- API Reference — endpoints that accept this filter (
/event/search,/event/scroll,/event/aggregations).