{"id":"nowork-studio-audit","name":"meta-ads-audit","summary":"Meta広告(Facebook + Instagram)アカウント監査とビジネスコンテキスト設定。まずこれを実行してください — ビジネス情報を集め、アカウントの健全性を分析し、他のMeta広告スキルが再利用するコンテキストを保存します。","body":"# Meta Ads Audit\n\nDiagnose Meta (Facebook + Instagram) account health and persist business context for downstream skills (`/meta-ads`). **Read-only** — never mutates the account. The user runs `/meta-ads` to execute fixes you recommend.\n\n## Setup\n\nFollow `../shared/preamble.md` — MCP detection, OAuth, ad account selection.\n\n## Filesystem contract (MUST persist)\n\n| Artifact | Path | When |\n|---|---|---|\n| Business context | `{data_dir}/meta/business-context.json` | First full audit, or refresh when `audit_date` is >90 days old. Skip on scoped audits if file is fresh. |\n| Personas | `{data_dir}/meta/personas/{accountId}.json` | Every full audit. |\n\nThese are the handoff to `/meta-ads` — write them even if the report itself is short. Otherwise downstream skills operate without business context and produce generic output.\n\nIf a `{data_dir}/business-context.json` exists from `/google-ads-audit` (no `meta/` subdir), read it as a starting point — most fields (services, brand voice, differentiators, locations, seasonality) are platform-agnostic. Then write the Meta-specific version to `{data_dir}/meta/business-context.json` with any Meta-specific overrides (different creative angles, different audiences, different funnel events).\n\n**business-context.json schema (shared with Google Ads where fields apply):**\n`business_name, industry, website, services[], locations[], target_audience, brand_voice{tone, words_to_use[], words_to_avoid[]}, differentiators[], competitors[], seasonality{peak_months[], slow_months[], seasonal_hooks[]}, social_proof[], offers_or_promotions[], landing_pages{}, unit_economics{aov_usd, profit_margin, ltv_usd, source}, notes, audit_date, account_id`.\n\n**Meta-specific extensions:**\n`meta_funnel_events{top_of_funnel, mid_of_funnel, conversion}, creative_inventory{concepts[], formats[], aspect_ratios[]}, custom_audiences{purchasers, abandoners, engagers, list_uploads[]}, pixel_health{pixel_id, capi_enabled, emq_score, last_event_at}`.\n\n**personas JSON schema:** `{account_id, saved_at, personas: [{name, demographics, primary_goal, pain_points[], decision_trigger, value, meta_creative_angles[], visual_cues[]}]}`. The Meta version adds `meta_creative_angles` (e.g. \"before/after demonstration\", \"founder-led explainer\", \"UGC review\") and `visual_cues` (objects, settings, emotions that resonate with this persona). See `references/persona-discovery.md`.\n\n## Policy freshness check (run first)\n\nRead `../shared/policy-registry.json`. For each entry where `last_verified + stale_after_days < today`:\n- **High-volatility** → WebSearch the `area` for recent Meta Ads changes; compare to `assumption`. If drift, banner the report and suggest registry update.\n- **Moderate-volatility** → one-line \"may warrant a check\" note.\n- **Stable** → skip silently.\n\nThe Meta platform changes faster than Google Ads (Advantage+, attribution, learning behaviors) — check high-volatility entries every audit.\n\n## Phase 1 — Pull the audit dataset\n\nUse a single `runScript` call with `ads.graphParallel` to fan out the queries an audit needs. Build the fan-out from this rubric.\n\nA complete audit needs at minimum:\n\n- **Ad account info** (`/{accountId}`) — currency, timezone, business id, spend cap, account status, balance.\n- **Pixel health** (`/{accountId}/customconversions` + `/{accountId}/adspixels`) — pixel id, last activity, CAPI status, Event Match Quality (EMQ) score.\n- **Campaigns** (`/{accountId}/campaigns`) — id, name, objective, status, daily/lifetime budget, special_ad_categories, buying_type, bid_strategy, created_time. Last 90 days.\n- **Ad sets** (`/{accountId}/adsets`) — id, name, status, campaign_id, optimization_goal, billing_event, bid_strategy, daily_budget, lifetime_budget, attribution_spec, targeting (summary), promoted_object, learning_stage_info.\n- **Ads** (`/{accountId}/ads`) — id, name, status, ad set, creative summary (image/video, primary text, headline, description, CTA), effective_status.\n- **Insights at campaign level** (`ads.insights({level:\"campaign\", date_preset:\"last_30d\"})`) — spend, impressions, reach, frequency, cpm, link CTR, link clicks, purchases (or other primary action), purchase value, ROAS, CPA.\n- **Insights at ad set level** — same fields, last 30 days.\n- **Insights at ad level** — top 50 ads by spend; same fields plus video metrics (3-sec views, ThruPlays) for video creatives.\n- **Insights with breakdowns** — placement (`publisher_platform,platform_position`), age/gender, device. Use these to spot placement losers and audience composition.\n- **Recent edit activity** — when available via `/{adsetId}` last_modified or `/{adsetId}` change history.\n\nCompute aggregates **in the script**, return summarized JSON. Don't return all rows — rank, slice, summarize. The agent narrates the result; the script does the math.\n\n`suggestImprovement` is a useful cross-check for the server's heuristic surface — call it as a separate tool after the runScript pass if you want to compare your findings.\n\nIf a critical query errors out (auth, schema, API version), surface the error and stop — don't fall back to a degraded audit.\n\n**Skip scoring entirely if** `totalSpend == 0` or `activeCampaigns == 0`. Go straight to business context.\n\n## Phase 2 — Scope handling\n\nIf the user narrows the audit (\"focus on one campaign\", \"campaign X\", \"just check creative fatigue\"):\n\n- Match campaign names by case-insensitive substring. If no match, list available campaigns and ask.\n- Filter the in-memory dataset before scoring — no extra API calls.\n- Account-level dimensions (Pixel health, attribution defaults) stay account-wide. Note \"Scoped to: X\" in the report.\n- Skip Phase 4 (business context refresh) on scoped audits if `business-context.json` is fresh.\n\n## Phase 3 — Score\n\nScore each of the 7 dimensions 0–5 using `references/account-health-scoring.md`. Overall = `round(sum × 100 / 35)`.\n\n| Score | Label | Meaning |\n|---|---|---|\n| 0 | Critical | Broken or missing — actively losing money |\n| 1 | Poor | Major waste or missed opportunity |\n| 2 | Needs Work | Several clear issues |\n| 3 | Acceptable | Functional, room to improve |\n| 4 | Good | Well-managed, minor opportunities |\n| 5 | Excellent | Best-practice |\n\nScope-aware: campaign-level dimensions reflect in-scope data; account-level dimensions (Pixel + CAPI, attribution setup) score account-wide with a note on scope impact.\n\n### Encoded heuristics — apply these, they aren't obvious\n\n- **Pixel + CAPI is upstream of everything.** EMQ < 7.0 means Meta can't match events well — Smart Bidding starves regardless of how good the creative is. STOP-condition input.\n- **Reported ROAS systematically overstates true ROAS.** Cross-check Meta-reported numbers against Shopify / GA4 / MMM where possible. The gap is the modeled-conversion premium and is typically 20–40% in ecom.\n- **Frequency × CPM trend = creative diagnosis.** Frequency > 3.0 with CPM rising ≥ 30% w/w is fatigue — recommend creative refresh, not budget cuts.\n- **One ad set carrying > 70% of a campaign is fragility, not concentration.** When it fatigues, the campaign collapses.\n- **Audience overlap > 50% between sibling ad sets fragments signal.** Consolidate; don't try to \"fix\" with bid caps.\n- **Special Ad Category misclassification is a takedown risk, not just a policy nit.** Surface as Critical regardless of current performance.\n- **Manual placements without evidence is a sign of inherited-from-2018 thinking.** Default should be Advantage+ Placements; deviations need data.\n\n### Pixel + Tracking Diagnosis Matrix\n\n| | EMQ < 5 | EMQ 5–6.9 | EMQ 7.0+ |\n|---|---|---|---|\n| **CAPI off** | Critical — flying blind | Critical — most events lost | High — leaving 15–25% of events on the table |\n| **CAPI on, dedup off** | Critical — duplicated and weak signal | High — duplicate counting risk | Medium — match quality improves with dedup |\n| **CAPI on, dedup on** | High — match quality is the bottleneck | Medium — improve event_id coverage | Healthy |\n\n## Phase 4 — Business context\n\nDerive what you can from the data already pulled:\n\n| Field | Source |\n|---|---|\n| `business_name` | Ad account name (`/{accountId}` `name` field) |\n| `services` | Top campaigns by spend, ad set names, top-converting ad creatives |\n| `locations` | Targeting geo summary (countries / regions in active ad sets) |\n| `brand_voice` | Top-performing ad copy (primary text + headline) |\n| `creative_inventory.formats` | Mix of image / video / carousel observed in active ads |\n| `creative_inventory.aspect_ratios` | Aspect ratios across active ads (1:1, 4:5, 9:16) |\n| `meta_funnel_events.conversion` | Most common optimization event on top-spending ad sets |\n| `custom_audiences` | Custom audiences referenced in active ad set targeting |\n| `pixel_health` | From the Pixel detail call |\n| `website` | Apex domain from active ad final URLs |\n\nThen crawl the website (homepage + about + 1–2 top landing pages, parallel `WebFetch`) and merge into the schema. See `references/business-context.md` for the full crawl procedure.\n\nAlways ask the user: differentiators, competitors, seasonality, **AOV + profit margin** (essential for ROAS-aware scoring). Ask for everything else only if data + crawl can't answer it.\n\n## Phase 5 — Personas\n\nDiscover 2–3 personas from creative performance (which angles convert), top-spending audiences, and landing-page content — all from the dataset already in memory. Persist to `{data_dir}/meta/personas/{accountId}.json`. Each persona must be grounded in **observable evidence** (a converting ad set, a converting creative angle, a landing-page section) — no inventing. See `references/persona-discovery.md`.\n\n## Phase 6 — Report\n\nLead with the verdict, then the top 3 actions (with dollar impact when possible), then the scorecard, then evidence for dimensions scoring 0–2 only. Cite specific campaigns, ad sets, ads, and dollar amounts. Cap at ~80 lines.\n\nEnd with a single closing line after the handoff to `/meta-ads`:\n\n> *Your audit history is saved to your NotFair account — view it at https://notfair.co.*\n\n## Guardrails\n\n1. **Read-only skill.** Diagnose; don't mutate. Every fix routes through `/meta-ads`. End the report with one handoff tied to the #1 action.\n2. **STOP condition** — if Pixel health scores 0–1 (EMQ < 5 or CAPI off in an ecom account), recommend pausing scaling decisions until tracking is fixed before recommending anything else. Everything downstream is unreliable.\n3. **Always persist** `meta/business-context.json` and `meta/personas/{accountId}.json` even if the report itself is short — downstream skills depend on them.\n4. **Name names.** Every finding cites specific campaigns, ad sets, ad creatives, and dollar amounts. \"Some ad sets are underperforming\" is not a finding.\n5. **Never report Meta-reported ROAS without footnoting the modeled-conversion premium.** \"ROAS 3.2× (Meta-reported, 7DC1DV — typically overstates Shopify-attributed ROAS by 20–40%)\" is honest. \"ROAS 3.2×\" is misleading.","author":"@nowork-studio","ownerProfile":null,"authorContacts":null,"sourceUrl":"https://github.com/nowork-studio/notfair-plugin/tree/main/meta-ads/audit","license":"MIT","category":"writing","lang":"en","tokens":2647,"stars":0,"calls30d":2,"claimed":false,"visibility":"public","origin":"crawler","version":"0.1.0","createdAt":"2026-08-22","updatedAt":"2026-08-22","files":[{"path":"references/account-health-scoring.md","size":9907,"sha256":"c78a45275db9260d1ed2bd2ef88e6c5ffdc59777d2c1a9505016b34e0162df53"},{"path":"references/business-context.md","size":7934,"sha256":"cd817432853602769ea22a1a34fd95d3f63025422db4af2c75252a7ce0c7f0f4"},{"path":"references/persona-discovery.md","size":6144,"sha256":"5750dea676ecd882aee9213acbcdb4790ba517c70bfac5d952d7c9fb602f4bc6"}],"requires":{"mcp":[],"tools":[]},"safety":{"flags":[{"code":"injection.preauthorise","kind":"injection","where":"references/business-context.md:58","excerpt":"always confirm","message":"pre-authorises approvals on the user’s behalf","severity":"warn"}],"scannedAt":"2026-08-22","hasScripts":false,"networkEndpoints":["notfair.co"]}}