Skip to content

Filters

Every metric, and searching customers, take a filter: a condition, and only the customers it matches are counted or listed.

Example: Customers in the US with an MRR above 1,000.

{
"filter": {
"all": [
{"key": "customer.country_code", "equals": "US"},
{"key": "customer.mrr", "greater_than": 1000}
]
}
}

Comparing a value

The simplest condition compares one value. It has a key, which says what to look at, and one operator, which says how to compare it.

Example: Customers in the US.

{"key": "customer.country_code", "equals": "US"}

A key starts with what it is about — customer, subscription or subscription_item — then the field: customer.status, subscription.currency_code, subscription_item.plan_id.

To use what one of your sources says about a record, put properties and the source’s slug in between: customer.properties.hubspot.industry.

List fields shows every key your project can use.

The value is read as whatever the key holds: text, a number, true or false, or a date. A date is ISO 8601 — 2026-03-01 or 2026-03-01T12:00:00Z — and is UTC unless it says otherwise. A key that does not exist, or a value that does not fit the key, is refused with an error saying why.

Equals

Matches if the field equals a specific value. Text is compared ignoring case.

Example: Customers in the US.

{"key": "customer.country_code", "equals": "US"}

Does not equal

Matches if the field is anything but a specific value, or has no value at all.

Example: Customers HubSpot does not put in finance, including those it says nothing about.

{"key": "customer.properties.hubspot.industry", "not_equals": "finance"}

Contains text

Matches if the field contains a piece of text, ignoring case.

Example: Customers with an email address at acme.com.

{"key": "customer.email", "contains": "@acme.com"}

For the opposite, wrap it in a not.

Example: Customers without an email address at acme.com.

{"not": {"key": "customer.email", "contains": "@acme.com"}}

Greater than

Matches if the field is greater than a value. For a number or a date.

Example: Customers with an MRR above 1,000, in the project’s reporting currency.

{"key": "customer.mrr", "greater_than": 1000}

Greater than or equal to

Matches if the field is greater than or equal to a value.

Example: Customers with an item of ten seats or more.

{"key": "subscription_item.quantity", "greater_than_or_equals": 10}

Less than

Matches if the field is less than a value. For a date, that means before it.

Example: Customers who first paid before 2026.

{"key": "customer.first_paying_at", "less_than": "2026-01-01"}

Less than or equal to

Matches if the field is less than or equal to a value.

Example: Customers with an ARR of 12,000 or less.

{"key": "customer.arr", "less_than_or_equals": 12000}

Has a value

Matches if the field has any value at all.

Example: Customers with an email address.

{"key": "customer.email", "present": true}

Has no value

Matches if the field is empty.

Example: Customers HubSpot has not given an industry.

{"key": "customer.properties.hubspot.industry", "present": false}

Matching every condition

all is an AND: it matches when every condition in its list matches.

Example: Paying customers in the US.

{
"all": [
{"key": "customer.status", "equals": "paying"},
{"key": "customer.country_code", "equals": "US"}
]
}

Matching any condition

any is an OR: it matches when at least one condition in its list matches.

Example: Customers in the US or Denmark.

{
"any": [
{"key": "customer.country_code", "equals": "US"},
{"key": "customer.country_code", "equals": "DK"}
]
}

Excluding a condition

not is a NOT: it matches when the condition inside it does not.

Example: Customers outside the US and Denmark.

{
"not": {
"any": [
{"key": "customer.country_code", "equals": "US"},
{"key": "customer.country_code", "equals": "DK"}
]
}
}

Nesting conditions

all, any and not can contain any condition, each other included.

Example: Paying customers in the US or Denmark, except those at acme.com.

{
"all": [
{"key": "customer.status", "equals": "paying"},
{
"any": [
{"key": "customer.country_code", "equals": "US"},
{"key": "customer.country_code", "equals": "DK"}
]
},
{"not": {"key": "customer.email", "contains": "@acme.com"}}
]
}

