# Ad Account Audit

> Audit a paid search or paid social account export for conversion-tracking gaps, budget pacing outliers, disapproved and limited ads, naming-convention drift, negative-keyword coverage and stale creative, returning severity-ranked findings…

Ad Account Audit is an AI skill that you can use in Claude Code, Codex, or type.com.

- Skill page: https://typestaging.com/library/skills/ad-account-audit
- Raw SKILL.md: https://typestaging.com/library/skills/ad-account-audit/SKILL.md
- Created by the type.com team
- Updated: September 24, 2026
- Package: 9 files

## How to use Ad Account Audit

1. **type.com:** Choose Use Skill to add Ad Account Audit to your type.com workspace.
2. **Claude Code:** Download the skill and extract it into ~/.claude/skills/ad-account-audit/ (or .claude/skills/ad-account-audit/ in a project). Then ask Claude to use Ad Account Audit.
3. **Codex:** Download the skill and extract it into ~/.agents/skills/ad-account-audit/ (or .agents/skills/ad-account-audit/ in a repository). Then ask Codex to use Ad Account Audit.

## Frequently asked questions

### What is Ad Account Audit?

Ad Account Audit is an AI skill that you can use in Claude Code, Codex, or type.com.

### What does Ad Account Audit do?

Audit a paid search or paid social account export for conversion-tracking gaps, budget pacing outliers, disapproved and limited ads, naming-convention drift, negative-keyword coverage and stale creative, returning severity-ranked findings…

### Can I use Ad Account Audit in Claude Code or Codex?

Yes. Ad Account Audit is a standard Agent Skills folder with a SKILL.md file. Download it and extract it into ~/.claude/skills/ for Claude Code or ~/.agents/skills/ for Codex.

### Who created Ad Account Audit?

The type.com team created Ad Account Audit. The type.com team reviews every skill before it is published in the Skills Library.

## Example output

Example output from a sample run. Company names and figures are sample data.

```markdown
## Paid account audit: Aurora Bikeworks — Google Ads (US/CA), 2026-09-01 to 2026-09-21

**14 findings across 9 campaigns and $16,583 of spend.** $608 (3.7%) went to search terms that converted zero times and that no negative blocks, and $3,150 (19.0%) sits in a campaign with no recorded conversion. Conversion tracking covers 80.3% of spend.

| Bucket | Amount | % of spend |
| --- | ---: | ---: |
| Wasted spend | $608 | 3.7% |
| Unmeasured spend | $3,150 | 19.0% |
| Unspent capacity | $4,030 | 24.3% |
| Spend at risk | $7,290 | 44.0% |
| Unattributable by naming | $780 | 4.7% |

Buckets overlap by design, so don't add them together. Only wasted spend can be stopped outright.

| # | Severity | Campaign | Check | Finding | Impact |
| ---: | --- | --- | --- | --- | ---: |
| 1 | HIGH | AB_US_PMax_AllProducts | Conversion tracking | 4,200 clicks, zero conversions | $3,150 unmeasured |
| 2 | HIGH | AB_US_YouTube_Awareness | Ad approvals | Every enabled ad is disapproved | $2,100 at risk |
| 3 | HIGH | AB_US_YouTube_Awareness | Budget pacing | Delivering only 5.7% of its daily cap | $1,980 unspent |
| 4 | HIGH | AB_US_NonBrand_Search | Negative keywords | 2 unblocked terms, 0 conversions | $235 wasted |
| 5 | HIGH | AB_CA_NonBrand_Search | Negative keywords | 2 unblocked terms, 0 conversions | $208 wasted |
| 6 | HIGH | AB_US_Shopping_Core | Negative keywords | "ebike battery replacement", 0 conversions | $165 wasted |
| 8 | MEDIUM | AB_CA_NonBrand_Search | Negative keywords | No negative keywords configured | $2,520 at risk |
| 9 | MEDIUM | AB_US_Shopping_Core | Budget pacing | Delivering only 61.0% of its daily cap | $2,050 unspent |

…plus 6 more findings in the full report, including 150.0% over-delivery on AB_CA_NonBrand_Search and creative last touched 310 and 356 days ago.

**Next actions**
- **AB_US_PMax_AllProducts:** confirm the conversion action is enabled, set as a primary goal, and included in bidding. Re-audit after one full conversion window.
- **AB_US_YouTube_Awareness:** fix the policy violation on ad-101001 and ad-101002 or rebuild the ads. Until then, move the $100.00/day budget to a campaign that can serve.
- **Negatives:** block "how to fix a flat bike tire", "bike mechanic salary", "velo electrique occasion" and "bike insurance canada" as phrase negatives, and promote jobs, salary, free and DIY repair to the shared negative list.
- **AB_CA_NonBrand_Search:** apply the shared negative list as a baseline, then reconcile $120.00/day of spend against its $80.00 daily cap.

**Inputs:** campaigns, ads, keywords and search-terms exports. AB_US_Legacy_Remarketing (not enabled, $240) is in totals but excluded from every check.

_Produced by running `bash examples/run.sh` on the sample data bundled with this skill._
```

