Metrics
Every number on a Tempio surface comes from one table of daily counts, and every rate comes from arithmetic done at the moment you look. Nothing that can be computed is stored, and nothing that is stored is a rate.
What is stored
One row per entity per day. The grain is the workspace, the connection, the platform, the ad account, the entity level, the entity, the date and the breakdown — so a campaign's Tuesday is exactly one row, and a re-sync of Tuesday rewrites that row rather than adding a second one.
| Column | What it is |
|---|---|
spend | Integer minor units of the account's currency |
impressions | A count |
reach | People reached, as the platform reported them for that day — or empty where the platform does not report it |
clicks | A count |
conversions | A count, which platforms can report fractionally |
conversionValue | Integer minor units of the account's currency |
currency | The account's own code, stamped on the row |
That is the whole of it. There is no stored CTR, no stored ROAS, no stored blended anything.
Reach is the one column that is not a plain count. Platforms report it de-duplicated: one person who saw an ad on Monday and again on Tuesday is one person across the week and two daily rows. Anything adding reach up over a range is adding daily reach, and every surface that shows it says so. Where a platform does not report reach at all the column is empty rather than zero — "did not report" and "reached nobody" are different facts and are shown differently.
What is computed
Five ratios, worked out when a page is drawn or a tool answers.
| Ratio | How |
|---|---|
| CTR | clicks ÷ impressions |
| CPC | spend ÷ clicks |
| CPM | (spend ÷ impressions) × 1000 |
| CPA | spend ÷ conversions |
| ROAS | conversion value ÷ spend |
The same function computes them everywhere — the dashboard tile, the campaign table, the account brief and the MCP result all divide the same way, so they cannot disagree about what CPA means.
A zero denominator gives no answer, not a zero. An account with no
conversions yet has no cost per conversion; the value is null, and it renders as
—. This is the rule most worth knowing about, because a zero would say
something false and cheerful: that conversions were free. An agent reading a
Tempio result is told the same thing — a null ratio is undefined, never nought.
Storing ratios would let them drift from the counts beneath them, which is why they are not stored. Recomputing them costs nothing next to a page's other work.
Money
Money is an integer in the ad account's own minor units, with the currency stamped beside it. Never a float, never a fraction of a cent, never a number whose denomination you have to infer.
How many minor units make a major one is the currency's business, not a universal hundred:
| Currency group | Minor units per major |
|---|---|
| Yen, won, and the other zero-decimal codes | 1 — ¥1,500 is 1500 |
| Most currencies | 100 — $15.00 is 1500 |
| Dinars and other three-decimal codes | 1000 — KD 1.234 is 1234 |
An unfamiliar code is treated as two decimals, which is both the majority and the least damaging way to be wrong. Every form on the ads surface parses a typed amount against the currency of the account that owns the row it is editing — never against a currency the form supplied — and every draft payload is stamped with that account's code on the way in.
Several currencies at once
A dashboard covering a US account and a Japanese one has a problem no rounding solves: minor units are not comparable across currencies. ¥1,500,000 has more digits than $12,000 and is less money.
Tempio handles that in one direction only — it says so.
- One currency in scope. Nothing is converted. The answer is exact and the figure is stated in that currency.
- Several. The totals are converted through published rates into whichever currency carries the most spend, compared honestly rather than by digit count, and the result is labelled an estimate with the date of the oldest rate the conversion leaned on. A stale leg cannot hide behind a fresh one.
- Several, and a rate is missing. Nothing is invented. A blended total that cannot be reached is refused rather than estimated, and a list that cannot be ranked comparably is returned in its raw order with that fact attached — a raw order across currencies is not a ranking, and every surface showing one says so.
Two windows compared against each other are pinned to the same currency, so a period-over-period change is never one currency divided by another.
Rates feed a labelled estimate and nothing else. No guardrail converts, no budget converts, and no cap is compared across currencies.
Where the numbers come from
Each sync pulls the days the platform is still willing to restate — 28 on Meta, 30 on Google, 14 on TikTok — so late conversions and platform corrections land as corrections rather than as gaps. Once a week the full ninety days are re-read. A sync that rewrites a large amount of already-stored history marks the connection restated, which is worth knowing before you conclude last month moved on its own. Connections has the sync behaviour.
Today is always partly filled in. A range ending today is reporting a day the platform has not finished counting, which is why comparisons default to complete days and why a tool result states the range it actually covers.
Reading them elsewhere
The dashboard shows the workspace blended; Campaigns shows
them per campaign, ad group and ad; the account brief summarises ninety days per
account. Over MCP, get_metrics and get_campaign_metrics answer the same
numbers, and every result carries a report block stating the currency the
answer is in — null when the scope spans currencies — the timezone the dates
are in, the range, the entity level, and whether the scope is the rows returned
or all of them. Read that block before comparing two results: two answers in two
currencies are not two numbers you may subtract.