Filters and segmentation
Filters let you select a subset of your data for analysis. Use them to segment users, pick out specific events, and build complex conditions.
What are filters?
A filter is a set of conditions that decides which events or users are included in the analysis. Filters run at the SQL query level (but you never need to know SQL), which keeps execution fast and efficient.
Filter structure
Filters in Metriox have a hierarchical structure:
- Filter
- Logic — AND or OR
- Predicates
- Predicate 1
- Predicate 2
- and so on
Filter logic
Logic defines how the conditions are combined:
- AND — every condition must match
- OR — at least one condition must match
Predicate types
A predicate is a single filter condition. It consists of:
- Type — an event, a property, or a user
- Operator — the comparison operation
- Value — what you compare against
- Negation — NOT (optional)
These four parts form one row in the filter builder. Here is how it looks on the Events page: the NOT toggle, the field, the operator, and the value, with the Add filter type menu adding the next predicate.

Event predicates
Filtering by event name:
Event [NOT] equals "button_click"
Event [NOT] contains "purchase"
Operators for events:
equals— exact matchcontains— contains a substring
Examples:
| Condition | What matches |
|---|---|
Event equals "purchase_completed" | Only events named purchase_completed |
Event contains "button" | Events button_click, button_view, share_button, and any other name containing that substring |
Event NOT equals "bot_started" | Every event except bot_started |
Property predicates
Filtering by event properties:
Property [NOT] <operator> <value>
The available operators depend on the property's data type.
User predicates
These select whole users rather than individual events, based on how they behaved over the chosen period — "users who opened the bot on at least 5 different days", or "users who spent more than 10,000". The predicate first computes a figure per user, then keeps the users who clear the threshold.
It has four parts:
| Part | What it sets | Example |
|---|---|---|
| Metric | what to measure per user | Event Count, Unique Days, Unique Events, Sum |
| Counting events | which events to count (required) | successful_payment |
| Window | measure over the whole period, or per day | Total / Per Day |
| Threshold | operator and number | > 10000 |
"Counting events" is required. Without saying which events to count, the figure means nothing — more than 5 of what? A request missing it is refused rather than counting every event indiscriminately.
The Sum metric additionally needs a numeric property and a source, for the same reason the Sum metric does: one payment can arrive from two sources, and without pinning to one the total doubles. See Metrics. A Sum threshold may be fractional; the other metrics take whole numbers.
The window separates two different questions. "Total" is the sum across the whole period ("spent more than 10,000 this month"). "Per Day" is the best single day ("spent more than 1,000 on at least one day").
Examples:
| Segment | Metric | Counting events | Window | Threshold |
|---|---|---|---|---|
| Regulars | Unique Days | any start event | Total | >= 5 |
| Paying users | Sum ($tg.total_amount, Bot API) | successful_payment | Total | > 10000 |
| One big purchase | Sum ($tg.total_amount, Bot API) | successful_payment | Per Day | > 5000 |
Operators by data type
String
Operators:
equals— exact matchcontains— contains a substringnot equals— not equal
Examples:
| Condition | What matches |
|---|---|
props.plan equals "premium" | Only events where plan = "premium" |
props.button_name contains "buy" | button_name: "buy_now", "buy_premium", "buy_subscription" |
props.language NOT equals "en" | Every language except English |
Number
Operators:
equals(=) — equal tonot equals(!=) — not equal togreater than(>) — greater thanless than(<) — less thangreater than or equal(>=) — greater than or equal toless than or equal(<=) — less than or equal to
Examples:
| Condition | What matches |
|---|---|
props.price greater than 100 | Price above 100 |
props.quantity equals 1 | Quantity equal to 1 |
props.age greater than or equal 18 | Age 18 and older |
props.rating NOT less than 4.0 | Rating 4.0 and higher |
DateTime
Operators:
equals(=) — exact matchnot equals(!=) — not equal togreater than(>) — after the dateless than(<) — before the dategreater than or equal(>=) — from the date onwardsless than or equal(<=) — up to and including the date
Examples:
| Condition | What matches |
|---|---|
props.subscription_start greater than "2026-03-01T00:00:00Z" | Subscriptions that started after 1 March 2026 |
props.trial_ends_at less than or equal "2026-03-31T23:59:59Z" | Trials ending before the end of March |
props.last_login NOT equals "2026-03-02T10:00:00Z" | Last login at any time other than the one given |
Use the ISO 8601 format: YYYY-MM-DDTHH:mm:ssZ
Boolean
Operators:
equals— equal to (true/false)not equals— not equal to
Examples:
| Condition | What matches |
|---|---|
props.is_premium equals true | Premium users only |
props.email_verified equals false | Email not confirmed |
props.has_completed_onboarding NOT equals false | Users who completed onboarding (true or null) |
Combining conditions
AND logic
Every condition must match at the same time.
Example:
- AND
Event equals "purchase_completed"props.amount greater than 500props.currency equals "RUB"
This selects purchases above 500 roubles.
OR logic
At least one condition must match.
Example:
- OR
Event equals "purchase_completed"Event equals "subscription_renewed"Event equals "trial_started"
This selects any monetization event.
Nested logic
Combine AND with OR to express complex conditions:
Example:
- AND
- OR
Event equals "button_click"Event equals "link_click"
props.plan equals "premium"
- OR
This selects clicks made by premium users.
Negation (NOT)
Add NOT to any predicate to invert its condition:
| Condition | What matches |
|---|---|
Event NOT equals "bot_started" | Every event except bot_started |
props.plan NOT equals "free" | Paying users |
props.age NOT less than 18 | Age 18 and older — the inverse of "younger than 18" |
Filter examples
Simple filters
All purchases:
Event equals "purchase_completed"
Premium users:
props.is_premium equals true
Purchases above 1000 roubles:
- AND
Event equals "purchase_completed"props.amount greater than 1000
Complex filters
New premium users:
- AND
Event equals "subscription_started"props.plan equals "premium"props.is_trial equals false
Active users (excluding bots):
- AND
- OR
Event contains "button"Event contains "screen"Event contains "message"
props.is_bot NOT equals true
- OR
Problem transactions:
- AND
Event equals "payment_failed"props.attempt_number greater than 2props.amount greater than or equal 500
User segmentation
Young audience from Russia:
- AND
props.age less than 25props.country equals "RU"props.language equals "ru"
High-value users:
- AND
props.total_spent greater than 5000props.is_premium equals trueprops.last_activity greater than "2026-02-01T00:00:00Z"
Applying filters
Every widget has its own filters:
- "Premium purchases" widget
- Type — Series
- Metric — Events
- Filter
- AND
Event equals "purchase_completed"props.plan equals "premium"
- AND
Technical details
Compiling to SQL
Filters compile into SQL WHERE conditions.
Filter:
- AND
Event equals "purchase_completed"props.amount greater than 500
SQL (conceptually):
WHERE event_name = 'purchase_completed'
AND JSONExtractFloat(props, 'amount') > 500
You do not need to know SQL — Metriox turns your filters into optimized queries automatically.
Performance
Metriox uses ClickHouse to execute queries quickly:
- Indexing on
event_name - Efficient handling of JSON properties
- Parallel query execution
Optimization:
- Filter by event first
- Prefer
equalsovercontainswhere possible - Keep the time range narrow
Best practices
Building filters
- Start by filtering on events
- Then add property conditions
- Use NOT sparingly (it can be slower)
Testing
- Test filters on short time ranges first
- Compare the results against what you expect
- Use tables to inspect the details