## Package files

- DATA_CONTRACT.md
- SKILL.md
- examples/data/ads.csv
- examples/data/campaigns.csv
- examples/data/keywords.csv
- examples/data/search_terms.csv
- examples/expected_output.txt
- examples/run.sh
- scripts/audit_account.py

## SKILL.md

````markdown
---
name: ad-account-audit
description: Audit a paid search or paid social account export for conversion-tracking gaps, budget pacing outliers, disapproved and limited ads, naming-convention drift, negative-keyword coverage and stale creative, returning severity-ranked findings with the dollars each one puts at issue.
---

# Ad account audit

Runs six hygiene checks against four local exports and returns a ranked findings
list. Every finding names the campaign, shows the evidence it was derived from,
attaches a dollar figure, and states the fix.

## Before you run

This skill ships scripts and sample data alongside this SKILL.md. Before running any command:

1. **Get the files.** Make sure the skill's other files (`scripts/`, `examples/` and anything else listed with this skill) are in your working folder at the same relative paths. Some environments load only SKILL.md; if yours did, fetch each file from this skill's published files and write it to the matching path. In Type, read them with the skill-file tools. Anywhere else, the Type Skills Library API lists every file with its path, content and `sha256`: GET `https://api.type.com/api/public/library/skills` and take the entry with slug `ad-account-audit`.
2. **Check the copies are exact.** Compare each file's size in bytes, not characters (and its hash, where your tools report one), with the published version before running. A copy written out from the published file is fine once its byte size and hash match; never run a script you summarised or reconstructed from memory.
3. **Run from the skill's folder**, calling interpreters explicitly: `python3 scripts/…` and `bash examples/run.sh`.
4. **Try the sample first.** If the skill ships `examples/run.sh` and `examples/expected_output.txt`, run `bash examples/run.sh`; its output should match the expected file exactly. If it doesn't, stop and report the first differing line rather than running on real data.

## When to use this

- Onboarding a new account and needing a defensible first-week findings list.
- A recurring (monthly or quarterly) hygiene pass on accounts under management.
- Performance dropped and the first question is whether the account is broken
  rather than the market.
- Preparing a pitch: run it on a prospect's export to ground the conversation in
  their numbers. (`new-business-pitch-builder` turns the opportunity into a
  proposal; this skill finds the problems.)

## Gathering the inputs

Four CSVs, all for the same account and the same date range. Exact columns are
in `DATA_CONTRACT.md`. The script reads local files only — it never calls an ad
platform and never handles credentials.

1. **`campaigns.csv`** — campaign report for the period, with status, daily
   budget, spend and conversions. Google Ads: Campaigns view with the date range
   set. Meta Ads: Campaigns tab with Amount Spent, Results and Budget columns.
2. **`ads.csv`** — ad-level export including `ad_status`, `approval_status` and
   `last_modified`. In Google Ads the policy column is "Status details"/"Policy
   details"; map it to `APPROVED`, `LIMITED`, `DISAPPROVED` or `UNDER_REVIEW`.
   In Meta, map "Active", "Rejected" and "In Review" to the same four values.
