Blog · Meta Ads Reporting

Meta ads reporting without the spreadsheet grind

Published July 17, 2026 · 8 min read

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:

terminal
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:

claude code → tablebi
# 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:

claude code → tablebi
# 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:

claude code → tablebi
# 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:

claude code → tablebi
# 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:

claude code → tablebi
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.

Try it

Give your Claude Code a data backend in five minutes.

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