MGID Performance Diagnostics
Explains a metric move. Retrospective and read-only: it answers what changed and why, then hands off. It does not decide what to do — that is the simulator's and the signal skills' job.
Tools: tool reference Assumptions: threshold assumptions
Required inputs
| Input | Required | Default |
|---|---|---|
| Symptom metric | Yes | ask: CPA, spend, conversions, CTR, or "something feels off" |
| Scope | No | whole account |
| Break window | No | last 3 days vs the 7 days before |
The user rarely knows the exact day. Find it rather than asking twice.
Order of elimination
Work top-down and stop at the first layer that explains the move. Each layer is cheaper and more common than the one below it.
| # | Layer | Question | Evidence |
|---|---|---|---|
| 0 | Tracking | Did conversions stop being recorded? | mgid-tracking-health-monitor |
| 1 | Own changes | Did we change something? | ask the user; changes are not readable through the tools |
| 2 | Composition | Did the mix shift between campaigns? | get_portfolio_statistics, two windows |
| 3 | Delivery | Did one campaign's volume or price move? | get_campaign_statistics daily rows |
| 4 | Placement | Did the traffic mix inside a campaign move? | get_selective_bidding_statistics |
| 5 | Creative | Did a teaser die or a new one take over? | run_custom_report / get_teaser_statistics |
| 6 | Unexplained | None of the above | say so plainly |
Layer 0 first, always. A broken postback looks exactly like a CPA catastrophe, and every action taken on it makes things worse.
Layer 1 costs a question, not a call. No tool reads back what was changed, so ask the user what moved recently — bids, filters, budgets, creatives — and correlate the answer with when the metric broke. Changes made in the MGID dashboard are equally invisible, so never rule a change out: if the break is real and nobody remembers touching anything, say a dashboard change cannot be excluded.
Workflow
Phase 0 — Gate
Run mgid-tracking-health-monitor on the scope. On fail: report the tracking
break, its start, the spend at risk, and stop. Do not diagnose CPA on
untrustworthy conversion data.
Phase 1 — Locate the break
get_portfolio_statistics(dateInterval: interval, startDate, endDate) // symptom window
get_portfolio_statistics(dateInterval: interval, startDate, endDate) // baseline window
Two calls for the whole account. Compute per campaign: Δspend, Δclicks, Δavcpc, Δconversions, ΔCPA, Δprofit — absolute and as a share of the account delta.
Rank campaigns by contribution to the account-level move, not by their own percentage change: a 300% CPA rise on $4 of spend is noise, a 20% rise on $4,000 is the story.
Phase 2 — Attribute
For the top contributors (cap at 5), pull daily rows:
get_campaign_statistics(campaignId, dateFrom, dateTo) // symptom + baseline in one range
Decompose the CPA move — this is the part a dashboard cannot do:
CPA = spend / conversions = (clicks × avgCPC) / (clicks × CVR) = avgCPC / CVR
so
- avgCPC up, CVR flat → an auction/price story → Layer 4
- CVR down, avgCPC flat → a traffic-quality or landing-page story → Layer 4/5
- both moved → report both contributions, largest first
- conversions flat, spend up → a pacing or limit change → Layer 1/3
- clicks collapsed, rates flat → delivery: budget exhausted, campaign paused, moderation rejection, or lost auction share
State the split numerically ("CPA +38%: +31pp from CPC, +7pp from CVR"), never as an adjective.
Phase 3 — Localise inside the campaign
get_selective_bidding_statistics(campaignId, entity, symptom window)
get_selective_bidding_statistics(campaignId, entity, baseline window)
Entity per the campaign-type table. Look for new entities carrying material spend in the symptom window and absent from the baseline — a newly opened source is the single most common cause of an overnight CPA jump.
Creative layer only if placement does not explain it: a teaser that stopped
serving (moderation rejection, exhausted, paused) or a new teaser that took the
share. list_teasers carries the rejection reason.
Phase 4 — Report
Output
Chat, in this order:
- One-sentence verdict. "CPA rose 38% because source X took 22% of spend at 4× the account CPA, starting Tuesday."
- The break date, with the numbers on either side of it.
- Contribution table — campaign, Δ, share of the account move.
- The decomposition — CPC vs CVR, in points.
- What was ruled out, explicitly: tracking, our own changes, composition.
- Confidence, plus what would raise it (a longer window, the customReports grant, a dashboard change history the API cannot see).
Then hand off: "mgid-source-auditor would price or block the sources involved"
— do not do it here.
Guardrails
- Read-only skill. It recommends no writes and calls no write tool.
- Never report a cause without the numbers that support it.
- Never attribute to a change in the audit log without matching the timestamp to the break; correlation must at least be in the right order.
- Fewer than 50 conversions in either window (ASSUMPTION) → label the CPA move as possibly statistical noise and say so before anything else.
- Same-day and yesterday-only windows are unreliable — stats settle. Prefer complete days, and name the window in the output.
- If nothing explains it, say "unexplained" and list what was checked. An invented cause is worse than an open question.