Contents
- Getting started
- Conditions (WHERE)
- Values, people and saved filters
- Dates and periods
- History (WAS / CHANGED)
- Grouping (GROUP BY)
- Columns and metrics (SHOW)
- Sorting and limits (ORDER BY, LIMIT)
- Combining queries (COMBINE, CALC)
- Clickable numbers (DRILL)
- Team scorecard (FROM team)
- Asking the AI
- Limits and safety
- Data reference
- Functions and operators
- More examples
Getting started
Every report is one query. It starts with FROM and the thing you count, then optional clauses in any order. Keywords are not case-sensitive. A query returns one of three shapes: a list of records, one summary row, or a row per group.FROM <entity> WHERE … GROUP BY … SHOW … ORDER BY … LIMIT n— The full shape. Only FROM is required.
Conditions (WHERE)
WHERE keeps only the records that match. Join conditions with AND, OR and NOT, and use brackets to group them. Filtering on an indexed field (marked in the data reference) is fastest.source = facebook— Equals. Also != > >= < <=.governorate IN (Cairo, Giza) · stage.name NOT IN ("Lost")— One of a list, or none of it.customer ~ "ahmed" · name ~ "test*" · name !~ "demo"— Contains (not case-sensitive). * and ? are wildcards; !~ means does not contain.owner IS EMPTY · ad IS NOT EMPTY— Has no value / has a value.tags ANY ("vip", "wholesale") · tags ALL ("vip", "repeat")— List fields: has at least one of / has all of.text ~ "acme"— Searches the main text fields of the entity at once (names, phone, company …).(source = facebook OR source = instagram) AND NOT cod = true— Brackets and NOT. Note: != and NOT IN skip empty values — add “OR field IS EMPTY” to keep them.
Values, people and saved filters
Write text in “double quotes” when it has spaces; single words and list values (won, pending, whatsapp) can be bare. Numbers and true / false are written as they are.stage.name = "Follow up" · value > 5000 · cod = true— Text, number and yes/no values.owner = currentUser()— You — whoever runs the report.owner = "sara@company.com" · owner IN membersOf("Sales")— A teammate by email, or everyone in a team.filter = "VIP leads"— Reuses the WHERE of a saved report on the same entity (up to 3 levels deep).
Dates and periods
Dates use your company’s time zone. Use a relative amount, a calendar date, or a function. Big tables (orders, messages, chats …) look at a recent window when the query has no date condition — the result says which window was used.created >= -30d · -12h · -2w · -3M · -1y · "-4w 2d"— Relative: m minutes, h hours, d days, w weeks, M months, y years.created >= "2026-03-01" AND created < "2026-04-01 00:00"— Calendar dates: yyyy-MM-dd or yyyy/MM/dd, optionally with HH:mm.created >= today() · created = yesterday()— Today and yesterday; now() is this moment.created >= startOfMonth()— This month. Also startOfDay, startOfWeek, startOfQuarter, startOfYear and the endOf… versions.created >= startOfMonth(-1) AND created < startOfMonth()— Last month: the number moves by whole periods (-1 = previous).
History (WAS / CHANGED)
On leads you can ask about the past, not only the current value: which deals were ever in a stage, or who moved them. The fields with history are listed in the data reference.Grouping (GROUP BY)
GROUP BY makes one row per value, up to 3 keys. Group a date by a period to get a timeline, or by hour of day / weekday to find patterns. Records with no value form their own “(none)” row.GROUP BY owner.name · GROUP BY channel.type, source— By a field, or by two.
GROUP BY channel.type AS channel— Rename a group column — needed to COMBINE two queries.
Columns and metrics (SHOW)
SHOW picks what appears: fields for a list, or metrics (up to 10) for a summary or groups. Every entity has ready-made metrics (revenue(), winRate() …) listed in the data reference; the general ones below work on any number field.count() · count(phone) · countDistinct(customer)— Rows, rows with a value, distinct values.sum(total) · avg(total) · min(total) · max(total)— Totals and averages of a number field.median(total) · p90(daysToWin)— The typical value, and the value 90% stay under.rate(cod = true)— Share of rows matching a condition, as a percentage.
Sorting and limits (ORDER BY, LIMIT)
ORDER BY sorts by a column name, a metric or its AS name. A list shows 100 rows unless you say otherwise, up to 1000; exports take up to 5000.Combining queries (COMBINE, CALC)
COMBINE puts numbers from different entities side by side — orders next to chats, spend next to revenue. Write up to 4 grouped queries, give the shared key the same AS name in each, and join them with COMBINE BY that name. Each part keeps its own WHERE, so repeat the date range. Every metric needs its own AS name. CALC adds up to 10 calculated columns (+ − × ÷, brackets, ROUND); dividing by zero leaves the cell empty. ORDER BY and LIMIT go at the very end.Clickable numbers (DRILL)
End a query with DRILL and every number in the result opens the records behind it, 50 to a page, newest first, with Open chat and Open lead links. DRILL SHOW picks the columns of that list. In a COMBINE, one DRILL at the end works for every part. Leave it out when the numbers should stay plain.Team scorecard (FROM team)
FROM team gives one row per teammate with numbers gathered from several tables — messages, chats, deals, orders, calls. Set the period with WHERE period; no GROUP BY is needed (GROUP BY team.name rolls members up into teams).Asking the AI
In Ask AI, describe the report in your own words (English or Arabic) and the AI writes the query, checks that it runs, and fixes it if not. Once a query is on screen, type a change instead — “add revenue”, “only COD”, “split by month”, “compare with last month” — and only that part changes. Undo keeps your last versions. The ✨ button next to the editor does the same for a query you wrote.Limits and safety
Reports can never slow down the CRM: each query is checked before it runs and refused if it would read too much — narrow the dates or filter on an indexed field. A run stops after 15 seconds. Each person can run 30 reports a minute. Results are cached for about a minute. You only ever see the records your role lets you see, and phone numbers stay masked for roles that cannot see them.GROUP BY ≤ 3 keys · ≤ 10 metrics · ≤ 30 conditions · LIMIT ≤ 1000 · ≤ 1000 groups · 4000 characters— Size limits per query.
Data reference
What each entity counts, its fields (for WHERE, GROUP BY and SHOW) and its ready-made metrics. Group = can be used in GROUP BY. Fast = indexed, fastest to filter on. Phone and email fields are masked for roles without access to phone numbers and cannot be filtered on.Leads / deals — FROM leads
- Date field:
created. - History (WAS / CHANGED) on:
stage,owner,value,priority,source,probability,currency,customerType. text ~ "…"searches:name,email,company,phone.
Store orders — FROM orders
- Date field:
created. - Without a date condition it looks at the last 90 days.
text ~ "…"searches:number,customer,email,phone.
Products sold (order lines) — FROM products
- Date field:
created. - Without a date condition it looks at the last 90 days.
text ~ "…"searches:name,sku.
Conversations (chats) — FROM conversations
- Date field:
created. - Without a date condition it looks at the last 90 days.
text ~ "…"searches:name,phone.
Chat messages — FROM messages
- Date field:
created. - Without a date condition it looks at the last 30 days.
Customers — FROM customers
- Date field:
created. text ~ "…"searches:name,company,email,phone.
Tasks — FROM tasks
- Date field:
created. text ~ "…"searches:title.
Phone calls — FROM calls
- Date field:
created. - Without a date condition it looks at the last 90 days.
text ~ "…"searches:phone,disposition.
Broadcasts — FROM broadcasts
- Date field:
created. text ~ "…"searches:name,template.
Ad spend (Meta ads, per ad per day) — FROM ads
- Date field:
date. - Without a date condition it looks at the last 90 days.
- Needs the
analytics:readpermission as well. text ~ "…"searches:ad.name,campaign.name.
Team (per teammate) — FROM team
- One row per teammate. The report period is
period(WHERE only). - Without a date condition it looks at the last 30 days.
text ~ "…"searches:name.
Functions and operators
- Aggregates:
count(),countDistinct(),sum(),avg(),min(),max(),median(),p90(),rate() - Date buckets (GROUP BY):
hour(field),day(field),week(field),month(field),quarter(field),year(field),hourOfDay(field),weekday(field) - Values:
now(),today(),yesterday(),startOfDay(),startOfWeek(),startOfMonth(),startOfQuarter(),startOfYear(),endOfDay(),endOfWeek(),endOfMonth(),endOfQuarter(),endOfYear(),currentUser(),membersOf() - Relative dates:
-30m,-12h,-7d,-2w,-3M,-1y,"-4w 2d" - Date formats:
yyyy/MM/dd,yyyy-MM-dd,yyyy-MM-dd HH:mm,ISO 8601 with zone - Operators:
=,!=,>,>=,<,<=,~,!~,IN,NOT IN,ANY,ALL,IS EMPTY,IS NOT EMPTY - COMBINE: up to 4 queries, up to 10 CALC columns
- DRILL: the records behind a number, 50 to a page, with Open chat / Open lead links

