Cut Google Ads spend on search terms that never convert

Every Wednesday, the search terms that cost money over 30 days with zero conversions, a proposed negative keyword for each, and one question: add them?

Runs
Wednesdays at 10:00
Posts
Asks you

From your apps to your board

How the skill works: your agent reads 30 days of search terms from Google Ads; google ads customer id, negative keyword list from What you tell it, wednesdays at 10:00, and gives you a question for you and a telegram ping and the report in the chat.

Reads

  • Google Ads30 days of search terms
  • What you tell itGoogle Ads customer ID, Negative keyword list
reads
Your agentClaude Code, Codex, Cursor or GeminiWednesdays at 10:00
posts

You get

  • A question for youOn your board, answered with a tap
  • A Telegram pingOnly when it needs your answer, if you connect Telegram
  • The report in the chatEvery run, with or without Briefkin

What you get

  • Wasted spend: the total over 30 days on terms with no conversions.
  • Terms: each with campaign, cost, clicks and the proposed negative with its match type.
  • The ask: add all, add some, or skip this week.
  • After approval, a short log of what was added and where.

The card on the right is a sample. Yours shows your own numbers and updates in place every run.

What lands on your board

AcmeGoogle Ads wasted search terms · Claude Code

7 search terms spent $707 with no conversions

Add these 7 negatives to the shared list "Account negatives", which covers all Search campaigns?

Over the last 30 days these 7 search terms cost $707 and brought 0 conversions. Four proposed negatives are phrase match on a single word that rules the search out; three are exact.

Search termCampaignCostClicksNegative
free invoice templateNon-brand Search$18461[free invoice template]
quickbooks loginCompetitors$14252"login"
invoice factoring companiesNon-brand Search$11234"factoring"
invoice clerk jobsNon-brand Search$9638"jobs"
how to write an invoice by handNon-brand Search$7129[how to write an invoice by hand]
xero invoice template downloadCompetitors$6419[xero invoice template download]
invoice meaning in hindiNon-brand Search$3821"meaning"
Resolve
An example with made-up numbers. Your agent posts your real ones.

What it does

The search terms report is where broad and phrase match show their work, and where part of the budget goes to searches nobody would have bid on: job seekers, people who want it free, a competitor's login page. Reading it is tedious, which is why negative keyword lists go stale.

The agent reads it weekly, picks the terms that spent real money without converting, and proposes the narrowest negative that blocks each one. Nothing changes until you say so. Then it adds the approved negatives to your shared list and reports exactly what it did.

How it works

  1. 1Pull 30 days of search terms

    Run GAQL on search_term_view selecting search_term_view.search_term, search_term_view.status, campaign.name, ad_group.name, metrics.cost_micros, metrics.clicks and metrics.conversions, WHERE segments.date DURING LAST_30_DAYS AND metrics.conversions = 0 AND metrics.cost_micros > 25000000, ordered by cost.

  2. 2

    2Skip what is already handled

    Drop terms whose status is already EXCLUDED or ADDED_EXCLUDED, terms with 5 clicks or fewer, and anything containing your brand name.

  3. 3

    3Propose the narrowest negative

    Use an exact match negative for a one-off term, and a phrase match negative for a single word that rules out any search (jobs, login, meaning). Negatives do not match close variants, so add the plural or the misspelling when that shows up too.

  4. 4

    4Ask before changing anything

    Post an action card with the terms, their cost and the proposed negatives, naming where they will go: a shared negative keyword list or specific campaigns.

  5. 5Add the approved negatives

    On approval, create SharedCriterion entries with keyword.text and keyword.match_type in the shared set through SharedCriterionService.MutateSharedCriteria, or campaign negatives through CampaignCriterionService with negative: true. Then report what was added.

  6. Post it to the board

    With BRIEFKIN_TOKEN set, the agent sends the result as one card that updates in place every run. Without it, you get the report in the chat.

Install and run it

Pick your agent, where the data comes from and how to schedule it; the commands below follow.