3. **`keywords.csv`** — targeting keywords and negative keywords, with match
   type. Use `list_type=negative` for negatives and the literal campaign name
   `ACCOUNT` for shared/account-level negative lists.
4. **`search_terms.csv`** — search terms report for the same period, with spend,
   clicks and conversions per term.

**Paid-social accounts (Meta, TikTok, LinkedIn) have no keywords or search
terms.** Pass `keywords.csv` and `search_terms.csv` containing only their header
rows (copy the first line of the files in `examples/data/`). The audit then
skips the search-term waste and negative-keyword checks and lists them under
"Audit notes" as not applicable; the other four checks run normally. Wasted
spend will read `$0` because it was not measured, not because none exists.

Set `--period-start` and `--as-of` to the exact first and last day of the export
window. Pacing arithmetic uses that day count, so a mismatch between the export
window and the flags produces wrong pacing findings.

## Running it

First run: `bash examples/run.sh` audits the bundled sample account in
`examples/data/`. To reproduce it by hand, or to point it at your own exports
(replace the `examples/data/` paths with wherever you saved them):

```bash
python3 scripts/audit_account.py \
  --campaigns examples/data/campaigns.csv \
  --ads examples/data/ads.csv \
  --keywords examples/data/keywords.csv \
  --search-terms examples/data/search_terms.csv \
  --account "Aurora Bikeworks — Google Ads (US/CA)" \
  --period-start 2026-09-01 \
  --as-of 2026-09-21
```

Tuning flags, all with defaults that suit a mid-size account:

- `--naming-pattern` (default `{brand}_{geo}_{funnel}_{type}`) — set it to the
  agency's actual convention. Ask the user rather than guessing; a wrong pattern
  turns every campaign into a false positive.
- `--pace-tolerance` (default `0.25`) — fraction above or below the daily cap
  before pacing is flagged.
- `--tracking-floor` (default `300`) — minimum campaign spend before a
  zero-conversion campaign is reported.
- `--term-floor` (default `50`) and `--waste-share-high` (default `5` percent) —
  minimum per-term spend to count as waste, and the share of campaign spend at
  which uncovered waste escalates to high severity.
- `--stale-days` (default `90`) and `--material-spend` (default `500`).
- `--json` — same analysis, machine-readable.

## Reading and presenting the output

- **Spend at issue** splits dollars into five buckets that deliberately do not
  sum: wasted, unmeasured, unspent, at risk, and unattributable by naming. Only
  *wasted* is money that can be stopped outright. Quote that number in client
  conversations and describe the others in their own terms — presenting the sum
  as "money we found" is the fastest way to lose credibility on the follow-up.
- **Findings** are sorted by severity, then by dollars. Work them top-down. Each
  finding's evidence lines are quotable in a client email as-is.
- **Checks that passed** exists so the audit reads as a complete pass rather
  than a list of complaints. Keep it in the deliverable.
- **Audit notes** records what could not be checked (campaigns with no ad rows,
  shared budgets, paused campaigns, and search-term checks skipped for
  paid-social accounts). Close those gaps before claiming full
  coverage.

Before sending, sanity-check the highest-value finding against the live account.
Exports go stale, and a disapproval that was fixed yesterday still appears in
yesterday's file.

## Limits

- It audits structure and delivery hygiene, not strategy. It has no opinion on
  offer, landing page, audience choice or creative quality.
- Negative-keyword matching approximates the platforms' own matching (exact,
  phrase, broad) on tokenized text. It ignores close variants, plurals, stemming
  and misspellings, so it can report a term as uncovered that a platform would
  in practice have blocked.
- Shared budgets and portfolio bid strategies are not modeled. Campaigns with no
  daily budget are skipped for pacing and listed in the notes.
- Wasted spend is measured against the exported period only. It is not
  annualized, and it is not a savings guarantee — blocking a query moves budget,
  it does not always remove it.
- Zero conversions on real spend is reported as *unmeasured*, never as proven
  waste. The skill cannot tell a broken tag from a genuinely unproductive
  campaign.
- One account per run. There is no cross-account rollup.
````
