snitch-adsready
The ads-ready.sh beside this SKILL.md exposes thin tools. Read tools emit JSON on stdout;
doctor and the proposal-generating fix tools emit status badges instead. Run
bash "${CLAUDE_SKILL_DIR}/ads-ready.sh" help for the full surface.
Ten platforms are tool-backed: Google, Meta, Microsoft, LinkedIn, TikTok, X, Pinterest, Reddit,
Snapchat, Apple. One more — ChatGPT ads — is presence-only: no pixel exists, so readiness there
is crawlability and page quality (references/10-capability-matrix.md).
Setup
- No mandatory secrets. Public-URL audits use curl + jq.
- Optional, raises quotas / unlocks platform reads:
PSI_API_KEY— PageSpeed Insights (CrUX + Lighthouse scores). Without it the anonymous quota runs out fast andstate cruxreturnsE_PSIwith status 429.lighthouseCLI —npm i -g lighthousefor full audit JSON.GOOGLE_GSC_AUTH,GA4_AUTH— Search Console / GA4 refresh-token JSON.- Per-platform Marketing API env (see
prereqsfor the exact names):GOOGLE_ADS_*,META_ACCESS_TOKEN+META_AD_ACCOUNT_ID,MICROSOFT_ADS_*,LINKEDIN_ADS_*,TIKTOK_ADS_*,X_ADS_*,PINTEREST_ADS_*,REDDIT_ADS_*,SNAPCHAT_ADS_*,APPLE_SEARCH_ADS_*.
- Refuses any global / legacy
API_KEYenv — see Guardrails. - Runtime state (findings, the API call log, snapshots, the
refresh-docscache) is written to${XDG_STATE_HOME:-$HOME/.local/state}/snitch-adsready, never into the skill folder.
Tools
Read-only, JSON on stdout, errors as JSON on stderr:
| Subcommand | Returns |
|---|---|
detect |
cwd signals: stacks[], pixel_libs[], pixel_snippets[], consent_libs[], vertical_hints[], hostnames[], package_managers[], current_host_provider, project_kind |
state site <url> [slice] |
site fetch + parse for all 10 platforms in one pass. Slices: digest (default), html, headers, pixels, consent, structured-data, robots, sitemap, ads-txt, lead-capture, full |
state crux <url> [mobile|desktop] |
CrUX field data + Lighthouse lab scores via PSI |
state lighthouse <url> |
full Lighthouse audit JSON if the CLI is installed; a nested state crux document otherwise |
state platform <name> [account-id] |
per-platform Marketing API state. <name> ∈ google|meta|microsoft|linkedin|tiktok|x|pinterest|reddit|snapchat|apple. Emits {locked:"<platform>-api"} when the auth env is unset — that is a Skip, not a Finding |
state gsc [property] |
Search Console state if GOOGLE_GSC_AUTH is set |
analytics ga4 <property-id> |
GA4 Data API report if GA4_AUTH is set |
fit-matrix [stack] |
stack integration hints; not measured readiness |
stack-docs [stack] |
canonical doc URLs (for WebFetch) |
score <url> |
heuristic composite: pixel × CWV × consent × structured data × headers × ads.txt |
Badges on stdout, not JSON — never pipe these into jq:
| Subcommand | Behavior |
|---|---|
doctor |
env health (curl, jq, lighthouse, PSI key, per-platform auth), one badge per check |
fix <area> [platform] |
apply one area for one platform (or all detected). Areas: pixel-install consent-mode capi-stub ads-txt robots structured-data security-headers mobile-meta verification-meta all. No flags — fix structured-data emits the Product/Offer feed starter and takes ecommerce as a positional to force it |
Setup help:
| Subcommand | Behavior |
|---|---|
setup <area> [platform] |
stepped JSON walkthrough: pre-checks → ordered steps (auto via fix, manual dashboard, external-tool installs) → verification |
recommend <area> |
tool catalogs: cmp, gtm-server, capi-helpers, lighthouse-runner, cwv-monitoring. Each option: name, vendor, pricing, install, pros, cons, recommended-for |
prereqs |
local CLI / platform accounts needed, with per-OS install hints |
Utility: export <url>, verify <url>, refresh-docs, help. export and verify both
require a URL and fail with E_USAGE without one.
Evidence rule
Three outcomes per check — Finding, Pass, or Skip — and each one carries its proof.
- Every row cites where the verdict came from. In crawl mode that is the URL plus the exact
JSON field and its value (
.pixels.meta.detected = false). In source mode it isfile:lineplus the matched snippet. Quote the field, not a paraphrase of it. - A Pass carries evidence too — what was read and what came back clean. A bare "OK" is not a Pass.
- A Skip carries the reason and what would unblock it —
{locked:"meta-api"}means "setMETA_ACCESS_TOKEN", not "N/A".
Interpret the evidence before grading. Missing initial-HTML pixel/CMP signatures do not prove absent runtime wiring. Inspect the relevant consent states, tag-manager configuration, network events, navigation, and deduplication before reporting a behavioral defect. An installed tag does not prove conversions reach the intended account. Cite supplied traces as supplied, not as tests you ran. Select required platforms from the user's plan; unused platforms and publisher-only ads.txt on an advertiser site are Skip, not missing features.
score is a heuristic composite, not a Finding: report the components and weights so the
reader can check the arithmetic, and never let a letter grade stand in for evidence.
references/30-recipes.md carries the full report format.
How to use
Classify intent (audit, set up tracking, verify a fix, recommend a tool, plan a migration).
Call the smallest set of tools. Prefer
state site <url>digest first — it covers all 10 platforms in one fetch. Addstate cruxandscoreonly when CWV or a composite is needed.Lazy-load the reference for each finding — see the area map below.
Synthesize the report per
references/30-recipes.md. Group by area; sort 🔴 FAIL → 🟡 WARN → ⚪ SKIP → 🟢 PASS.For every FAIL, offer to set it up. The mandated prompt is: "Want help setting this up? I can run
setup <area> [platform]for a stepped plan."When the user accepts, call
setup <area> [platform]for the JSON plan, present each step in order, get confirmation per step, chainfixcalls for auto steps, link to dashboards for manual ones.For project file changes (
fix pixel-install,fix consent-mode,fix capi-stub,fix ads-txt,fix robots,fix structured-data,fix security-headers,fix mobile-meta,fix verification-meta), the tool emits proposed contents + a diff:=== FILE: <relative-path> === === DIFF === <unified diff> === CONTENT === <full proposed file body> === END ===Apply with
Edit/Writeafter the user confirms. The skill never writes inside the user's project. For platform-side secrets (CAPI tokens, MP secrets), the tool emits the dashboard URL and the env-var name — never type secret values yourself.
Area → reference map
Read the file whose area produced a finding. Nothing else.
| Area | Reference |
|---|---|
| orchestration, report format, evidence rule | references/30-recipes.md |
| the JSON each subcommand emits | references/31-tool-contracts.md |
| auth, tokens, per-platform API versioning | references/01-auth-and-tokens.md |
| pixel install, load order, dedup | references/02-pixel-foundations.md |
| conversion events, CAPI, offline import | references/03-conversion-tracking.md |
| consent, CMP, Consent Mode v2 | references/04-consent-and-cmp.md |
| Quality Score and engagement signals | references/05-quality-and-engagement-signals.md |
| Core Web Vitals targets and fixes | references/06-core-web-vitals.md |
Product/Offer markup a shopping feed reads |
references/07-structured-data.md |
| ads.txt / app-ads.txt | references/08-ads-txt.md |
| where a setting lives in each platform UI | references/09-platform-dashboards.md |
| what is free vs paid vs API-gated | references/10-capability-matrix.md |
| Google API specifics | references/11-google-apis-cheatsheet.md |
| tracking incidents, status pages | references/13-incident-response.md |
| API quotas and where the bill lands | references/14-cost-and-budgets.md |
| per-framework install patterns | references/15-stack-best-practices/<stack>.md |
| server-side tag manager | references/16-tag-manager-server-side.md |
| AI crawler access, the ChatGPT-ads surface | references/17-ai-crawler-access.md |
| mobile meta, per-region ad rules | references/18-mobile-and-international.md |
| per-vertical expectations | references/25-verticals/<vertical>.md |
| one platform's specifics | references/platforms/<name>.md |
| a stepped setup walkthrough | references/setup/<area>.md |
| a tool catalog | references/recommendations/<area>.md |
Guardrails
- Refuses generic / global API key shapes (
API_KEY=without a platform prefix,*_GLOBAL_KEY); redirects to scoped OAuth refresh tokens or service-account credentials per platform. - No pixel before consent.
fix pixel-installrefuses to propose a tracking pixel into a project with no consent banner / CMP signal — it FAILs and points atfix consent-modeandrecommend cmpinstead.fix allruns consent before pixels for the same reason. - Never lowers posture in a
fix. No removing an existing CSP, no overwriting an existingads.txtwith fewer lines. A fix adds or it stops. - Never mutates ad campaigns. No pausing, no bid changes, no creative. The skill reads, and sets up tracking. Campaign management belongs in the platform UI.
- Never verifies billing. It audits readiness, not whether a charge succeeded.
- Search surfaces are not judged here. Schema beyond the
Product/Offera shopping feed reads, llms.txt and AI-search content, hreflang and localized landing pages, AI-crawler policy for the non-ad assistants, and free business-listing profiles all belong to the marketing audit — when a finding lands there, call the Skill tool with "snitch-marketing" instead of grading it. fixis idempotent — a re-run no-ops when the target state is already met.- Site-side parsers don't store fetched HTML on disk; the
htmlslice prints the body but does not cache it. - Respects
robots.txton the audited site; identifies asads-ready-skill/1. - A framework name cannot prove tracking or CWV failure.
fit-matrixis integration context, not a migration gate. Recommend stack changes only against measured problems and the user's constraints; never install extra pixels, schema blocks, or sellers merely to raise a score. - Missing performance evidence is unknown, not zero performance. Keep lab, URL field, and origin field data distinct; do not describe a lab score as field CWV conformance.
- Apple Search Ads / SKAdNetwork is iOS-only; with no iOS app, mark
apple⚪ SKIP with the reason — don't manufacture work. - For an actual ad-account compromise, use the platform's native security tooling. Tracking
incidents (conversions stopped, pixel stopped firing) are in scope — see
references/13-incident-response.md.