google-ads-audit — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited google-ads-audit (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Diagnose account health and persist business context for downstream skills (/google-ads, /google-ads-copy, /google-ads-landing). Read-only — never mutates the account. The user runs /google-ads to execute fixes you recommend.
Follow ../shared/preamble.md (MCP detection, account selection) and ../shared/analysis-principles.md (evidence requirement, guardrails). Both apply throughout this skill.
| Artifact | Path | When |
|---|---|---|
| Business context | {data_dir}/business-context.json | First full audit, or refresh when audit_date is >90 days old. Skip on scoped audits if file is fresh. |
| Personas | {data_dir}/personas/{accountId}.json | Every full audit. |
These are the handoff to every other ads skill — write them even if the report is short. Otherwise /google-ads-copy and /google-ads-landing operate without business context and produce generic output.
business-context.json schema: 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[]}, keyword_landscape{high_intent_terms[], competitive_terms[], long_tail_opportunities[]}, social_proof[], offers_or_promotions[], landing_pages{}, unit_economics{aov_usd, profit_margin, source}, notes, audit_date, account_id.
personas JSON schema: {account_id, saved_at, personas: [{name, demographics, primary_goal, pain_points[], search_terms[], decision_trigger, value}]}. See references/persona-discovery.md.
Read ../shared/policy-registry.json. For each entry where last_verified + stale_after_days < today:
area for recent Google Ads changes; compare to assumption. If drift, banner the report and suggest registry update.Use a single runScript call with ads.gaqlParallel to fan out the queries an audit needs. The server's notfair://playbooks/audit-account resource has a battle-tested baseline; extend it with what your specific question needs.
You decide the exact GAQL shape, but a defensible audit needs to see, at minimum:
customer)campaign, 90-day cap for impression-share data)ad_group)keyword_view)search_term_view)campaign_criterion + shared sets)conversion_action) — including counting type, attribution model, primary/secondarysegments.ad_network_type) when diagnosing CPA/CVR shifts or Search Partnersad_group_ad)campaign_criterion LOCATION + PROXIMITY)change_event, last 30 days) — for explaining regressionsAggregate inside the script. Return summarized JSON, not raw rows. The agent narrates; the script does the math.
getRecommendations and summarizeAccountSetup are useful cross-checks against Google's own and the server's structural views — call them as a separate tool turn after the runScript pass when comparison would sharpen the report.
If a critical query errors out (auth, schema), surface the error and stop — don't fall back to a degraded audit.
Skip scoring entirely if totalSpend == 0 or activeCampaigns == 0. Go straight to business context.
If the user narrows the audit ("focus on one campaign", "campaign X", "just check waste"):
business-context.json is fresh.The audit's headline output is three pulse metrics — Waste ($/mo), Demand captured (%), CPA ($) — each annotated with its top contributor and a pointer to the fix. Read references/account-health-scoring.md for the formula, annotation rules, signal-failure overrides, and audit-history.json schema. The pulse metric IS the verdict; you don't add a letter grade or 0–5 score on top.
To compute and back the pulse metrics, you'll need to look across these seven areas. They are diagnostic surface area, not graded dimensions:
account-health-scoring.md); they're different problems with different fixes.For Signal Quality and network-mix questions, read references/conversion-network-audit.md. It adds the prerequisite checks for conversion-action integrity, Search Partners, Display leakage in Search campaigns, and regression decomposition.
Per-area findings only show up in the report when the area surfaced something material. Cite specific entities, dollars, and time windows. "Some keywords are underperforming" is not a finding; "Campaign X has $1,840 in last-30-day spend on 12 keywords with 0 conversions and QS ≤ 4" is.
For unit-economics-aware framing: if business-context.json.unit_economics.aov_usd and profit_margin exist, frame waste and headroom in dollars saved / captured per month, not "above account average". See ../shared/ppc-math.md.
Derive what you can from data already pulled:
| Field | Source |
|---|---|
business_name | customer.descriptive_name |
services | Campaign + ad-group names, top converting keywords |
locations | campaign_criterion LOCATION + PROXIMITY |
brand_voice | Top-performing RSA headlines / descriptions |
keyword_landscape.high_intent_terms | Converting keywords with strong CVR |
keyword_landscape.competitive_terms | Keywords in campaigns with high rank-lost-IS |
keyword_landscape.long_tail_opportunities | Converting search terms not yet promoted to keywords |
website | Apex domain from ad final URLs |
Then crawl the website (homepage + about + services + top 3 ad landing pages, parallel WebFetch) and merge into the schema. See references/business-context.md.
Ask the user — it's faster than guessing — for: differentiators, competitors, seasonality, unit economics (AOV, margin). Ask for everything else only if the data + crawl can't answer it.
Discover 2–3 personas from search terms, top keywords, ad-group themes, landing pages, geo, and device split — all from the dataset already in memory. Persist to {data_dir}/personas/{accountId}.json. Each persona must be grounded in 5+ actual search terms; if not, drop it. See references/persona-discovery.md.
Structure: pulse metrics (3 lines, each with number + top contributor + fix pointer) → per-area findings (only those that surfaced something material) → Quick Wins section (per the rules in references/account-health-scoring.md). Cap at ~80 lines. Every claim cites a specific entity, number, and window.
End with a single closing line after the handoff to /google-ads:
Your audit history is saved to your NotFair account — view it at https://notfair.co.
/google-ads (or /google-ads-copy, /google-ads-landing). End the report with one handoff tied to the #1 action.business-context.json and personas/{accountId}.json even if the report is short — downstream skills depend on them.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.