AI workflowApplied across most of our client accounts · Google Ads + Meta

How we make a performance review explain why the numbers moved

Most performance reviews tell you the numbers moved, not why. This one does both. It's a deliberately simple weekly (or monthly) read of the account — but before it lands, we enrich it with two things almost nobody pulls together: the full history of changes we made (straight from the Google Ads and Meta APIs) and the macro and micro market signals we scrape. So a ROAS drop arrives already attributed — we changed the bid, a product went out of stock, or the market moved — instead of kicking off a Monday-morning investigation.

3 layers
Numbers · changes · market
WoW / MoM
Runs at your cadence
2 APIs
Change logs pulled in
Every Mon
Digest lands itself
Outcome

The weekly review stopped being a "what happened" and became a "why it happened." Pairing the performance numbers with our own change log and the period's market signals means most shifts arrive already explained — internal cause, external cause, or honestly flagged as unexplained. The payoff is calmer decisions: far fewer panic budget cuts when the cause was a competitor promo we never controlled, and far fewer missed tailwinds when a season or trend was quietly lifting demand. It runs at whatever cadence the account needs, and the read takes minutes instead of an afternoon of digging.

All numbers here are anonymized and illustrative of the pattern, not exact client data. Like our A/B test workflow, this is less "look what we built" and more a way of working — any team can copy it with Claude Code or any other LLM.

The idea

A weekly or monthly performance review is the simplest thing in the world: pull the numbers, see what moved. The hard part is the next sentence — why did it move? Most reviews never answer that. They report that ROAS dropped 12% and then everyone spends Monday morning guessing, or worse, reacting: cutting a budget that was never the problem.

So we take a deliberately simple performance read and enrich it with two things almost nobody pulls together in the same place:

  1. The history of changes we made — every bid, budget, campaign, keyword, and creative edit, straight from the Google Ads and Meta APIs.
  2. The macro and micro market signals we didn't control — competitor promos, seasonality, shipping costs, regulation, local trends — scraped from the outside world.

With those two layers attached, a number stops being a question and becomes an answer: ROAS dropped because we raised the target on Tuesday, or because a competitor went on sale Monday — or, honestly, because we don't know yet. Four steps, and only the last decision needs a human.

From number to cause

illustrative
PERFORMANCEthe numbers, WoW / MoMCHANGE LOGGoogle Ads + Meta APIMARKET SIGNALSscraped, externalROAS−13%INTERNALwe changed itEXTERNALthe market didUNEXPLAINEDflagged, not forced

Three layers in, one attributed shift out: the performance numbers, the changes we made, and the market we didn't control — resolved into an internal cause, an external one, or an honest "unexplained."

Step 1 — Pull the performance numbers (MCP)

The review starts with the boring part: this period versus last. Spend, revenue, ROAS, CPA, broken out by campaign type — week over week, or month over month, whatever cadence the account runs on.

The pull runs through an MCP connected to Google Ads, Meta, or GA4, so the AI fetches the latest numbers itself — no exporting tabs and pasting them in. On its own, this is just a tidy report. The value is what we attach to it next.

Step 2 — Pull what we changed (the change history)

Performance moves for a reason, and most of the time the reason is internal: we changed a target ROAS, raised a budget, launched a campaign, added keywords, swapped creatives, shipped a new landing page — or something happened on the site, like a price change or a product going out of stock.

Here's the thing almost no one uses: both Google Ads and Meta expose a full change history over their APIs — every edit, timestamped. We fetch it for the same period and hand it to the model alongside the numbers. Suddenly most "mystery" shifts aren't mysteries. The CPA jump lines up with the bid we raised on Tuesday. The revenue dip lines up with fourteen SKUs that went out of stock on Wednesday. The model cross-references the two and tells us how much of the move each change likely explains.

Step 3 — Pull what we didn't control (market signals)

Some weeks the numbers move and nothing in our change log explains it. That's when the outside world matters. Some clients are very sensitive to it; some barely feel it — but it's always worth checking before assuming we broke something.

So we scrape the signals that could move demand for that specific industry and market: a competitor running a category-wide promo, a seasonal swing, news on tariffs, embargoes, shipping times or costs, a regulation change — even a short, local trend where a product category suddenly spikes because of something happening in the world. An LLM is genuinely good at gathering this: point it at the right sources (news, SERPs, trend data) and ask what changed in the industry this period.

This is the layer that explains the shifts your own actions can't — and stops you from "fixing" a drop that was really a competitor's sale, or from missing a tailwind that a season was quietly handing you.

Step 4 — The digest that ties it together

The last step is one read that combines all three: the numbers, the changes we made, and the market signals — with each notable shift tagged INTERNAL, EXTERNAL, or honestly left UNEXPLAINED. Same format every time, so we scan it in seconds. Here's what lands:

Marketing IntelligenceAPPMon 9:01 AM
📈 Performance Review — Account: [Client]   ·   Wk 22 vs Wk 21   (2026-05-25 → 05-31)

HEADLINE
  Spend      €71.4k    (+4%   WoW)
  Revenue    €213k     (-9%   WoW)
  ROAS       2.98×     (was 3.41×,  -13%)   ← worth a look
  CPA        €18.20    (+15%  WoW)

