Skip to main content

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:

  1. Type — an event, a property, or a user
  2. Operator — the comparison operation
  3. Value — what you compare against
  4. 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.

The Metriox Events page: section navigation on the left, the bot picker and the "Last 7 days" range on top, and the filter builder holding a single predicate (NOT / User ID / equals / 160266) with a "1 condition" badge and the "Add filter type" menu offering Event, Property, and User

Event predicates

Filtering by event name:

Event [NOT] equals "button_click"
Event [NOT] contains "purchase"

Operators for events:

  • equals — exact match
  • contains — contains a substring

Examples:

ConditionWhat 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:

PartWhat it setsExample
Metricwhat to measure per userEvent Count, Unique Days, Unique Events, Sum
Counting eventswhich events to count (required)successful_payment
Windowmeasure over the whole period, or per dayTotal / Per Day
Thresholdoperator 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:

SegmentMetricCounting eventsWindowThreshold
RegularsUnique Daysany start eventTotal>= 5
Paying usersSum ($tg.total_amount, Bot API)successful_paymentTotal> 10000
One big purchaseSum ($tg.total_amount, Bot API)successful_paymentPer Day> 5000

Operators by data type

String

Operators:

  • equals — exact match
  • contains — contains a substring
  • not equals — not equal

Examples:

ConditionWhat 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 to
  • not equals (!=) — not equal to
  • greater than (>) — greater than
  • less than (<) — less than
  • greater than or equal (>=) — greater than or equal to
  • less than or equal (<=) — less than or equal to

Examples:

ConditionWhat matches
props.price greater than 100Price above 100
props.quantity equals 1Quantity equal to 1
props.age greater than or equal 18Age 18 and older
props.rating NOT less than 4.0Rating 4.0 and higher

DateTime

Operators:

  • equals (=) — exact match
  • not equals (!=) — not equal to
  • greater than (>) — after the date
  • less than (<) — before the date
  • greater than or equal (>=) — from the date onwards
  • less than or equal (<=) — up to and including the date

Examples:

ConditionWhat 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
Date format

Use the ISO 8601 format: YYYY-MM-DDTHH:mm:ssZ


Boolean

Operators:

  • equals — equal to (true/false)
  • not equals — not equal to

Examples:

ConditionWhat matches
props.is_premium equals truePremium users only
props.email_verified equals falseEmail not confirmed
props.has_completed_onboarding NOT equals falseUsers 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 500
    • props.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"

This selects clicks made by premium users.


Negation (NOT)

Add NOT to any predicate to invert its condition:

ConditionWhat matches
Event NOT equals "bot_started"Every event except bot_started
props.plan NOT equals "free"Paying users
props.age NOT less than 18Age 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

Problem transactions:

  • AND
    • Event equals "payment_failed"
    • props.attempt_number greater than 2
    • props.amount greater than or equal 500

User segmentation

Young audience from Russia:

  • AND
    • props.age less than 25
    • props.country equals "RU"
    • props.language equals "ru"

High-value users:

  • AND
    • props.total_spent greater than 5000
    • props.is_premium equals true
    • props.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"

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
Note

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 equals over contains where 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

What's next?

  • Metrics — see which metrics you can count with filters
  • Widgets — apply filters inside widgets
  • Events — the structure of events and properties