Marketing report templates you can pin as live dashboards
Searching for a marketing report template usually gets you a nicely designed document with empty charts — and the layout was never your problem. The problem is the refill: every week or month, someone pipes fresh numbers into the old frame, checks the totals, fixes the chart that broke, and ships a file that's stale on arrival. This page takes a different approach. Below are three marketing report templates defined not as documents but as widget lists — a title plus a SQL query per widget — that you pin once with a single command. Each becomes a live dashboard URL that refreshes itself. The template stops being a chore you repeat and becomes a report that maintains itself.
The template was never the work — the refill is
Be honest about where reporting time actually goes. Picking a layout happens once. What repeats, forever, is:
- Exporting this period's numbers from every platform, in every platform's own format.
- Pasting them into the template's spreadsheet or slides and repairing whatever shifted.
- Re-checking definitions — was ROAS computed off the same conversion value column as last month?
- Re-sending the file, and answering "which version is current?" three days later.
A document template can't fix any of that, because a document is a snapshot by nature. The fix is to change what the template is.
A marketing report template is just titles + SQL
On TableBI — a data backend built to be driven by an AI agent like Claude Code (Anthropic's terminal-based coding agent) — a report template is literally a list of widgets. Each widget is "Title=SQL" for a table, or "Title::line=SQL" for a line chart. One tablebi pin command publishes the list as a dashboard with a public, read-only URL that re-pulls from your connected sources automatically — on access and on a schedule. Definitions come from shared macros (roas(), ctr(), cpa()…), so the arithmetic is identical in every report, every period, no matter who pins it.
Setup, if you haven't already:
npm i -g @tablebi/cli
tablebi login
tablebi install
# connect whichever sources the template needs (OAuth in browser)
tablebi connect gsc --site sc-domain:example.com
tablebi connect ga4
tablebi connect meta_ads
tablebi connect google_ads
Now the three templates. Each is a complete command — copy, paste, done. Your agent can also adapt any of them from a plain-English request ("add a country breakdown"), which is the intended workflow.
Template 1: weekly marketing overview
When to use it: the standing Monday view — is anything up, down or on fire across all channels. Who it's for: you, your team standup, or a founder who wants one link instead of four platform logins.
tablebi pin --title "Weekly marketing overview" \ --widget "Clicks by day (28d)::line=SELECT date, SUM(clicks) AS clicks FROM facts WHERE date >= (SELECT MAX(date) FROM facts) - 28 GROUP BY date ORDER BY date" \ --widget "Spend by platform (28d)=SELECT platform, SUM(cost) AS spend FROM facts WHERE date >= (SELECT MAX(date) FROM facts) - 28 GROUP BY platform ORDER BY spend DESC" \ --widget "Top campaigns by spend (28d)=SELECT platform, campaign, SUM(cost) AS spend, SUM(conversions) AS conversions FROM facts WHERE date >= (SELECT MAX(date) FROM facts) - 28 GROUP BY platform, campaign ORDER BY spend DESC LIMIT 10" ✓ published → https://<your-ws>.tablebi.com/d/dsh_… (public, read-only, self-refreshing)
Note the date idiom used throughout: date >= (SELECT MAX(date) FROM facts) - 28 anchors the window on the freshest data actually present, not today's calendar date — so a platform reporting a day behind never punches a fake dip into your charts.
Template 2: SEO monthly report
When to use it: the monthly organic check-in — search trend and which pages carry it. Who it's for: whoever owns content and SEO, or a client who asks "is the blog working?"
This one runs on search_console_raw, the lossless Search Console altitude, because page-level detail is platform-specific and doesn't belong in the cross-channel layer:
tablebi pin --title "SEO monthly report" \ --widget "Impressions by day (28d)::line=SELECT date, SUM(impressions) AS impressions FROM search_console_raw WHERE date >= (SELECT MAX(date) FROM search_console_raw) - 28 GROUP BY date ORDER BY date" \ --widget "Clicks by day (28d)::line=SELECT date, SUM(clicks) AS clicks FROM search_console_raw WHERE date >= (SELECT MAX(date) FROM search_console_raw) - 28 GROUP BY date ORDER BY date" \ --widget "Top pages by clicks (28d)=SELECT page, SUM(clicks) AS clicks, SUM(impressions) AS impressions FROM search_console_raw WHERE date >= (SELECT MAX(date) FROM search_console_raw) - 28 GROUP BY page ORDER BY clicks DESC LIMIT 15" ✓ published → https://<your-ws>.tablebi.com/d/dsh_…
Every pinned dashboard also carries the trust context the queries ran with — source freshness and caveats — which matters here because Search Console's numbers arrive on a platform-specific lag, and a report that silently pretends otherwise invites the wrong conclusions.
Template 3: paid efficiency review
When to use it: weekly or before any budget conversation — where paid money works, where it doesn't, and what's burning with nothing to show. Who it's for: the person who moves budgets, and anyone who has to defend the ad spend line.
tablebi pin --title "Paid efficiency review" \ --widget "ROAS by platform (28d)=SELECT platform, SUM(cost) AS spend, roas(SUM(conversion_value), SUM(cost)) AS roas FROM facts WHERE cost > 0 AND date >= (SELECT MAX(date) FROM facts) - 28 GROUP BY platform ORDER BY spend DESC" \ --widget "CPA by campaign (28d)=SELECT platform, campaign, SUM(cost) AS spend, cpa(SUM(cost), SUM(conversions)) AS cpa FROM facts WHERE cost > 0 AND date >= (SELECT MAX(date) FROM facts) - 28 GROUP BY platform, campaign ORDER BY spend DESC LIMIT 15" \ --widget "Spending, zero conversions (14d)=SELECT platform, campaign, ad_group, SUM(cost) AS spend FROM facts WHERE date >= (SELECT MAX(date) FROM facts) - 14 GROUP BY platform, campaign, ad_group HAVING SUM(cost) > 0 AND SUM(conversions) = 0 ORDER BY spend DESC" ✓ published → https://<your-ws>.tablebi.com/d/dsh_…
The third widget is the one that pays rent: ad sets and campaigns that spent in the last two weeks and converted nothing, ranked by damage. Because the facts layer normalizes Meta, Google and CSV-imported channels into the same columns, this list is cross-platform for free — Meta's purchase value and Google's conversion value are both just conversion_value here.
What a pinned template looks like
Templates on a page are hypothetical; here's a real pinned dashboard, built exactly this way, running on live Search Console data (open any widget's "ask" button and you can send the author a question about it):