A filter is at most four levels deep, with at most twenty-five comparisons.

Subscriptions and items

A filter is about customers, and a customer can have several subscriptions. Take two customers:

  • Customer1 has one subscription, active and in euros.
  • Customer2 has two: one active and in dollars, and one canceled and in euros.

A condition about a subscription matches a customer who has a subscription that matches it, and each condition is checked on its own. So the filter below matches both customers: Customer1’s subscription is active and in euros, and Customer2 has an active subscription and a subscription in euros, though not the same one.

Example: Customers with an active subscription, and a subscription in euros. Matches Customer1 and Customer2.

{
"all": [
{"key": "subscription.status", "equals": "active"},
{"key": "subscription.currency_code", "equals": "EUR"}
]
}

To ask for one subscription that is both, put the conditions in a has_subscription. Everything inside it is about the same subscription.

Example: Customers with an active subscription in euros. Matches Customer1 alone.

{
"has_subscription": {
"all": [
{"key": "subscription.status", "equals": "active"},
{"key": "subscription.currency_code", "equals": "EUR"}
]
}
}

has_subscription_item does the same for an item. Inside a has_subscription it is an item of that subscription; on its own, an item of any subscription.

Example: Customers with an active subscription that has an item of ten seats or more on the Pro plan.

{
"has_subscription": {
"all": [
{"key": "subscription.status", "equals": "active"},
{
"has_subscription_item": {
"all": [
{"key": "subscription_item.plan_id", "equals": "stripe:prod_pro"},
{"key": "subscription_item.quantity", "greater_than_or_equals": 10}
]
}
}
]
}
}

Example: Customers with no active subscription in euros. Matches Customer2.

{
"not": {
"has_subscription": {
"all": [
{"key": "subscription.status", "equals": "active"},
{"key": "subscription.currency_code", "equals": "EUR"}
]
}
}
}

A filter contains at most five of them, counting each condition about a subscription or an item outside one as one of its own.

In a metric

A metric adds up revenue. There, a condition about a subscription or an item outside a has_subscription narrows the revenue counted to the subscriptions or items it matches.

Example: The MRR of subscriptions in euros alone.

{
"measure": "mrr",
"filter": {"key": "subscription.currency_code", "equals": "EUR"}
}

Inside a has_subscription, it asks about the customer instead, and counts all of their revenue once they have such a subscription.

Example: The whole MRR of customers who have a subscription in euros.

{
"measure": "mrr",
"filter": {
"has_subscription": {"key": "subscription.currency_code", "equals": "EUR"}
}
}

A metric that counts customers, such as paying_customers, has no subscription of its own to narrow to, and takes a condition about a subscription or an item only inside a has_subscription.

When a value is read

A value can change: a customer moves country, a subscription is canceled. A comparison reads the value at one moment, and its at says which:

at Reads the value
"now" as it is today. What a customer search reads when at is left out.
A date or a date and time as it was then. A date means the end of that day, in the project’s reporting timezone.
"window" as it was in each period: at its end for a figure like MRR, and when the money moved for a movement. Metrics only, and what a metric reads when at is left out.

Example: Customers who were paying on March 1, 2026, whatever they are today.

{"key": "customer.status", "equals": "paying", "at": "2026-03-01"}

In a metric, leaving at out reads each period as it was. Say a customer moved from Denmark to the US in June. This counts their MRR as American from June on, and as Danish before.

Example: MRR per month of customers in the US, as they were each month.

{
"measure": "mrr",
"from": "2026-01-01",
"to": "2026-12-31",
"interval": "month",
"filter": {"key": "customer.country_code", "equals": "US"}
}

With "at": "now", every month reads the value as it is today instead, so the same customer counts as American in every month of the year.

Example: MRR per month of the customers who are in the US today.

{
"measure": "mrr",
"from": "2026-01-01",
"to": "2026-12-31",
"interval": "month",
"filter": {"key": "customer.country_code", "equals": "US", "at": "now"}
}