Blog · KPIs & reporting

Marketing KPI dashboard: define the metrics once, then stop rebuilding

Published August 10, 2026 · 9 min read

Almost nobody's marketing KPI dashboard fails because the charts were ugly. It fails because two people looked at "conversions" and meant two different things, or because the tab that fed it stopped being updated in March and nobody noticed until a decision got made on a stale number. The charting is the easy 10%. The other 90% is settling what each KPI means, wiring it to sources that keep themselves current, and making the thing readable without a briefing.

This guide is the version that survives: which KPIs earn a slot, how to define them so they hold across four platforms, and how to end up with a live URL instead of a file that needs a maintainer.

Why most KPI dashboards go stale in three weeks

Watch the lifecycle of a typical one. Someone builds it in a spreadsheet or a BI tool in a burst of Q1 enthusiasm. It looks great for a fortnight. Then:

  • A source drifts. An ad account gets renamed, a campaign naming convention changes, someone adds a fifth channel. The dashboard doesn't break loudly — it just quietly under-reports, which is worse.
  • The refresh becomes a chore. If a human has to export four CSVs on Monday morning, the dashboard has a staffing dependency. Staffing dependencies lose to busy weeks.
  • Definitions fork. Paid reports ROAS from the platform. Finance computes revenue over spend from the invoice. Both are labelled "ROAS" and they don't match, so people stop trusting the panel and go back to opening four tabs.

Notice these are all maintenance failures, not design failures. The fix has to be structural: definitions that live in one place, sources that pull themselves, and a surface that regenerates instead of being edited.

The KPIs that actually earn a slot

A KPI dashboard is a decision instrument, not an inventory of every field your platforms expose. The useful test: has this number ever changed what someone did? If not, cut it. In practice a marketing KPI dashboard needs to answer three standing questions, and the metrics fall out of them.

1. Is demand growing?

Impressions and non-brand clicks from Search Console, sessions from GA4. Brand and non-brand behave differently enough that blending them hides the only interesting half — brand search usually tracks what your other channels did last month, while non-brand tracks whether your content is winning new ground.

2. Is paid efficient?

Spend, CPA and ROAS by platform, with clicks and CTR one level down as the diagnostic. CPA answers "what did a customer cost", ROAS answers "did the money come back", and you want both because they fail in opposite directions — a campaign can hit target CPA on cheap, low-value conversions and still lose money.

3. Is anything broken?

The delta view: what moved more than usual since last week. A page that lost half its impressions, a campaign whose CTR fell off a cliff, a source that stopped reporting. This is the panel people actually scan first, and it's the one most dashboards omit.

Rule of thumb: seven KPIs on the front panel, everything else one query away. A dashboard with thirty tiles gets read like wallpaper.

The definition problem nobody puts on the dashboard

Here's the part that quietly ruins cross-channel KPIs. Every platform counts with its own rules, and none of them are wrong — they're answering different questions:

  • Attribution windows differ. Meta and Google Ads both credit conversions back to a click, but not over the same window and not with the same view-through treatment. Summing their conversion counts gives you a number that belongs to no one.
  • GSC clicks are not GA4 sessions. One counts clicks on a search result, the other counts what happened after the landing, with its own deduplication. Expecting them to match is a category error, and it's the single most common way a KPI dashboard loses credibility on first read.
  • "Revenue" is at least three things. Platform-reported conversion value, GA4 purchase value, and what actually cleared in your billing system.

The structural answer is a definition layer: one place where spend is spend, clicks are clicks, and derived KPIs are macros rather than arithmetic retyped per chart. That's how TableBI is organized — data lands in two altitudes. There's a unified facts table where every platform's columns are normalized into shared definitions, and there are per-platform raw tables underneath that keep everything lossless for when you need to see exactly what a platform reported.

KPIs come from macros over the unified table, so nobody re-derives the arithmetic slightly differently on the fourth chart:

claude code → tablebi
# the paid-efficiency panel, in one query across every ad platform
tablebi ask "SELECT platform,
             SUM(cost) AS spend,
             roas(SUM(conversion_value), SUM(cost)) AS roas,
             cpa(SUM(cost), SUM(conversions))      AS cpa,
             ctr(SUM(clicks), SUM(impressions))    AS ctr
             FROM facts
             WHERE date >= (SELECT MAX(date) FROM facts) - 28
             GROUP BY platform ORDER BY spend DESC"

Build it: connect once, then query

Setup is a CLI install and one OAuth round-trip per source. The install step plants a skill so Claude Code knows the tool exists and which command to reach for — after that you can ask in English and the agent writes the SQL.

