Reporting
Reporting is the readout for campaigns the agency built on the platform from your handoff. You register each live campaign here by its platform id, and Klyo pulls a small KPI set for it every night, so you can read performance without leaving the app.
What works today
Registering a campaign to track and reading its last pull work end to end. DV360 campaigns pull through a DV360 connection. Google Ads campaigns register the same way but pull nothing until Google Ads reporting access clears (see Platforms). The nightly pull ships switched off by default and is not yet enabled, so Measurement reads "not switched on yet" until an admin turns it on. Past performance imports work independently of that switch, since the file is the source rather than the pull.
Tracked Campaigns
A Tracked Campaign is one campaign that already runs on a channel, pointed at from Klyo so its numbers come home. Klyo does not build or change it: the agency sets it up from your handoff, and you paste its id here to watch it.
Track one from the Reporting page with four fields:
- Platform: DV360 or Google Ads.
- Connection: the account the pull reads through. It authenticates with that connection's own credential, so the connection has to reach the campaign.
- Campaign id: the platform's own id for the campaign, the one the agency gives you.
- Label: a name you will recognise in the list.
Tracking, renaming, and stopping tracking need the user or admin role. Stopping tracking only removes the row from your list; the campaign keeps running on the channel.
What each row shows
Each row carries the campaign's platform and id, the connection it pulls through, when it last ran, and the KPIs the last pull returned: impressions, views, clicks, and spend when the campaign spent (a views-only channel reports none). The numbers are a readout, not a live dashboard: they are whatever the most recent pull banked, and the caption under the label states the exact trailing window and the day it ran, so a stale figure reads as stale.
A row shows Not pulled yet until the first nightly run reaches it. Disconnected means the connection the row pulled through is gone; re-track the campaign against a live connection to resume.
Platforms
- DV360 pulls today, through a DV360 connection. The pull runs as that connection's account, so an older connection may need to sign in again before it can read the campaign.
- Google Ads registers now but pulls nothing until Klyo's Google Ads developer-token review clears. Adding the campaign early is fine; the nightly pull fills it in once access opens.
Connect a channel once per Organization on the Organization page's Connections tab. See Channel connections.
Measurement
Measurement is the other half of reporting: results for the creatives Klyo itself activated, pulled from each channel once a day and joined back to the combination that earned them. Tracked Campaigns cover campaigns someone else built; Measurement covers the ones that left Klyo.
It shows in two places, both reading the same numbers:
- The Dashboard Overview tab, across every campaign in the Organization.
- The campaign builder's Monitoring step, for that one campaign. The step opens once a creative has been activated, since nothing serves before that.
Pick a window (7, 28, or 90 days) in the header. 28 rather than 30 because a whole number of weeks removes the day-of-week swing from the comparison. The line under the title states the window and the last day the numbers run to.
The numbers
Five metrics come off the channels: impressions, views, clicks, spend, and conversions. Four rates are derived from them:
| Rate | What it is |
|---|---|
| CTR | Clicks divided by impressions |
| CPM | Spend per thousand impressions |
| CPV | Spend per view |
| CPA | Spend per conversion |
A rate whose denominator is zero does not exist, so Klyo leaves it out instead of printing a zero that would read as a measured result.
There is no ROAS and no conversion value. The channels report a conversion count, not what it was worth, so revenue is simply not in the data. CPA is the closest honest answer to "what did this cost me".
Spend carries no currency symbol. Each channel reports it in its ad account's own currency, and Klyo does not convert, so a total across accounts billing in different currencies is a sum of unlike numbers. Read spend per account.
Reading the tables
- By channel splits the window per network. A creative pushed to more than one network appears in each of their rows, so the channel rows add up to the totals above only when every creative ran on a single network.
- Top creatives ranks the 25 creatives with the most impressions, one row per combination. Clicking a column re-ranks those 25; it does not pull in a creative from outside them. A creative that has since left the matrix keeps its numbers and has no link to open.
- By catalogue item (Monitoring step only) rolls a campaign's numbers up to the catalogue items its creatives carry.
The catalogue item roll-up is directional
An item's row is the sum of every combination it appeared in, so one impression counts once for each item in that combination. The sums therefore exceed the campaign total, by design.
More importantly, the platform decides which combinations get shown. An item can look strong because it ran alongside strong items, or because delivery favoured its combinations, and not because of the item itself. Read the roll-up as a direction worth testing, not as a result. To settle it, run a real test: hold an item out, rotate combinations evenly, or use the platform's own experiment tools.
Peak combinations on each row is the most combinations that item was seen in on a single day of the window, not a total across days. It is there so you can discount a row: an item that ran in two combinations and one that ran in forty are not comparable.
When the view is empty
The panel says which kind of empty it is, because each one needs a different next step:
- Nothing is running yet. No creative has been activated. Approve a final video, push it from the activation queue, and its numbers arrive the next day.
- No results have arrived yet. Something is running and the daily pull has not landed its numbers. A creative you handed off for someone else to run reports under Tracked Campaigns instead.
- Measurement is not switched on yet. The daily pull has not been enabled for this environment. It is switched on during deployment rather than from the app, and results appear from the first run after that.
Past performance
The daily pull only knows what Klyo pushed or tracks, so your numbers from before Klyo arrived have to be brought in. Past performance takes a campaign report you exported from Google Ads or DV360 as a CSV or Excel file and loads it into the same warehouse the pull writes to, so old and new numbers sit side by side.
Importing takes two steps. You pick the file and say which of its columns hold the day, the campaign, and each metric; Klyo then shows a preview of what it read before anything is written, and you confirm. Two rules are worth knowing up front:
- A line with no campaign id or no day is treated as the report's own total or footer and skipped. A line that has both and still will not parse stops the whole import, naming the line, the column, and the cell, rather than loading a guess.
- Dates written
03/07/2026are refused, because that is March 7th in one country and July 3rd in another and a wrong day is a wrong benchmark. Use a format that states the year first, or the month by name.
Re-importing the same days for the same campaign replaces those rows rather than doubling them, so a corrected export is just another import. A campaign the new file does not mention keeps the history it already had.
Every imported row is campaign-level. The export knows which campaign spent on which day and nothing about which creative earned it, so these numbers stay out of the per-creative and per-catalogue-item tables above. The register on the page is read straight from the warehouse, so it always shows what is actually loaded.
Importing needs the user or admin role. Any member can read the register.
Bringing data in from BigQuery
If your history already sits in BigQuery, reshape it there first and upload the result. The import wants one row per campaign per day, so a query that collapses timestamps to days, sums the metric columns into the names the importer uses, and picks up the external campaign id from your mapping table gives you a file you can upload without editing it afterwards.
SELECT
DATE(f.event_timestamp) AS day,
m.external_campaign_id AS campaign_id,
m.campaign_name AS campaign_name,
SUM(f.impressions) AS impressions,
SUM(f.clicks) AS clicks,
SUM(f.video_views) AS views,
SUM(f.cost_micros) / 1000000 AS spend,
SUM(f.conversions) AS conversions,
SUM(f.conversion_value) AS revenue
FROM `my-project.marketing.campaign_export` AS f
JOIN `my-project.marketing.campaign_mapping` AS m
ON m.warehouse_campaign_key = f.campaign_key
WHERE DATE(f.event_timestamp) BETWEEN '2025-01-01' AND '2025-12-31'
GROUP BY day, campaign_id, campaign_name
ORDER BY daySave the result as CSV, then upload it in Past performance like any other export. The column picker recognises these names on sight, apart from revenue, which you point at once because exports label that column in several ways. Two things to watch: spend has to be a plain number, which is why the micros are divided out, and the day has to read year first, which is what DATE() already writes. A metric your warehouse does not carry can be left out of the query and imports as zero.
Klyo does not read your warehouse for this import. The file upload is the path, and the same replace-by-day rule applies, so you can rerun the query for a corrected window and upload it again.

