# Negative Keyword Engine

> The single skill for all Google Ads negative keyword and search term work, with three modes: Audit (find wasted spend in a search terms report), Leakage (find systematic gaps in existing negative lists), and Mine (proactively build a comprehensive negative list for new campaigns or overhauls). Use this skill whenever the user wants to analyze, audit, or clean up search terms, find wasted ad spend, identify irrelevant queries, build or expand a negative keyword list, audit their negatives, or asks anything like "why is my CPA bad", "where is my budget leaking", "review my search terms", "what negatives should I add", "what should I be blocking", "negative keyword gaps", or uploads a Google Ads search terms report (CSV/Excel). Trigger even when the user doesn't say "negative keywords" explicitly: any request involving search terms data, PPC waste reduction, or blocking irrelevant traffic qualifies.

- Skill: `kochellenk-afk/negative-keyword-engine` (Agent Skill)
- Install (CLI): `npx skillmds@latest add kochellenk-afk/negative-keyword-engine`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kochellenk-afk/negative-keyword-engine/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Data & Analytics
- Author: kochellenk-afk (https://skillmd.com/u/kochellenk-afk)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kochellenk-afk/negative-keyword-engine

---


# Negative Keyword Engine

Three lenses on one problem: money leaving a Google Ads account through
irrelevant queries. Pick the mode, or combine them.

## Mode selection

| Mode | Question it answers | Data needed | Use when |
|---|---|---|---|
| **Audit** | Which specific terms wasted money? | Search terms report | Waste already happened; reactive cleanup |
| **Leakage** | What patterns keep slipping past my negatives? | Search terms report AND existing negative lists | Deeper structural review of blocking coverage |
| **Mine** | What should I block before waste happens? | Keywords + business description | New campaigns or a major list overhaul |

Selection heuristics:
- Search terms report only, "find the waste" → **Audit**
- Search terms report + existing negative lists, or "audit my negatives" /
  "leakage" / "gaps" → **Leakage**
- New campaign, "build me a list", "starter negatives", no search terms data
  yet → **Mine**
- "Do a full cleanup" or ambiguous with rich data → run **Audit** then
  **Leakage**, and offer **Mine** for the proactive layer

State which mode(s) you're running at the top of the response.

## Shared required inputs (all modes)

1. **Product/service description**: what they sell and who buys it. Without
   this, "irrelevance" cannot be judged. NEVER guess it from search terms
   alone. If missing, ask before analyzing.
2. **Competitor strategy**: does the user intentionally bid on competitor
   brands? Affects whether competitor names become negatives. Ask if unclear.
3. **Existing negatives** (required for Leakage, strongly recommended for
   Audit and Mine to avoid duplicate recommendations).

## Shared rules (all modes)

- **Never recommend blocking a term with any conversions.** Conversions mean
  the waste isn't waste.
- **State your thresholds and assumptions at the top** so the user can
  challenge them.
- **Quantify recoverable spend in dollars per month**, not percentages. If
  lookback is 7 days, extrapolate with ~4.3x and say so.
- **Don't recommend pausing keywords or campaigns.** Negatives only; bidding
  and structure are other skills' jobs.
- **Don't claim Quality Score impact** unless the data includes QS columns.
- **Plain language.** Not "match type semantic drift" but "this broad-match
  keyword is pulling in unrelated queries."

---

## MODE 1: Audit (reactive waste finder)

### Step 1: Gather inputs

If not already provided, ask in one message:

> Before I run the audit, I need three things:
> 1. **What do you sell, and who's the buyer?** (one sentence is fine)
> 2. **The search terms report**: CSV/Excel upload, or live via Google Ads MCP
> 3. **Thresholds**: I default to flagging $25+ spend with zero conversions,
>    and CTR under 1% over 100+ impressions. Adjust for your account size?

### Default thresholds

| Threshold | Default | When to lower |
|---|---|---|
| Min spend with zero conversions | $25 | Account <$2K/month → $10 |
| Min CTR floor | 1.0% | Brand campaigns → 0.5% |
| Min impressions for CTR check | 100 | Account <$2K/month → 50 |
| Lookback | Last 30 days | User specifies otherwise |

### Step 2: Load and validate data

Required columns (or close equivalents): Search term, Match type,
Campaign/Ad group, Impressions, Clicks, CTR, Cost, Conversions, Cost/conv.

Handle export variations: "Conv." vs "Conversions", currency symbols ($, £,
€), comma thousand separators, percent signs in CTR, different locales. For
Excel use pandas with openpyxl. If columns are missing, name exactly which and
how to re-export. Don't guess column meaning.

### Step 3: Four flagging rules

1. **High-spend zero-conversion**: `Cost >= min_spend AND Conversions == 0`
2. **Irrelevant to offering**: semantic check against the product description.
   Common patterns: "free", "jobs", "salary", "DIY", "how to", competitor
   names (unless intentional), wrong-vertical terms.
3. **Low CTR**: `Impressions >= min_impressions AND CTR < min_ctr AND Cost > 0`
4. **Duplicate/cannibalizing**: same or near-identical term triggering across
   multiple ad groups, splitting spend.

A term can hit multiple rules; list all that apply.

### Step 4: Outputs (always both)

**A. Markdown findings table**, sorted by spend descending, grouped by theme
where possible:

| Search term | Spend | Impr. | Clicks | CTR | Conv. | Reason flagged | Recommended match type |

Follow with **total recoverable monthly spend** and a count summary by reason.

**B. Google Ads Editor-ready CSV** saved to
`/mnt/user-data/outputs/negative-keywords-import.csv` and shared via
present_files. Format spec below.

If the user said "just markdown", skip the file. If they asked for "a
deliverable", also produce a Word doc summary via the docx skill.

---

## MODE 2: Leakage (systematic gap finder)

### Step 1: Validate inputs

This mode needs TWO data sources. If existing negatives are missing, stop and
ask:

> I need both your search terms data AND your existing negative keyword lists
> to find leakage gaps. Without knowing what you already block, I'd recommend
> negatives you've already added. Please export:
> 1. Search terms report (last 30 days minimum)
> 2. Shared negative lists (Tools & Settings → Shared library)
> 3. Campaign-level negatives (per-campaign export)

Never run a leakage scan on incomplete data; the output would be misleading.

### Step 2: Filter already-blocked terms

For every search term, check whether an existing negative already covers it
(account, campaign, or ad group level, with correct match-type semantics).
Drop covered terms. What remains is the actual leakage.

### Step 3: Cluster into themes

Group remaining irrelevant terms by theme:

- **Information-seeker:** "how to", "what is", "guide", "tutorial", "examples"
- **Free/cheap:** "free", "cheap", "discount", "coupon", "promo code"
- **Job-seeker:** "jobs", "salary", "career", "hiring", "resume"
- **DIY:** "DIY", "build your own", "from scratch", "homemade"
- **Wrong industry/vertical:** matches a different product type entirely
- **Competitor brands:** company names competing in the space
- **Geographic outside service area**
- **Wrong intent:** commercial keyword pulling informational research queries

Clustering discipline: three search terms isn't a theme; ten is. Below ten,
treat as one-offs and handle them in Audit mode instead.

### Step 4: Per-theme blocking plan

| Field | Content |
|---|---|
| Theme name | Plain-language label |
| Top 5 example terms | With spend |
| Total theme spend | Last 30 days |
| Recommended negatives | Keywords with match types |
| Scope | Shared list / campaign-level / specific campaigns |

### Step 5: Match-type gap analysis

For broad-match keywords in the account: are they triggering terms with very
low semantic similarity? Does any single broad-match keyword account for >30%
of total waste? If yes, recommend switching to phrase/exact OR adding
aggressive theme-level negatives.

### Step 6: Cross-campaign bleed

Find terms appearing in multiple campaigns splitting spend. Recommend
consolidating negatives into a shared list applied across relevant campaigns.

### Step 7: Brand contamination

If non-brand campaigns receive branded queries, recommend exact-match brand
negatives (plus misspellings/variants) on all non-brand campaigns, and verify
the terms exist as positives in the brand campaign.

### Step 8: Implementation plan output

1. Top-line recoverable spend ($/month if all gaps closed)
2. Theme summary table sorted by spend impact
3. Detailed theme breakdowns
4. Match-type gap findings
5. Cross-campaign bleed findings
6. Brand contamination findings
7. The Editor-ready CSV (format below)

Warn about close-variant risk whenever recommending broad-match negatives,
especially brand-adjacent terms.

---

## MODE 3: Mine (proactive list builder)

### Step 1: Gather context

If the user just said "build me a negative keyword list":

> Before I build the list, I need:
> 1. **What do you sell, and who buys it?** (a paragraph is fine)
> 2. **Industry/vertical**: be specific (not "SaaS" but "B2B project
>    management SaaS for engineering teams")
> 3. **Top 20 keywords** or a keyword report
> 4. **Existing negatives**: attach so I don't duplicate
> 5. **Service area**: global, US-only, specific cities?
> 6. **Competitor strategy**: bid on competitor names, or block them?

### Step 2: Generate from five signal sources

**A. Search terms data** (if available): apply Audit-mode logic for
demonstrated waste.

**B. Industry-standard negatives** for the vertical. Think through what most
accounts in this industry block: for B2B SaaS that's typically job-seeker
terms, "free"/"open source" (relevance-check first), academic/definition
queries, wrong-scale modifiers. For local services: out-of-area geos, DIY,
supplier/wholesale terms. Always relevance-check: "free" is right for premium
SaaS, wrong for a free-tier product.

**C. Semantic neighbors** of each top keyword with WRONG intent. For "CRM
software": right intent is "best CRM", "CRM pricing"; wrong-intent neighbors
are "CRM jobs", "CRM definition", "what is CRM".

**D. Competitor brands**: ONLY if the user said they don't want competitor
traffic. If they bid on competitors intentionally, skip entirely. Don't guess.

**E. Geographic negatives** if the service area is limited. But recommend
fixing location targeting FIRST; negatives are the workaround, not the fix.

### Step 3: Deduplicate against existing negatives

Drop anything already covered (with correct match-type semantics).

### Step 4: Categorized output

```
## Industry-standard negatives
## From your search terms data
## Semantic neighbors of your keywords
## Competitor brands (if applicable)
## Geographic exclusions (if applicable)
```

For each negative: keyword, match type, recommended scope, one-sentence
reason.

If the list exceeds 100, lead with a summary line (counts per category plus an
order-of-magnitude monthly waste-prevention estimate, clearly labeled as
approximate). Quality discipline: 50 well-chosen negatives beat 500 sloppy
ones.

### Step 5: CSV output

Save to `/mnt/user-data/outputs/negative-keywords-mined.csv`, default scope
shared list, present via present_files.

---

## Match-type strategy (all modes)

- **Exact** `[term]`: one-off waste, terms that should only block on exact
  match, brand-adjacent blocks where close variants are risky.
- **Phrase** `"term"`: multi-word irrelevant patterns where word order matters
  ("how to make").
- **Broad** `term`: theme-level kills ("jobs" blocks "marketing jobs", "ppc
  jobs"). Highest reach, highest close-variant risk. Always flag the risk when
  recommending broad negatives near brand or converting terms.

Bias: exact for one-offs, broad for theme cleanup, phrase in between. Note the
choice's rationale wherever it isn't obvious.

## Google Ads Editor CSV format (all modes)

Generate with pandas. One row per negative. Columns, exactly:

```
Action,Campaign,Ad group,Keyword,Criterion Type,Status
```

- `Action`: "Add"
- `Campaign`: campaign name for campaign-level negatives; leave blank rows out
  of shared-list files (shared lists import separately: use columns
  `Action,Keyword list name,Keyword,Criterion Type` with list name)
- `Ad group`: only for ad-group-level negatives, else empty
- `Keyword`: the term, no brackets or quotes (match type is its own column)
- `Criterion Type`: "Negative Exact", "Negative Phrase", or "Negative Broad"
- `Status`: "Enabled"

If recommendations span scopes, produce one CSV per scope and say which import
screen each goes into.