terminal
npm i -g @tablebi/cli
tablebi login
tablebi install

# one browser round-trip each, then data syncs in
tablebi connect gsc --site sc-domain:example.com
tablebi connect ga4
tablebi connect google_ads
tablebi connect meta_ads

# anything without a live connector arrives as CSV, same definitions
tablebi connect csv --file tiktok-export.csv --platform tiktok_ads

Before building anything, get the lay of the land in one call — connected sources, available definitions, how fresh each source is:

terminal
tablebi context --json

That freshness field matters more than it looks. Search Console finalizes on a multi-day lag; ad platforms settle within about a day. A KPI dashboard that shows today as a cliff is usually just showing an incomplete day, and the fastest way to destroy trust in a panel is to let someone read that cliff as a collapse. Every answer here ships with a trust block carrying that freshness plus the caveats — including the GSC-clicks-are-not-GA4-sessions one — so the agent reading it stops short of the wrong comparison.

Pin it: the KPI dashboard as a URL

Once the queries are right, freeze them into a dashboard rather than screenshotting the terminal. Each widget is a title plus a query; the dashboard re-runs them as new data syncs, so it's current without anyone touching it:

claude code → tablebi
tablebi pin --title "Marketing KPIs" \
  --widget "Spend by platform (28d)=SELECT platform, SUM(cost) AS spend FROM facts …" \
  --widget "ROAS trend::line=SELECT date, roas(SUM(conversion_value), SUM(cost)) AS roas FROM facts …" \
  --widget "Non-brand clicks::line=SELECT date, SUM(clicks) AS clicks FROM search_console_raw …"
✓ published → https://dk.tablebi.com/d/dsh_…  (public, read-only, self-refreshing)

Below is a real pinned dashboard built exactly this way — live Search Console data across a portfolio of sites. It's not a mockup; it refreshes as the sources sync:

Reading it on Monday without lying to yourself

Three habits separate a KPI dashboard that drives decisions from one that decorates a wall:

  • Compare against the same weekday. Week-over-week, not versus yesterday. Most marketing data has a weekly shape, and day-over-day deltas are mostly weekday noise dressed up as signal.
  • Check freshness before you react. If the last two days are partial, a "drop" is an artifact. This is the mistake that produces the most unnecessary Monday panic.
  • Let the delta panel pick the questions. Don't read all seven tiles equally; read what moved, then drop to the raw altitude to find out why. The raw tables are where the answer is — which query, which campaign, which landing page — and the unified table only ever tells you that something moved.

That last move is the reason for keeping both altitudes. Cross-channel KPIs tell you where to look; per-platform raw rows tell you what happened. A dashboard that only has the first is a smoke alarm without a floor plan.

When a BI platform is still the better call

Be honest about the boundary. If a dozen people need to build their own views, if you need row-level access control, or if marketing data is one input into a warehouse that finance and product also model against, buy the BI platform — that's the job it's built for, and a CLI is not a governance layer.

The setup here wins in the other case, which is more common than the vendor pages admit: one shared set of KPIs, a handful of readers, and nobody who wants to own a modeling layer. Then per-seat billing is paying for a collaboration feature you're not using, and the thing you actually needed was a link that stays correct. We compared those tradeoffs directly in Looker Studio alternatives, and the general dashboard build in the marketing dashboard guide. If your KPIs are mostly paid-side, the PPC reporting walkthrough goes deeper on Google Ads and Meta together; for the recurring-delivery version see automated marketing reports.

FAQ

What KPIs should a marketing dashboard actually show?

Enough to answer three standing questions — is demand growing, is paid efficient, is anything broken. That's usually spend, clicks, CTR, conversions, CPA, ROAS and a demand indicator like non-brand clicks. If a metric has never changed a decision, cut it.

Why do the same KPIs disagree between platforms?

Different counting rules. Meta and Google Ads use different attribution windows; GA4 credits sessions on its own model; Search Console clicks are search-result clicks, not sessions. None are wrong — which is exactly why you need one shared definition layer rather than four screenshots side by side.

How often should it update?

As often as your slowest trusted source. Ad platforms settle in about a day, Search Console finalizes on a multi-day lag, so daily is honest. Showing per-source freshness matters more than raw frequency — it stops people reading an incomplete day as a decline.

Do I need a BI tool for this?

Only if many people need to build their own views and governance matters. For one shared KPI set that refreshes itself and is readable by anyone with the link, a CLI your agent drives covers it without per-seat billing.

Try it

Define your KPIs once. Let the dashboard keep itself current.

terminal
npm i -g @tablebi/cli && tablebi install