Report Builder
Pick the columns, set the filters, choose how each measure is aggregated, and run it against your own data. No SQL, and no export-and-pivot round trip.
What this feature does
A report in Routy is a named set of columns you pick from and run. You choose the columns, apply at least one filter, decide how each measure is aggregated, set the sort, and the rows come back in the app or as a file you download.
Every report's columns are read from the data behind it, and each column carries metadata that decides what you can do with it: its data type, whether it can be sorted, whether it can be filtered, whether a filter on it is required, and which aggregations it accepts. The builder offers you only what each column supports, so a report you are allowed to assemble is a report that will return rows.
Columns come in two kinds. A dimension groups the result: country, account, day, traffic source. A fact is a measure that gets aggregated across the rows sharing those dimension values: clicks, revenue, commission. Put country and revenue in a report and you get revenue per country. Facts sum unless you say otherwise.
What you'll get out of it
- Five aggregations per fact column, chosen per column and per run: Sum, Avg, Min, Max and Count. Each column declares which of them it accepts, and asking for one it doesn't accept returns a 400 naming the column and the allowed set. Omit the choice and a fact sums, which is what it did before this existed.
- Twelve filter operators: Equals, NotEquals, GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual, Between, In, NotIn, Contains, StartsWith and EndsWith. Which ones a column offers follows its data type, so a boolean takes Equals and NotEquals and nothing else, and a date takes the comparisons and Between but not Contains.
- Presets that Routy ships ready to run, including unified Events, Pages and Tracker reports. They are read-only to you. Editing one copies it: the copy is yours to change and the original stays as it was. Your own presets are either private to you or shared with everyone on your affiliate.
- A date window that moves with you. A preset's dates are stored as relative tokens like
now-30d, re-resolved every time the report runs, so a preset saved in March still means the last 30 days in October. - Date and date-time columns handled in your time zone. A Date column resolves against your local calendar day, taken from the time zone on your session, so "today" for a user in Asia/Jerusalem is the Jerusalem day and not the UTC one.
- Reports that take named inputs, not just filters. The live cases are a target currency, which converts the report's money columns at each month's rate, and a breakdown dimension baked into the source. A parameter changes what the report computes before any filtering, so it can't be expressed as a filter.
- Device type, device brand and model, browser and operating system on your clicks and page views, worked out from the user agent and from the browser's client hints where it sends them. Device type is one of desktop, mobile, tablet, tv, console, wearable or other.
- Deposits, chargebacks, withdrawals, downloads and earnings filled in on the day, account and account-by-day summary reports, alongside estimated commission split by CPA, RevShare, CPL and CPC and shown separately from the commission the network itself reported.
- Export to CSV or Excel, up to 100,000 rows, using the same rows and the same parameter values that were on screen. Totals are left off the exported file.
- The same reports from an MCP client, through three tools:
list_reports,describe_reportandrun_report.run_reporttakes the same columns, aggregations, filters, sorting and parameters as the app, and returns up to 500 rows per call.
Two things the builder does not do. Reports can't be scheduled or emailed on a cadence yet; the design exists and nothing is built, so a recurring report is still someone opening it. And there's no drill-down from an aggregated row to the events behind it. The closest thing is raw mode, which turns aggregation off entirely and returns the rows as they are.
How it actually works
Running one
Open Reports, pick a report, choose your columns, and add your filters. At least one filter is required and the request is refused without one, because a report with no filter is a full scan of the source. Any column marked as requiring a filter has to carry one too, and leaving it out returns a 400 that names the column you missed. The builder pre-fills those from the column's own default, so this is usually invisible.
A run is a row range rather than a page number: you send an offset and a limit, up to 1,000 rows in one request. Routy decides how to serve that range by how many rows the report produces, keeps a cached result for up to five minutes, and gives a query 120 seconds before it gives up.
Each report also returns the limits that apply to it. The defaults are 50 columns in total, of which up to 20 can be facts, 10 grouping dimensions, 50 filter conditions and 5 sort columns. They can be raised or lowered for one report or for one account, and the report tells you which of the three it resolved from, so the app can stop you at the boundary instead of letting the server reject the run.
Presets, and who sees what
A preset stores columns, filters and sorting under a name. Routy's own presets carry a scope of system and show up for every account as a baseline. Yours carry user if they're private or affiliate if you shared them, and that is the whole sharing model: you, or everyone on your affiliate. There is no per-teammate report sharing and no admin-only preset.
Routy can also delist a preset without deleting it, so a baseline we stop recommending disappears from the list while every copy anyone made of it carries on working.
Two of these are set by Routy rather than by you. A report can be kept out of the main report list, which is how reports that exist only to feed a dashboard tile stop cluttering the menu. And the list comes back in a fixed order rather than whatever the database returned, so the report you open every morning isn't below the one you open twice a year. Neither is a permission: a delisted report still runs, and every dashboard, preset and link pointing at it is unaffected.
Parameters, and why one of them isn't yours
A report declares which inputs it takes and where each one comes from. The ones marked as client-supplied are yours: a currency picker, a breakdown. The ones marked as server-supplied are filled in from your signed-in session, which is usually the affiliate the report is scoped to, and anything you send for one of those is ignored. That is the mechanism that stops a report being pointed at another account's data, so it is deliberately not a field on the form.
Where the numbers come from
A report reads from a named view on a connection. Clicks, page views and conversions can be served from either Postgres or ClickHouse, and which one answers your request is config, resolved per report family and per account, with no deploy needed to switch or to switch back. The rows are the same either way.
When the data behind a report moves, the report moves with it and keeps its name, its URL, who can see it, its limits and every column rename an admin set on it. A move is checked against the new source first, and refused if a column the report currently returns isn't there, so a field can't disappear from the response of something you built a dashboard on. There is a dry run for checking a target without moving anything.
What it won't give you
Clicks, page views and conversions reports won't accept a start date more than three months old. Ask for one and you get a 400 reading "From date cannot be older than 3 months", with the oldest allowed date in the response. Older ranges come out of the export system, which takes a start date up to 120 days back, and anything past that sits in the archive and is retrieved for you rather than queried from the report.
The summary reports carry no page-view measure, so views come back as zero there. Clicks, conversions and the money columns are populated; page views are their own report.
Why this is worth doing
The questions you act on cut across what a fixed dashboard keeps on separate screens. Which traffic source produced the conversions that approved, in the markets where you're running native, last month. Answering that without a report builder means exporting two or three files, lining them up in a spreadsheet, and getting a number that was true on the morning you pulled it. The same question as a report is columns, filters and a run, and it returns current rows every time someone opens it.
The honest comparison is with the two things people use instead. A spreadsheet is faster than anything for the first report and becomes the thing nobody wants to inherit by the fiftieth, because the logic lives in cells and only one person remembers it. A warehouse will answer more than this will, and it wants either an analyst or a serious week from you, and a pipeline that keeps the tables fed. The builder sits between them: more flexible than a fixed dashboard, narrower than SQL, and bounded on purpose at 50 columns and one required filter so a run can't take the source down.
The team this changes most is a small one with no analyst. There, the thing standing between a question and its answer is whoever has to write the query, and a report anyone on the account can assemble removes that step.
Frequently asked questions
Do I need to know SQL?
No. Columns, filters, aggregations, sorting and parameters are all selected from the report's own metadata. SQL is what the server builds from your selections.
How many columns can one report have?
Fifty by default, of which up to 20 can be fact columns, with 10 grouping dimensions. The caps can be raised or lowered for a single report or a single account, and every report returns the limits that apply to it.
Can I export a report, and in what format?
Yes, to CSV or Excel, up to 100,000 rows. The export uses the same rows and the same parameter values the report ran with. Fact totals are left off the file.
Can reports be emailed on a schedule?
Not yet. A scheduled run delivered by email and Slack is designed and not built, so today a recurring report means someone opening it or calling it from the API.
Can I share a report with my team?
Yes. A preset is either private to you or shared with everyone on your affiliate. There is no sharing with named individuals, and no admin-only preset.
Why won't a report run without a filter?
Because the alternative is reading the whole source. The server refuses the request and asks for at least one filter. Any column flagged as requiring a filter needs one too, and the error names the column that's missing.
How far back can a clicks or page-view report go?
Three months. A start date older than that is rejected, and the response carries the oldest date the report will take. Beyond three months the data comes from an export, which reaches back 120 days, or from the archive.
Can I run these reports from my own tools?
Yes, over the API, and from an MCP client using list_reports, describe_report and run_report. The MCP path takes the same columns, aggregations, filters and parameters and returns up to 500 rows per call.
Ready to try Report Builder?
Open Reports and run one of the presets Routy ships, then change its columns and save your own copy. Pick the date range from the picker; it overrides whatever window the preset came with.