Agent
Data
Schedule
  1. Install the skill

    One command. It puts the SKILL.md in ~/.claude/skills and in ~/.agents/skills, which Codex, Cursor, Gemini CLI, Copilot CLI and OpenCode read too.

    shellcurl -fsSL https://briefkin.dev/skills/google-ads-wasted-search-terms/install | sh
  2. Run it

    Ask Claude Code:

    promptRun the google-ads-wasted-search-terms skill

    Or paste the prompt instead of installing:

    promptFind wasted spend in my Google Ads account. Using GAQL on search_term_view for the last 30 days, list search terms with metrics.conversions = 0, more than $25 in cost and more than 5 clicks, skipping terms already excluded and anything with my brand name. For each, show campaign, ad group, cost and clicks, and propose the narrowest negative keyword: exact match for a one-off, phrase match for a single word that makes any search irrelevant (like jobs, login, free). Give the total wasted. Do not change anything: ask me which to add, and to which shared negative list or campaign.
  3. Put it on a schedule

    Wednesdays at 10:00, from cron on any machine where Claude Code is signed in:

    crontab0 10 * * 3 claude -p "Run the google-ads-wasted-search-terms skill"

    Add it with crontab -e. A laptop asleep at that time runs it when it wakes if you use launchd or Task Scheduler instead; GitHub Actions works for the API route.

  4. Send it to your board

    Connect Briefkin once with curl -fsSL https://briefkin.dev/install | sh and every run lands on your board as a question for you. How setup works

View the SKILL.mdRaw file
SKILL.md---
name: google-ads-wasted-search-terms
description: "Every Wednesday, the search terms that cost money over 30 days with zero conversions, a proposed negative keyword for each, and one question: add them?. Use when the user asks for this, or when it runs on a schedule."
---

# Google Ads wasted search terms

Every Wednesday, the search terms that cost money over 30 days with zero conversions, a proposed negative keyword for each, and one question: add them?

The search terms report is where broad and phrase match show their work, and where part of the budget goes to searches nobody would have bid on: job seekers, people who want it free, a competitor's login page. Reading it is tedious, which is why negative keyword lists go stale.

The agent reads it weekly, picks the terms that spent real money without converting, and proposes the narrowest negative that blocks each one. Nothing changes until you say so. Then it adds the approved negatives to your shared list and reports exactly what it did.

## Two ways to get the data

Use the API or MCP route when you have an MCP server, a CLI or an API token for the app. Otherwise, if you can drive a browser the user is signed in to (Claude in Chrome, a Playwright or Chrome DevTools MCP server), use the browser route. Say which one you used.

## Route A: API or MCP server

### What you need

- Standard (edit) access to the Google Ads account, since approved negatives are written to it; read access is enough until you approve.
- Google Ads API access through a Google Cloud project with at least Basic access and OAuth credentials (developer tokens were retired in September 2026). The official Google Ads MCP server is read-only, so the write step needs the API or a connector that can make changes.
- The name of the shared negative keyword list to add to, or the campaigns to use instead.

If something is missing, say what and stop; do not invent numbers.

### Steps

1. **Pull 30 days of search terms** (Google Ads): Run GAQL on `search_term_view` selecting `search_term_view.search_term`, `search_term_view.status`, `campaign.name`, `ad_group.name`, `metrics.cost_micros`, `metrics.clicks` and `metrics.conversions`, `WHERE segments.date DURING LAST_30_DAYS AND metrics.conversions = 0 AND metrics.cost_micros > 25000000`, ordered by cost.
2. **Skip what is already handled**: Drop terms whose `status` is already `EXCLUDED` or `ADDED_EXCLUDED`, terms with 5 clicks or fewer, and anything containing your brand name.
3. **Propose the narrowest negative**: Use an exact match negative for a one-off term, and a phrase match negative for a single word that rules out any search (`jobs`, `login`, `meaning`). Negatives do not match close variants, so add the plural or the misspelling when that shows up too.
4. **Ask before changing anything**: Post an action card with the terms, their cost and the proposed negatives, naming where they will go: a shared negative keyword list or specific campaigns.
5. **Add the approved negatives** (Google Ads): On approval, create `SharedCriterion` entries with `keyword.text` and `keyword.match_type` in the shared set through `SharedCriterionService.MutateSharedCriteria`, or campaign negatives through `CampaignCriterionService` with `negative: true`. Then report what was added.

