From mureo
Detects creative fatigue across active ads by measuring frequency, CTR decline, and CPM drift, scoring each ad as FATIGUED, WATCH, or FRESH, and triggers creative refresh.
How this skill is triggered — by the user, by Claude, or both
Slash command
/mureo:ad-fatigue-checkThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> PREREQUISITE: Read `../_mureo-shared/SKILL.md` for auth, security rules, output format, and **Tool Selection** (Read/Write on Code, `mureo_strategy_*` / `mureo_state_*` MCP on Desktop / Cowork).
PREREQUISITE: Read
../_mureo-shared/SKILL.mdfor auth, security rules, output format, and Tool Selection (Read/Write on Code,mureo_strategy_*/mureo_state_*MCP on Desktop / Cowork).
Find the ads whose audience has seen them too many times. Creative fatigue is a slow leak — the same creative keeps spending while frequency climbs, CTR erodes, and CPM drifts up as the algorithm works harder to place a tiring ad. This skill reads active ads per platform, measures the fatigue signals the tools genuinely expose, scores each ad against documented thresholds (with noise guards so a single slow day never triggers a rotation), and hands the fatigued ones to a creative refresh with the evidence attached.
onboard skill first)Before you start: Run the Diagnostic preamble from ../_mureo-shared/SKILL.md — load learning insights (mureo_learning_insights_get) and consult advisors (mureo_consult_advisor) before drawing conclusions.
Load context: Read STRATEGY.md (Goals, Operation Mode) and STATE.json. Note any learning insights about fatigue thresholds — a VALIDATED insight ("this account tolerates frequency 5 before CTR drops") overrides the default rubric in step 4.
Discover active ads per platform:
meta_ads_ads_list (filter to ACTIVE/effective_status delivering).google_ads_ad_performance_report scoped to ENABLED ads.tiktok_ads) / mcp__mureo__<plugin>_* plugin platform best-effort, reporting only what its own tools expose and emitting analytics_not_available_for_<platform> for the fatigue value-adds below (see ../_mureo-shared/SKILL.md). BYOD data is reachable only through mureo MCP tools — do not look for raw CSVs in the project directory.Measure fatigue signals — honestly, per what the tools expose:
frequency field — but meta_ads_insights_report returns both impressions and reach, and frequency is defined as impressions ÷ reach. Compute it yourself from meta_ads_insights_report (level ad, window last_7d): frequency ≈ impressions / reach. This is Meta's own definition, so it is an honest derivation, not a guess. If reach is 0 or absent for an ad, the frequency is undefined — say so, do not divide.meta_ads_insights_report (level ad) exposes ctr but no built-in trend. Get two adjacent weeks the same way weekly-report does: pull last_7d (this week) and last_14d, then derive the prior week as last_14d totals − last_7d totals. Compute the CTR change % between prior-week and this-week.meta_ads_insights_report returns cpm; compare this-week vs prior-week CPM (same subtraction technique). Rising CPM on a flat audience is a fatigue corroborator. meta_ads_analysis_cost also decomposes a campaign's cost change into CPM inflation / CTR drop / creative fatigue drivers — use it to corroborate at campaign level.google_ads_ad_performance_report over adjacent windows (LAST_7_DAYS vs LAST_14_DAYS, same subtraction); Google Ads exposes no frequency at the ad level here, so score Google display/RSA ads on the CTR-trend signal only and say so.google_ads_rsa_assets_audit (replacement recommendations) and google_ads_rsa_assets_analyze (per-asset performance_label + CTR) to find LOW/POOR assets to swap.Fatigue scoring rubric (document the thresholds; let learning insights override them):
Noise guards (apply before assigning any verdict):
../_mureo-learning/SKILL.md). Below that, the ad is insufficient-data, not fatigued.Ranked table — worst first:
| Ad | Campaign | Frequency | CTR w/w | CPM w/w | Impr (this/prior) | Verdict |
|---|---|---|---|---|---|---|
| Ad A | Prospecting | 4.2 | −27% | +14% | 32k / 30k | FATIGUED |
| Ad B | Retargeting | 3.6 | −8% | +3% | 18k / 17k | WATCH |
| Ad C | Brand | 1.8 | −4% | +1% | 21k / 20k | FRESH |
Recommendations — rotate / refresh, with the evidence as the brief: For each FATIGUED (and borderline WATCH) ad, hand off to a creative workflow, passing the fatigue evidence (frequency, CTR decline, the tiring asset) as the input brief:
/creative-generate./creative-refresh.
Do not silently produce new creative here — this skill diagnoses and routes; the creative skills generate under their own approval gates.Pausing a clearly-fatigued ad — approval gate: Pausing is a write. Apply the Confirm Before Write Operations rule from ../_mureo-shared/SKILL.md: list the ad(s), their current spend/frequency/CTR, and confirm before pausing via meta_ads_ads_pause (Meta) or google_ads_ads_update_status (Google Ads). Prefer rotate-in-a-replacement over pause-into-a-gap unless the ad is actively harmful — pausing without a fresh creative ready starves delivery. Never bulk-pause without listing the total impact first.
Record outcome context: For each ad paused or queued for refresh, append to action_log via mureo_state_action_log_append with metrics_at_action (frequency, ctr, cpm, impressions, conversions, cpa) and observation_due 14 days out (the creative-change window from ../_mureo-learning/SKILL.md). A pure diagnostic run with no writes still logs a summary entry (the verdict table), with no observation_due.
Persist the report summary (best-effort): Call mureo_state_report_set with report="fatigue" and a concise summary object so the read-only dashboard can render this check without re-running you. Follow this convention:
generated_at: ISO 8601 timestamp of this runperiod: the two adjacent windows compared (this week / prior week)kpis: counts by verdict (fatigued / watch / fresh / insufficient-data) and the worst-frequency + worst-CTR-decline adsflags: notable items (e.g. ["3_ads_fatigued", "meta_reach_missing_frequency_undefined", "google_display_ctr_only"])narrative: the 1-2 sentence verdict (creatives fresh / rotation needed)Reflect the FINAL state, and persist this LAST — after every action_log entry and any pause you applied this run. This is best-effort: if mureo_state_report_set is unavailable (e.g. a pure file-mode host without the context MCP), skip it silently — the rest of this skill still works.
npx claudepluginhub logly/mureo --plugin mureoScores ad creatives for fatigue risk, predicts when performance will drop, and generates refresh recommendations with A/B test plans.
Detects ad fatigue and audience saturation by analyzing frequency, CTR, and CVR decay against early-flight baseline. Returns rotate-creative, widen-audience, or hold triggers per ad set for scaled campaigns.
Deep-dive analysis of a specific creative asset. Use when the user asks about a specific ad by name, ID, or URL — "analyze this ad", "why is this working?", "why is this not working?", "break down this creative", "[pastes ad name]", "look at this ad", "what's the angle in this ad?", "compare to account averages", or references a specific creative by name or identifier. Handles creative lookup, disambiguation when multiple matches exist, entity hierarchy mapping (creative → ads → adsets → campaigns), and metric-appropriate analysis. This is the most common interaction pattern — users often analyze multiple ads in sequence. Always use this skill, not creative-strategist, when the user references a specific creative.