Meta ads reporting without the spreadsheet grind
Most Meta ads reporting is a weekly ritual: open Ads Manager, set the date range, pick the breakdowns, export, and rebuild the same pivot table you built last Tuesday. This guide shows the alternative: connect Meta Ads once via OAuth, keep the data resident and queryable, and let an AI agent answer the recurring questions — campaign ROAS rankings, ad sets burning money with zero conversions, this week versus last — in seconds of SQL instead of an afternoon of spreadsheet work. At the end, the whole thing gets pinned to a live URL, so next week there is no ritual at all.
The Ads Manager export loop
Ads Manager is a fine place to run campaigns and a frustrating place to answer questions. The loop looks like this:
- Every question needs a fresh export — columns configured again, date range set again, breakdown re-picked again.
- The export is a snapshot. By Thursday it's stale; the pivot table built on it is staler.
- The numbers live alone. Comparing Meta against Google Ads means a second export, a second dialect, and a VLOOKUP with a definitions problem — Meta's purchase value is not the same column, name or concept as Google's conversion value.
- Sharing means screenshots, and screenshots invite the worst question in reporting: "is this current?"
None of the individual steps is hard. The grind is that they repeat — weekly, per account, per client — and repetition is exactly the work that shouldn't belong to a human anymore.
Meta ads reporting as queries, not exports
The structural fix: stop pulling data out to where the questions are, and move the questions to where the data lives. TableBI is a data backend built for that, designed to be driven by an AI agent — its tagline is "the data backend for your Claude Code," Claude Code being Anthropic's terminal-based coding agent. You don't need to write the SQL below yourself; the agent does, and definition macros keep the arithmetic honest either way. Setup is two commands and one OAuth screen:
npm i -g @tablebi/cli
tablebi login
tablebi install
# browser opens for OAuth, then the account syncs in
tablebi connect meta_ads
From then on the account is resident and current. Data lands in two altitudes: facts, the cross-channel table with unified definitions (date, platform, account, campaign, ad group, ad — with clicks, impressions, cost, conversions, conversion value), and meta_ads_raw, the lossless platform-native rows for when you need exactly what Meta reported. Reporting stops being an export and becomes a query.
The queries that replace the pivot table
Four workhorses cover most weekly Meta reviews. Campaign ranking first — spend and ROAS, using the roas() macro so the formula is applied one way, every time:
# campaign spend + ROAS, last 28 days tablebi ask "SELECT campaign, SUM(cost) AS spend, roas(SUM(conversion_value), SUM(cost)) AS roas FROM facts WHERE platform = 'meta_ads' AND date >= (SELECT MAX(date) FROM facts) - 28 GROUP BY campaign ORDER BY spend DESC LIMIT 20"
Then the budget-leak check — ad sets that spent money and converted nothing. In Ads Manager this is a sort, a squint and a scroll; here it's a HAVING clause:
# spending with zero conversions, last 14 days tablebi ask "SELECT campaign, ad_group, SUM(cost) AS spend FROM facts WHERE platform = 'meta_ads' AND date >= (SELECT MAX(date) FROM facts) - 14 GROUP BY campaign, ad_group HAVING SUM(cost) > 0 AND SUM(conversions) = 0 ORDER BY spend DESC"
Week-over-week movement, without exporting two date ranges and eyeballing them side by side:
# last 7 days vs the 7 before tablebi ask "SELECT CASE WHEN date >= (SELECT MAX(date) FROM facts) - 7 THEN 'last 7d' ELSE 'prior 7d' END AS period, SUM(cost) AS spend, SUM(conversions) AS conversions, roas(SUM(conversion_value), SUM(cost)) AS roas FROM facts WHERE platform = 'meta_ads' AND date >= (SELECT MAX(date) FROM facts) - 14 GROUP BY 1 ORDER BY 1"
Note the date idiom: windows anchor on MAX(date) in the data, not on today's calendar date — so a query never silently includes days the platform hasn't reported yet. Every answer also carries a trust block: per-source freshness, applicable caveats, and lineage showing exactly which formula produced each derived metric. That's the difference between an agent's answer you double-check and one you forward.
Meta and Google in the same currency
The fourth workhorse is the one Ads Manager can't run at all. Meta reports purchase value; Google Ads reports conversion value; every platform names and measures its own way. In the facts layer both land in one column — conversion_value — with spend, clicks and conversions normalized the same way. That's the entire point of a unified layer: cross-platform comparison becomes one honest query instead of a spreadsheet reconciliation project:
# Meta vs Google, same definitions, one query tablebi ask "SELECT platform, SUM(cost) AS spend, roas(SUM(conversion_value), SUM(cost)) AS roas, cpa(SUM(cost), SUM(conversions)) AS cpa FROM facts WHERE platform IN ('meta_ads', 'google_ads') AND date >= (SELECT MAX(date) FROM facts) - 28 GROUP BY platform"
One caution the trust block will also give you: unified definitions make numbers comparable, not identical in meaning — each platform still attributes conversions its own way, so treat cross-platform ROAS as a steering signal, not a courtroom exhibit. For the Google side of this workflow — query patterns, account structure, the same macros — see Claude Code for Google Ads.
Pin the weekly report as a live link
The last export you ever do is the one you don't: pin the weekly view once, and share a URL that re-pulls from Meta on access and on schedule:
tablebi pin --title "Meta Ads — weekly" \ --widget "Spend by day (28d)::line=SELECT date, SUM(cost) AS spend FROM facts WHERE platform = 'meta_ads' AND date >= (SELECT MAX(date) FROM facts) - 28 GROUP BY date ORDER BY date" \ --widget "Campaigns by spend=SELECT campaign, SUM(cost) AS spend, roas(SUM(conversion_value), SUM(cost)) AS roas FROM facts WHERE platform = 'meta_ads' AND date >= (SELECT MAX(date) FROM facts) - 28 GROUP BY campaign ORDER BY spend DESC LIMIT 10" ✓ published → https://<your-ws>.tablebi.com/d/dsh_… (public, read-only, self-refreshing)
The URL is public and read-only — a media buyer, a founder or a client can open it any day and see current numbers, and each widget has an "ask" button so their follow-up question routes back to you instead of dying in a thread. If you run this across many accounts or clients, the agency reporting guide covers the multi-workspace version; if you'd rather start from ready-made widget lists, these report templates include a paid-efficiency board you can pin verbatim.
What stays in Ads Manager
To be clear about the boundary: TableBI is read-only. Building campaigns, editing creative, shifting budgets, audience work — all of that stays in Ads Manager, where it belongs. And if what you want is a drag-and-drop Facebook ads reporting tool with a template gallery and white-label PDF exports, this isn't that either — reports here are defined as SQL and published as live links, with a "Powered by TableBI" footer. The trade is deliberate: an agent-driven workflow and a URL that's never stale, in exchange for the GUI.
FAQ
Is this a Facebook ads reporting tool that replaces Ads Manager?
No — it replaces the export-and-pivot loop, not campaign management. TableBI is a read-only reporting and analysis layer: you still build, edit and budget campaigns in Ads Manager. What moves out is answering performance questions and publishing reports.
How does the Meta Ads connection work?
One command — tablebi connect meta_ads — opens a browser OAuth flow. After you authorize, spend, impressions, clicks, conversions and conversion value sync into a queryable backend and stay current. Pinned dashboards then refresh themselves on access and on a schedule.
Can I report Meta and Google Ads together in one place?
Yes. The facts layer normalizes both platforms into one set of definitions — Meta's purchase conversion value and Google's conversion value both land in a single conversion_value column — so one query compares ROAS or CPA across both, and one dashboard shows both.
Do I need to know SQL to use this?
Not really. The workflow assumes an AI agent — Claude Code, Anthropic's terminal-based coding agent — writes the SQL from your plain-English question. Definition macros like roas() and cpa() keep the arithmetic consistent no matter who or what writes the query.
Give your Claude Code a data backend in five minutes.
npm i -g @tablebi/cli && tablebi install