---
name: "ad_creative_fatigue"
description: "Diagnose whether a paid video or image ad is truly wearing out: build a fresh baseline, read frequency and reach curves, score click and cost decay by audience slice, run confounder checks for audience mix, edits, saturation, auction pressure, page and tracking problems, and end in a keep, rest, or replace call with evidence. Triggers on creative fatigue, ad fatigue, wearout, falling CTR with rising frequency, rising cost per result, when to refresh or kill an ad, or an ad that started strong then declined."
metadata: { "includeInPrompt": true }
---

# Ad Creative Fatigue

## Purpose

Performance falls, and the fastest explanation in the room is that the ad wore out. Sometimes that is true. Often the real cause is an audience that changed underneath the ad, an edit that reset delivery, a shrinking pool, a more expensive auction, or a page that stopped converting. Killing a working ad is expensive, and keeping a worn out ad is expensive. This skill separates the two with evidence: a scored decay pattern, a slice breakdown that shows whether decay follows exposure, and a confounder gate that must pass before any creative is killed. It ends in one call, keep, rest, or replace, with the numbers behind it.

## Workflow

1. **Freeze a baseline before judging anything.** Take the first stable window after delivery settled, usually 7 days, and record impressions, reach, frequency, CTR, CPM, CPC, post click conversion rate, conversions, and cost per result. Skip platform marked learning or exploration days. Every later judgement is against this window, never against an industry benchmark and never against the ad's best single day.

2. **Pull equal windows and draw the exposure curve.** Pull the same metrics in equal length windows up to today. Put impressions and reach side by side: impressions holding or rising while reach falls means the pool is recycling and frequency is climbing mechanically. Frequency is impressions divided by reach, and it only means anything with its window attached, so label every frequency as 7 day, 30 day, or lifetime. Note reporting lag where the platform has it: Google warns that modelled reach and frequency data can take up to 3 days to arrive, so the newest days are incomplete.

3. **Score the decay.** Fill `references/scoring-sheet.md` or build the JSON from `scripts/diagnosis.example.json` and run `python3 scripts/score_fatigue.py diagnosis.json`. Six signals score 0 to 2 each: click decay, cost decay, exposure pressure, post click pattern, slice pattern, and persistence. Read the post click pattern before the total. CTR down with post click conversion rate steady points at the ad. Both down together points after the click.

4. **Slice by exposure and by audience.** Break the current window down by exposure count where the platform reports a frequency distribution, by first time versus repeat viewers, by audience segment, and by placement. The evidence that separates wearout from everything else is a gradient: response worst in the highest exposure slice and near baseline among first time viewers. A flat fall across every slice, including people seeing the ad for the first time, is not wearout, whatever the frequency says.

5. **Run the confounder gate.** Work through every check in `references/confounder-checks.md` and record cleared, found, or not checkable for each one: audience mix shift from warm to cold traffic, significant edits and learning resets, audience saturation, auction and season pressure, audience overlap, page and offer and product changes, tracking and reporting breaks, placement mix shift, and plain low volume noise. Check platform labels last and read them correctly: on Meta, Creative Fatigue means cost per result at least twice its past level and Creative Limited means higher but less than double, and Meta attaches no frequency threshold to either label.

6. **Run a discriminating test when the gate leaves doubt.** Two tests settle most arguments. Same creative, fresh audience: exclude everyone already exposed, or use a new pool or geography. Recovery near baseline means the pool was exhausted, not the creative. New creative, same audience: recovery means the creative was the problem. If neither is possible at the available budget, keep the call at watch and say what data is missing, rather than guessing at replace.

7. **Make the call.** Keep: score 0 to 3, or a confounder fully explains the decay and is being fixed. Keep running, set a recheck date, and state the number that would change the call. Rest: score 7 to 9, or a high score in a saturating pool where the creative still works on fresh viewers. Pause or cut exposure, rotate a variant in, and schedule a rested retest. Rest is a real option, not a delay: research on ad wearout finds that annoyance from repetition fades faster than brand memory, so a rested ad can recover when the category is relevant again. Replace: score 10 to 12 with the confounder gate passed, or a score of 7 to 9 plus a failed rested retest or a discriminating test that convicts the creative. Add the replacement to the existing ad group or ad set where the structure is healthy, which is TikTok's published refresh guidance, instead of rebuilding delivery from zero.

8. **Confirm and record.** After a replace or rest call, check the next full window. A replacement that recovers CTR on the same audience structure confirms the diagnosis. A replacement that decays the same way reopens it, and the next suspects are the audience, the offer, and the page, in that order. Record the baseline, the scores, the gate answers, the call, and the confirmation result, so the next diagnosis on this account starts from evidence instead of memory. See `references/worked-diagnosis.md` for a full run of this workflow.

## Output Contract

Deliver, in this order:

1. **Series table**: baseline and each later window with impressions, reach, frequency with its window labelled, CTR, CPM, CPC, post click conversion rate, conversions, and cost per result, plus the percent change of the current window against baseline.
2. **Scorecard**: the six signals with a score each, the evidence number behind every score, the total out of 12, and the scorer output when the script was run.
3. **Slice evidence**: CTR and cost per result by exposure slice and by first time versus repeat viewers, or an explicit note that the platform does not expose the breakdown.
4. **Confounder gate**: every check from `references/confounder-checks.md` answered cleared, found, or not checkable, with the evidence for each answer.
5. **Call**: keep, rest, or replace, in one sentence, with the two or three numbers that carry it, the action that follows, and the recheck date.
6. **Confirmation plan**: what the next window must show for the call to stand, and what result would reopen the diagnosis.

## Operating Rules

1. No universal frequency threshold exists, and this skill does not invent one. Do not kill an ad because frequency crossed 3, 4, or any other round number. Kill it because response decayed with exposure, in slices, over time, with confounders cleared.
2. Never score across an edit boundary. A significant budget, targeting, bid, or creative change splits the series. Score inside clean windows only.
3. A platform fatigue label is supporting evidence, not a verdict, and the absence of a label is not a clearance. Labels compare cost per result against account history and arrive after costs have already risen.
4. If the data is too thin to score, say so and wait. A diagnosis on a handful of conversions is a coin flip dressed as analysis.
5. Distinguish saturation from wearout every time. Saturation is a pool problem fixed with audience and budget moves. Wearout is a creative problem fixed with new creative. The fresh audience test is how you tell them apart, so run it or name its absence.
6. Do not promise a recovery number for refreshing creative. Report what the replacement actually did in the confirmation window.
7. Keep SKILL.md tight. Scoring bands live in `references/scoring-sheet.md`, the gate lives in `references/confounder-checks.md`, and the full worked run lives in `references/worked-diagnosis.md`.
