# Skill: negative-keyword-builder

## Purpose

Takes Google Ads search term data, applies zero-conversion and spend-waste rules, and produces a **paste-ready negative keyword list** organised by match type and scope (account-level vs campaign-level). One input, one output — ready to paste into Google Ads Editor or add directly in the UI.

This skill does not evaluate search terms for bid optimisation or new keyword discovery. Use **search-auditor** for that. This skill only identifies what to block.

> **Read-and-recommend only.** This skill never modifies keyword lists in the account. All changes are applied manually by the user.

---

## When to Use This Skill

Use when the user says:
- "Build me a negative keyword list"
- "Which search terms should I be blocking?"
- "I'm wasting spend on irrelevant searches"
- "Clean up my search terms"
- "I need negatives for my [campaign]"

---

## Step 0 — Data Inventory

Before proceeding, confirm:

1. **Data source** — MCP (GoMarble GAQL `search_term_view`) or CSV (Google Ads Search Terms report)?
2. **Date range** — Minimum 14 days. 30 days preferred. Shorter ranges miss low-impression waste.
3. **Account CPA or ROAS target** — needed to set the spend waste threshold. Ask the user if not visible.
4. **Campaign scope** — Are we building negatives for one campaign, a subset, or the whole account?
5. **Existing negative lists** — Ask if the account already has a negative keyword list applied. Terms already blocked don't need to be added again.

---

## Flagging Logic — Which Search Terms to Block

Apply the following rules in order. A term that qualifies under any rule gets flagged for blocking.

### Rule 1 — Zero-conversion waste

| Condition | Flag |
|---|---|
| Spend > (CPA target × 1.5) AND conversions = 0 | FLAG — confirmed waste |
| Spend > (CPA target × 0.75) AND conversions = 0 AND impressions > 50 | FLAG — likely waste |
| Spend > $20 AND conversions = 0 AND the query is clearly non-commercial (see intent check below) | FLAG — intent mismatch |

**If no CPA target is available:** use $50 as a conservative default spend threshold and flag it as such in the output.

### Rule 2 — Intent mismatch (no spend threshold required)

Flag any search term that contains the following patterns regardless of spend — these signal users who will never convert:

- Informational: "how to", "what is", "guide", "tutorial", "tips", "examples", "learn", "explain"
- Free-seeking: "free", "no cost", "open source", "without paying"
- Job-seeking: "jobs", "salary", "career", "hiring", "resume", "vacancy"
- Competitor + "reviews" without buying signal: "[competitor] review", "[competitor] complaints", "[competitor] bad"
- Navigational: searches that are clearly trying to reach a different brand's website

### Rule 3 — Low CTR / high impression waste

| Condition | Flag |
|---|---|
| Impressions > 200 AND CTR < 0.3% AND conversions = 0 | FLAG — the ad is being shown to people who consistently ignore it |

---

## Scope Assignment — Account vs Campaign Level

Once terms are flagged, assign scope:

**Account-level negative** (add to all campaigns): The query is so irrelevant that it should never trigger any ad in the account.
- Criteria: intent mismatch terms (Rule 2), or the query has wasted spend in ≥ 2 different campaigns.

**Campaign-level negative** (add only to the specific campaign where it appeared): The query is only irrelevant for this campaign's objective, but might be valid elsewhere.
- Criteria: Rule 1 or Rule 3 terms that appeared in only one campaign and are not clear intent mismatches.

If unsure, default to campaign-level to avoid over-blocking.

---

## Match Type Assignment

For each flagged term, assign the correct negative match type:

| Scenario | Match Type | Logic |
|---|---|---|
| The exact query string should never trigger an ad | Exact | Use when the full phrase is the problem |
| Any query containing a specific word or phrase should be blocked (e.g. "free") | Phrase | Use for intent-mismatch words |
| A single irrelevant root word should be blocked in any combination | Broad | Use sparingly — broad negatives can over-block |

**Default rule:** Start with Exact for specific queries, Phrase for intent-mismatch words. Avoid Broad negatives unless the term is clearly toxic in any combination.

---

## Output Format

```
NEGATIVE KEYWORD LIST
Period analysed: [date range]
Campaign(s): [name(s)]
Spend analysed: $[total]
CPA target used: $[X] (stated / estimated)

────────────────────────────────
ACCOUNT-LEVEL NEGATIVES
(Add to shared negative list — applies to all campaigns)
────────────────────────────────

[keyword] | [Phrase] | Intent mismatch: [rule triggered]
[keyword] | [Phrase] | Intent mismatch: [rule triggered]
[keyword] | [Exact] | Wasted $[X] across [N] campaigns, 0 conversions

Subtotal: [N] terms

────────────────────────────────
CAMPAIGN-LEVEL NEGATIVES
[Campaign Name]
────────────────────────────────

[keyword] | [Exact] | $[spend], 0 conversions, [N] impressions
[keyword] | [Exact] | $[spend], 0 conversions
[keyword] | [Phrase] | CTR [X]%, [N] impressions, 0 conversions

Subtotal: [N] terms

────────────────────────────────
SUMMARY
────────────────────────────────

Total negatives to add: [N]
Estimated monthly waste blocked: $[X]
  (based on last [N]-day rate of $[Y]/day on flagged terms)

Terms not flagged: [N] terms reviewed, [N] had conversions or insufficient data — left active.

────────────────────────────────
HOW TO ADD THESE
────────────────────────────────

Option A — Google Ads Editor:
  1. Open Shared Library > Negative Keyword Lists
  2. Create or open the relevant list
  3. Paste the account-level terms above
  4. For campaign-level: go to each campaign > Negative Keywords > add the list above

Option B — Google Ads UI:
  1. Campaign > Keywords > Negative Keywords
  2. Add at campaign or account level as indicated above
```

---

## Guardrails

- Do not block branded terms (competitor names) without asking the user. Some accounts intentionally bid on competitor names and blocking them as negatives would conflict with that strategy.
- Do not flag terms that have conversions, even if CPA is high. High-CPA terms are a bid/targeting issue, not a blocking issue.
- Do not add negatives that would block all traffic to a campaign. Before outputting, apply a sanity check: if these negatives were in place, would any legitimate traffic still reach the account?
- Do not recommend broad negatives for any term that contains the product or service category name.
- If date range is < 14 days, flag the output as provisional — the spend waste estimate will be understated.

---

## Minimum Required Data

| Source | What You Need |
|---|---|
| MCP (GoMarble GAQL) | `search_term_view` query with: `search_term`, `metrics.cost_micros`, `metrics.conversions`, `metrics.impressions`, `metrics.clicks`. Segment by `campaign.name` to enable scope assignment. Date range: 14–30 days. |
| CSV | Google Ads Search Terms report (separate from Campaigns report). Must include: Search term, Campaign, Impressions, Clicks, CTR, Cost, Conversions. Date range: 14–30 days. Note: this is NOT the Keywords report — it's the Search Terms report specifically. |