## Route B: the browser

### What you need

- Signed in to Google Ads with Standard access if negatives will be added in the browser; Read-only access is enough to review the list.

If something is missing, say what and stop; do not invent numbers.

### Steps

Start at https://ads.google.com/aw/keywords/searchterms. The user is signed in already; never type passwords or codes, and ask if a sign-in page appears.

1. **Open the search terms report**: Open `https://ads.google.com/aw/keywords/searchterms` (Campaigns, then Insights and reports, then Search terms). Pick the client account if asked, and set the date range to `Last 30 days`.
2. **Filter to spend without conversions**: Add filters `Conversions = 0` and `Cost > 25`, then sort by Cost, highest first. Check that the `Clicks`, `Campaign`, `Ad group` and `Added/Excluded` columns are visible.
3. **Skip what is handled**: Ignore rows already marked Excluded in the Added/Excluded column, rows with 5 clicks or fewer, and anything containing the brand name.
4. **Propose a negative per term**: Exact match for a one-off term, phrase match for a single word that rules out any search (`jobs`, `login`, `meaning`). Negatives ignore close variants, so include a plural or misspelling when it appears too.
5. **Ask, then add the approved ones**: Show the list with cost and clicks and stop. After approval, tick the rows, click `Add as negative keyword`, choose the negative keyword list or campaign, set the match type and save; then report what was added.

