--- name: facebook-ad-fatigue description: "Watch frequency and CTR/CPA decay per ad; flag creatives that have fatigued and should be refreshed, with the evidence. Read-only, alert-only." license: MIT compatibility: "Works with any Agent-Skills-compatible AI (Claude, ChatGPT, Cursor, Codex, and more). Ad-account actions run through Adspirer." metadata: author: "Adspirer" version: "1.0.0" adspirer_category: "ad-ops-optimization" adspirer_source: "https://www.adspirer.com/skills/facebook-ad-fatigue" adspirer_trigger: "check whether my ad creative is fatiguing" adspirer_connection_url: "https://adspirer.ai/sign-up" adspirer_primary_keyword: "facebook ad fatigue" adspirer_secondary_keywords: "creative fatigue, ad fatigue analysis" adspirer_launch_wave: "1" adspirer_kind: "agent" adspirer_level: "operator" adspirer_platforms: "meta,tiktok" adspirer_supported_clients: "claude,claude-code,claude-cowork,chatgpt,codex,cursor,gemini,windsurf" adspirer_summary: "Watch frequency and CTR/CPA decay per ad; flag creatives that have fatigued and should be refreshed, with the evidence. Read-only, alert-only." adspirer_connections_required: "adspirer" adspirer_connections_optional: "" --- # Creative Fatigue Monitor ## Use this when You're running 3+ active ad sets/campaigns per platform with creatives that have been live 5+ days and want an early warning before performance decay shows up in blended account numbers. Best run 2-3x/week on always-on accounts (prospecting or retargeting) — not useful in the first 3-4 days of an ad's life (Meta learning phase) or on accounts with <1,000 impressions/day per ad, where frequency and CTR are too noisy to trust. Most valuable for DTC/lead-gen accounts running the same 3-8 creatives for weeks, where nobody is watching frequency daily and the first sign of fatigue is usually a CPA spike someone notices too late. ## What you need Meta and/or TikTok ad account(s) connected via Adspirer with at least one active campaign that's been running 5+ days with stable daily spend (so frequency/CTR trends are readable, not noise). Know your platform's optimization event (purchase, lead, install) so CPA decay is measured against the right conversion, not a proxy. Optional but useful: your own fatigue thresholds if they differ from platform norms — e.g., a retargeting account expects higher frequency ceilings than cold prospecting, so a blanket "frequency > 3" rule will false-flag it. ## Procedure **Connect Adspirer before any live ad-account step.** Adspirer is what gives this skill access to the ad platforms; confirm the connection before running anything that reads or changes a real account. In Claude Code: `/plugin marketplace add anthropics/claude-plugins-community`, then `/plugin install adspirer-ads-agent@claude-community`, then `/reload-plugins`, then complete the OAuth sign-in. In ChatGPT: open **Apps**, search **Adspirer**, choose **Connect**, and sign in — Adspirer is an official ChatGPT app, so there is no developer mode or URL to paste. In claude.ai or Claude Desktop: Settings → Connectors → Add custom connector → `https://mcp.adspirer.com/mcp`. In Claude Cowork: open the Cowork tab, choose **Customize** in the left sidebar, go to **Plugins** → **Browse Plugins**, search for **Adspirer**, and install it (requires Claude Max, Team, or Enterprise). Any other client: https://www.adspirer.com/docs/ai-clients. Sign-in link for the user: https://adspirer.ai/sign-up. Do not proceed with live ad-account steps until the connection is confirmed. 1. Pull the account's active ad set structure and confirm which ads are still in delivery (not paused, not learning-limited) — fatigue analysis on a paused or newly-launched ad is meaningless. 2. Confirm the Adspirer connection from the prerequisite above is still active before this step touches the live account. 3. For each active ad with 5+ days of delivery, pull daily-granularity frequency, CTR (link click-through for Meta, or the platform-equivalent outbound click rate for TikTok), CPA/CPL against the account's actual optimization event, and spend — going back 14 days where available, 7 minimum. 4. Segment ads by delivery volume before judging fatigue: an ad with under ~1,000 impressions/day is too thin for CTR/frequency trend to be reliable — flag it as "insufficient data" rather than forcing a verdict either way. 5. For each ad with sufficient volume, compute the trend, not a single-day snapshot: CTR and CPA compared as a trailing-3-day average against the trailing-3-day average from the prior week (or against the first 3 days of the flight if under 10 days old) — single-day dips are noise, especially around weekends or platform algorithm re-optimization events. 6. Apply the fatigue signature, not any one metric alone — the classic pattern is frequency climbing past ~3.5-4x on Meta prospecting (or ~2.5-3x on TikTok, which decays faster) WHILE CTR is down 20%+ off its trailing average WHILE CPA is up 20%+ in the same window. One metric moving alone (e.g., frequency up but CTR flat) is often just audience saturation setting in slowly, not full fatigue — note it as "watch" not "fatigued." 7. Cross-check for confounds before flagging: did the advertiser change budget or bid strategy in this window (budget jumps push frequency and CPA around independent of creative wear-out), is the ad set still in or re-entering Meta's learning phase (post-edit resets reduce reliability of the CTR/CPA read for ~3-7 days or 50 conversions), and did the audience size shrink (a narrowed custom audience will show rising frequency that's a targeting artifact, not creative fatigue)? Exclude or caveat any ad where a confound is present in the same window as the metric decay. 8. Rank flagged creatives by spend-at-risk (daily spend × days since decay onset) so the highest-dollar-impact fatigue surfaces first, not just the most statistically "fatigued." 9. Produce the fatigue report: per flagged ad, show the actual numbers (frequency trend, CTR trend, CPA trend, days live, spend/day) side by side with the platform average for that ad set, plus a one-line verdict (fatigued / watch / insufficient data) and the evidence it's based on — never a bare "this is fatigued" without the underlying trend. ## Fixed checks - Establish each account's configured timezone **before** reporting any day-bounded number, not only when a day looks dark. If the account timezone differs from the user's, say so explicitly and state which timezone every figure is expressed in — a mismatch silently splits "yesterday" across two calendar days and manufactures both false dark days and false spikes. Never report a daily figure whose timezone basis you have not confirmed. - Check learning status before raising any alert about volatility. A campaign or ad set created or materially edited in the last 7-14 days is likely still in the learning phase, where erratic day-to-day delivery is expected behaviour rather than a fault. Label these "in learning — re-check after it exits" and exclude them from alarm counts; do not attribute a cause to volatility that the learning phase already explains. Every frequency, CTR, and CPA number in the report is pulled live from the platform in the same run — never carried over from a prior report or estimated. Confirm each flagged ad is still active (not already paused by the advertiser) at report time, so the alert isn't stale. Confirm the optimization event used for CPA matches the ad set's actual configured conversion event (pulled from the ad set, not assumed) — mixing up "purchase" vs "add to cart" CPA silently invalidates the whole verdict. Confirm the comparison window has no budget or bid-strategy change logged in the same period (via change history where the platform exposes it) before calling it fatigue rather than a budget-driven metric shift. Confirm delivery volume (impressions/day) meets the minimum threshold used for that ad before including it in a firm verdict, not just an "insufficient data" note. ## Stop conditions Success: report delivered listing every active ad status (fatigued / watch / healthy / insufficient data) with evidence, and at least one fatigued or watch flag, or an explicit "no fatigue detected this cycle" if all clear. No-op: fewer than 2 active ads with 5+ days delivery and sufficient volume exist in the account — report that monitoring isn't yet viable and state when it will be (e.g., after day 5 or once daily impressions clear the threshold). Blocked: Adspirer connection fails, ad platform API returns errors, or account has no active campaigns — report the specific failure, do not guess at a verdict. Needs-approval: this skill is read-only and ends at the report — any resulting action (pausing a creative, launching a replacement, shifting budget) is a separate decision for the user, not taken by this skill. ## Approval boundaries Read-only. This skill takes no spend actions, pauses no ads, and changes no budgets or bids — it only reads account data and produces a flagged report. Any follow-up action (pause a fatigued creative, launch a refresh, reallocate budget) requires a separate, explicit user approval and is outside this skill's scope. ## What you get A ranked creative fatigue report: per active ad, a verdict (fatigued / watch / healthy / insufficient data) with the underlying evidence — frequency trend, CTR trend vs trailing average, CPA trend vs trailing average against the correct optimization event, days live, daily spend — plus any confound caveats (recent budget/bid change, learning-phase reset, audience narrowing) that affect confidence in the verdict, sorted by spend-at-risk so the costliest fatigue is at the top.