Step 1 — Pull spend and performance from Google Ads (read-only)

For every active campaign, ad group, ad, and keyword, pull: daily spend, monthly budget, clicks, impressions, conversions, cost per acquisition (CPA), and return on ad spend (ROAS) where conversion value is tracked. Pull the trailing 30-day baseline for the same metrics.

Step 2 — Pull spend and performance from Meta Ads (read-only)

For every active campaign, ad set, and ad across Facebook and Instagram placements, pull the same fields: daily spend, budget, clicks, impressions, conversions, CPA, and ROAS, plus the trailing 30-day baseline.

Step 3 — Check budget pacing

For each campaign, compare spend-to-date against the elapsed fraction of its budget period.
Pacing signalCriteria
On paceSpend-to-date within ±15% of the expected linear pace
OverpacingSpend-to-date more than 15% ahead of expected pace — will exhaust budget early
UnderpacingSpend-to-date more than 20% behind expected pace — budget is going unused

Step 4 — Check CPA/ROAS drift

Compare each campaign's/ad's trailing 7-day CPA and ROAS against its 30-day baseline.
Drift signalCriteria
StableCPA within ±15% and ROAS within ±15% of baseline
CPA driftCPA up more than 15% vs. baseline with flat or falling conversions
ROAS driftROAS down more than 15% vs. baseline
Compounding driftCPA up AND ROAS down in the same window — flag first

Step 5 — Flag underperforming ads and keywords

Underperformer signalCriteria
Low-CTR adClick-through rate less than half the ad set's/ad group's average, with 1,000+ impressions
High-cost, no-convert keyword/adSpend above the account's median per-unit spend with zero conversions over the trailing window
Wasted-spend keywordSearch term with 3+ clicks and zero conversions over 14+ days (Google Ads search terms report)

Step 6 — Detect anomalies

Flag anything that breaks the normal pattern rather than drifting gradually:
  • A single day's spend more than 2x the campaign's trailing 7-day daily average.
  • A sudden CTR drop of more than 50% day-over-day on a previously stable ad.
  • A campaign that stopped delivering (near-zero impressions) while still marked active with budget remaining.

Step 7 — Draft the recommendation for each finding

Every finding gets exactly one concrete, human-actionable recommendation:
  • Overpacing → suggest lowering the daily budget or adding a spend cap so it doesn't exhaust the period early.
  • Underpacing → suggest raising bids, widening targeting, or reallocating the unused budget toward a better-performing campaign.
  • CPA/ROAS drift → suggest pausing the specific ad or keyword driving it, or shifting budget toward the campaign's best-performing ad.
  • Underperforming ad → suggest pausing that ad and shifting its budget to the top performer in the same ad set/ad group.
  • Wasted-spend keyword/search term → suggest adding it as a negative keyword.
  • Anomaly → surface it plainly with the numbers; recommend investigating before assuming it's a pacing or drift issue.

Step 8 — Rank and post

Sort findings highest-impact first (compounding drift and overpacing that risks exhausting budget rank above a single underperforming keyword). Post exactly one message to {{alert_channel}}: for each finding, the campaign/ad/ keyword, the specific numbers, and the recommended action. Post exactly once per run — this is a fresh session, so there is no prior list to update or diff against; the whole scan is recomputed and reposted every day.
Ad performance review — Kortix Marketplace | Kortix