Note: The report omits low-volume search terms for privacy, in the UI as well as the API, and Performance Max terms are not in it (look under the campaign's Insights tab). Download the table when the account has more than a few hundred qualifying rows.

## The report

- **Wasted spend**: the total over 30 days on terms with no conversions.
- **Terms**: each with campaign, cost, clicks and the proposed negative with its match type.
- **The ask**: add all, add some, or skip this week.
- After approval, a short log of what was added and where.

## Post it to Briefkin

When `BRIEFKIN_TOKEN` is set, or `~/.config/briefkin/env` exists (the installer from https://briefkin.dev/docs writes it), also send the result to the user's Briefkin board as one card. Keep the `item_key` the same on every run so the card updates in place, use a new `event_id` per run, and put today's real numbers in place of the example ones. If the request fails, say so once and carry on.

```bash
[ -n "${BRIEFKIN_TOKEN:-}" ] || . ~/.config/briefkin/env
curl -sS -X POST "${BRIEFKIN_URL:-https://briefkin.dev}/v1/events" \
  -H "authorization: Bearer $BRIEFKIN_TOKEN" \
  -H "content-type: application/json" \
  -d @- <<'JSON'
{
  "v": 1,
  "event_id": "google-ads-wasted-search-terms/<date of this run, e.g. 2026-10-16>",
  "item_key": "google-ads-wasted-search-terms",
  "project": "Acme",
  "source": "Google Ads wasted search terms skill",
  "kind": "action",
  "title": "7 search terms spent $707 with no conversions",
  "summary": "Over the last 30 days these 7 search terms cost **$707** and brought 0 conversions. Four proposed negatives are phrase match on a single word that rules the search out; three are exact.",
  "action": {
    "request": "Add these 7 negatives to the shared list \"Account negatives\", which covers all Search campaigns?",
    "options": [
      "Add all 7",
      "Add the 4 phrase ones",
      "Add the 3 exact ones",
      "Not this week"
    ]
  },
  "widget": {
    "type": "Table",
    "props": {
      "columns": [
        "Search term",
        "Campaign",
        "Cost",
        "Clicks",
        "Negative"
      ],
      "align": [
        "left",
        "left",
        "right",
        "right",
        "left"
      ],
      "rows": [
        [
          "free invoice template",
          "Non-brand Search",
          "$184",
          61,
          "[free invoice template]"
        ],
        [
          "quickbooks login",
          "Competitors",
          "$142",
          52,
          "\"login\""
        ],
        [
          "invoice factoring companies",
          "Non-brand Search",
          "$112",
          34,
          "\"factoring\""
        ],
        [
          "invoice clerk jobs",
          "Non-brand Search",
          "$96",
          38,
          "\"jobs\""
        ],
        [
          "how to write an invoice by hand",
          "Non-brand Search",
          "$71",
          29,
          "[how to write an invoice by hand]"
        ],
        [
          "xero invoice template download",
          "Competitors",
          "$64",
          19,
          "[xero invoice template download]"
        ],
        [
          "invoice meaning in hindi",
          "Non-brand Search",
          "$38",
          21,
          "\"meaning\""
        ]
      ]
    }
  }
}
JSON
```

Widgets come from the Briefkin catalog (https://briefkin.dev/v1/catalog). Without a token, just give the user the report.

## Run it on a schedule

Suggested: Wednesdays at 10:00 (`0 10 * * 3`). From cron, with the agent signed in on that machine:

```bash
0 10 * * 3 claude -p "Run the google-ads-wasted-search-terms skill"
# Codex: codex exec, Gemini CLI: gemini -p, Copilot CLI: copilot -p, OpenCode: opencode run
```

Or use the agent's own scheduler (Claude Code routines, Codex automations, Claude or ChatGPT scheduled tasks): https://briefkin.dev/skills/google-ads-wasted-search-terms#schedule

Source: https://briefkin.dev/skills/google-ads-wasted-search-terms

What your agent needs

  • Standard (edit) access to the Google Ads account, since approved negatives are written to it; read access is enough until you approve.

  • Google Ads API access through a Google Cloud project with at least Basic access and OAuth credentials (developer tokens were retired in September 2026). The official Google Ads MCP server is read-only, so the write step needs the API or a connector that can make changes.

  • The name of the shared negative keyword list to add to, or the campaigns to use instead.

Connecting Google Ads

  1. Google Ads MCP server, Google's open-source, read-only server (google-ads-mcp, source). Run it locally with pipx run --spec git+https://github.com/googleads/google-ads-mcp.git google-ads-mcp, or deploy it to Cloud Run for remote clients. Its tools are list_accessible_customers, search for GAQL and get_resource_metadata (docs).
  2. Google Ads API with OAuth. Enable the Google Ads API in a Google Cloud project, sign in with Application Default Credentials (gcloud auth application-default login with the adwords scope) or an OAuth client, and set GOOGLE_PROJECT_ID. Add GOOGLE_ADS_LOGIN_CUSTOMER_ID when you reach client accounts through a manager account, and write customer IDs without dashes.

The adwords scope can't be narrowed, so sign in as a Google Ads user with Read only access; the MCP server has no write tools either way.

Questions

Why are Performance Max search terms missing?

Performance Max does not report through search_term_view; it shows search categories instead, in campaign_search_term_insight. Negatives for Performance Max go in at the campaign or account level, and the agent can propose those separately if you ask.

Will a phrase negative like "free" block good searches?

It blocks every search containing the word, so "free trial" goes too. The agent only proposes a one-word phrase negative when every term with that word over the last 90 days had no conversions, and lists those terms if you ask.

Do I need Briefkin to use the Google Ads wasted search terms skill?

No. The skill runs with your own agent and gives you the report in the chat. With a Briefkin token set, each run also posts it to your board as a asks you, so you can glance at it instead of asking again.

Which agents can run it?

Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot CLI, OpenCode, Windsurf and Amp all read SKILL.md files. The install command puts it in ~/.claude/skills and ~/.agents/skills, where they look. ChatGPT, the Claude app and Grok take the prompt instead. Pick your agent under "Install and run it" and the commands change to match.

Can it work without an API or MCP server, from my browser?

Yes. Switch the data source to "Your browser" and the steps change to the Google Ads pages themselves: the agent opens ads.google.com/aw/keywords/searchterms in a browser you are signed in to and reads the numbers off the page. Claude Code, Codex, Cursor, Claude app and ChatGPT can drive a browser out of the box; Gemini CLI, Copilot CLI and OpenCode need a Playwright or Chrome DevTools MCP server first. It is slower than the API and needs you signed in, so it suits a report you run by hand or from a scheduler on your own computer.

Answer your agents from one board, or from Telegram

Skills are free to use with any agent. Briefkin is where their results land: one board for every report, number and question your agents send, with a ping when something needs you.

Free during the open beta. No card.