LIKELY WHY   (numbers cross-checked against change log + market)
  • INTERNAL — tROAS on "Search · Core" raised 3.2 → 3.6 on Tue (change log).
    Matches the CPA jump and lower volume. Most of the drop sits here.
  • INTERNAL — 14 product pages went out of stock Wed (feed diff). PMax revenue
    for those SKUs fell to ~0. Explains roughly a third of the revenue miss.
  • EXTERNAL — competitor running -25% across the category since Mon (scraped + SERP).
    Our CTR on brand-adjacent terms down 6%. Not in our control.
  • UNEXPLAINED — ~2% of the gap. Flagged, not forced.

CHANGES WE MADE   (Google Ads + Meta change history)
  Tue  tROAS 3.2 → 3.6     Search · Core
  Wed  +6 RSAs             Search · Generic
  Thu  budget +€500/d      PMax · Catalog

MARKET SIGNALS   (scraped)
  • Competitor category-wide promo (-25%), live since Mon.
  • Freight rates +8% on the lane — margin watch, not demand yet.
  • Seasonal: category search interest +11% MoM (early summer).

📅 Next review: Mon 2026-06-08

A few things make the format work: the (was X) on each row shows movement without digging up last week's report; the LIKELY WHY block is the whole point — every shift carries a probable cause and roughly how much it explains; and the UNEXPLAINED line is sacred — the model is told never to invent an explanation just to fill space.

Run it yourself

You don't need our stack. Paste this into your LLM — with your numbers, or wired to an MCP that pulls them for you:

You're running my performance review for an ad account (weekly or monthly). Goal: don't
just report the numbers — explain WHY they moved, separating what WE changed from what
the MARKET did.

INPUTS (pull via MCP if connected, otherwise I'll paste):
  1. PERFORMANCE — this period vs last: spend, revenue, ROAS, CPA, by campaign type.
     <pull from Google Ads / Meta / GA4 via MCP, or paste>
  2. CHANGE HISTORY — every change in the account this period.
     <pull from the Google Ads & Meta change-history API, or paste: bid/budget edits,
      new campaigns/keywords/creatives, plus site/price/stock/feed changes>
  3. MARKET SIGNALS — anything external that could move demand for this industry and
     market this period: competitor promos, seasonality, news on tariffs/shipping/
     regulation, local trends. <scrape / web-search, or paste>

Then write the review in EXACTLY this format every time, so I can scan it in seconds:
  1) HEADLINE: spend, revenue, ROAS, CPA — each vs last period, with % change.
  2) LIKELY WHY: for each notable shift, the most probable cause, tagged INTERNAL
     (cross-referenced to the change history) or EXTERNAL (to a market signal), with
     roughly how much of the move it explains. Add an UNEXPLAINED line for the rest.
  3) CHANGES WE MADE: the change log for the period, dated.
  4) MARKET SIGNALS: the external context you found, sourced.
  5) Next review date.

Rules: attribute, don't advise — propose causes, I make the calls. Never invent an
explanation: if a shift has no plausible cause in the change log or the market, say so.

If your LLM can reach Google Ads, Meta, or GA4 through an MCP, it can pull both the numbers and the change history itself and post the digest on a schedule. If not, paste them in — the value is in the constant format and the three-layer attribution, not the plumbing.

What other teams could steal

  1. A number is useless without its cause. "ROAS down 12%" isn't information, it's a question. The job of a review isn't to report the shift — it's to attribute it: did we change something, did the market, or do we genuinely not know? Pair every movement with a probable cause, or it just generates anxiety and bad reactions.

  2. The change history is the most underused data you already have. Both Google Ads and Meta expose a full, timestamped change log over their APIs — every bid, budget, campaign, and creative edit. Almost nobody reads it. Feed it to the model and most "mystery" shifts line up with something you did three days ago.

  3. Scrape the outside world, but let a human judge causation. Macro and micro signals explain the shifts your own actions can't. An LLM can gather them — and it can also over-explain. Let it propose the likely cause and how much it accounts for; let a person confirm which one actually drove the number. And always leave room for "unexplained."

Key Takeaways

Three things worth taking away.

1

A number is useless without its cause.

"ROAS down 12%" isn't information — it's a question. The job of a review isn't to report the shift, it's to attribute it: did we change something, did the market, or do we genuinely not know? Pair every movement with a probable cause, or it just generates anxiety and bad reactions.

2

The change history is the most underused data you already have.

Both Google Ads and Meta expose a full, timestamped change log over their APIs — every bid, budget, campaign, and creative edit. Almost nobody reads it. Feed it to the model and most "mystery" performance shifts line up with something you did three days ago.

3

Scrape the outside world, but let a human judge causation.

Macro and micro signals — competitor promos, seasonality, shipping costs, local trends — explain the shifts your own actions can't. An LLM can gather them, and it can also over-explain. Let it propose the likely cause and how much it accounts for; let a person confirm which one actually drove the number. And always leave room for "unexplained."

Want to ship something like this?

We build these systems for paid advertising teams that want strategy and execution in one engagement. One-time audit or on-demand consulting.