Turns a search terms report into a reviewed set of negative keywords. The output is an approval sheet, a clean conflict check and a Google Ads Editor import file. Nothing changes in the account until a person imports, reviews and posts.
When to use
Use this skill when:
- Someone asks how to create negative keywords, or wants wasted spend cut from Search, Shopping, Performance Max or AI Max campaigns. Shopping notes: references/match-types-and-levels.md.
- Search terms show spend on job, free, DIY, learning, competitor, far-away place or existing-customer searches.
- A negative keyword list or the account-level list needs building, pruning or a check against its limit.
- A keyword stopped serving, or the search terms report shows a term as both added and excluded.
- A new campaign needs a starting set of negatives from theme seed terms before it has data.
Use something else when:
- One ad group catches every intent or broad keywords run everywhere. Fix structure first with the b2b-search-campaign-structure skill when it is installed; otherwise stop, tell the user structure comes first and list the overlapping ad groups you found. Negatives on a bad structure only move the waste.
- The job is a full account review: use the google-ads-account-audit skill when installed, otherwise say this skill covers search terms only.
- Bulk Editor files for keywords, ads and assets: the google-ads-editor-import-builder skill when installed.
- Display and YouTube placements or topics: those need content exclusions, not keyword negatives.
- Conversions look wrong. Fix measurement first; every flag below trusts the conversion column.
Inputs
Read these first if they exist:
martech-context/stack.md: customer ID (format123-456-7890), manager account, currency, time zone, the exact names of the brand, non-brand, competitor and Performance Max campaigns, Editor version.martech-context/metrics.md: which conversion actions sit in the Conversions column, target CPA or ROAS.martech-context/decisions.md: earlier competitor, served-region and existing-customer decisions.
Then gather:
- Search terms for 30 to 90 days, ending before the conversion lag (default: leave out the last 7 days). Campaign, ad group, keyword, match type, Added/Excluded, impressions, clicks, cost, conversions, conversion value, and the totals rows.
- Performance Max search terms as a separate file.
- Current keywords with match type and keyword, ad group and campaign status.
- Every live negative: ad group, campaign, the contents of every shared list and the campaigns each is applied to, the account-level list, Performance Max negatives and brand exclusions. Leave out removed rows. How to read each: references/reading-the-account.md.
- One line each from the business: what it sells, where, to whom, and whether free trials, templates, students, job seekers, competitors' customers and existing customers are wanted.
Never ask for, print or store credentials or tokens. Remove any search term that contains a person's name, email or phone number before sharing a sheet.
Procedure
1. Export and check coverage
- Web interface: Campaigns, Insights and reports, Search terms (checked 2026-10-17). Remove filters before downloading.
- Performance Max: same report, "Search terms and landing pages for Performance Max".
- Google Ads MCP server: read-only in the release checked on 2026-10-17, with
list_accessible_customers,search(GAQL) andget_resource_metadata. Clients can show them with a prefix (customers_list_accessible_customers,search_search,metadata_get_resource_metadata). Confirm the customer with the user and check fields withget_resource_metadatabefore running the queries in the reading reference. - The n-gram run prints the share of cost the visible terms carry. Web downloads supply it from their totals rows; for API data pass
--total-costfrom the campaign cost query in the reading reference. Below 70%, say in the summary that the rest is hidden low-volume terms or a filter left on, and re-download if a filter is the cause.
2. Run the n-gram analysis
node scripts/negatives.mjs campaigns search-terms.csv
node scripts/negatives.mjs ngrams search-terms.csv --not-campaign "Search - Brand" --out ngrams.csv
node scripts/negatives.mjs ngrams search-terms.csv --campaign "Search - Brand" --out ngrams-brand.csv
- Brand and non-brand run separately: brand conversion rates distort the baseline.
--campaignand--not-campaigntake one whole campaign name each; repeat the flag for more. Take the names fromstack.md, or ask, and compare with thecampaignslist. A name that matches no campaign stops the run. Name patterns (--campaign-match) are in the mining reference; a barebrandpattern also catches "Non-Brand".- Read "campaigns in this run" and "campaigns left out" for both runs. Every campaign sits in exactly one run and neither run is empty (an empty run stops with an error).
- Flags:
no-conv-significant(zero conversions with at leastln(0.05)/ln(1 - p)clicks, about3 / p, wherepis the baseline conversion rate),no-conv-over-target-cpa(zero conversions, cost at or above target CPA),cpa-over-2x-target. About 1 in 20 flagged rows that convert at baseline is a false positive, so every flag still needs the meaning check in step 3. converting_termsabove zero means a broad or phrase negative on that n-gram blocks a search that converted.- Columns, thresholds, options and reading order: references/mining-method.md.
3. Classify by theme
Read the n-gram table by cost, then the 50 most expensive search terms. Give each candidate one theme: job seeker, free or DIY, wrong intent, irrelevant, competitor, wrong location, existing customer.
- Meaning first. A theme term that cannot buy (jobs, salary, course) is negated at any volume.
- An ambiguous term needs a flag and
converting_termsof 0. - Never negate buying words (pricing, quote, demo, trial, vs, alternative, review, best, software, near me) without the owner.
- Competitor, wrong location and existing customer are business decisions: list them separately with their numbers.
- Lead generation: a theme term that cannot buy but shows conversions is often junk form fills. Compare with CRM or offline qualified outcomes where they exist and record the result as the owner decision on its CONVERTING line.
- Seed terms and traps per theme: references/mining-method.md.
4. Choose the level
- Account-level: wrong for every campaign, now and planned. Applies to all eligible search and shopping inventory, Performance Max included. Limit 1,000.
- Shared list: a theme for two or more campaigns, named by theme. 20 lists per account, 5,000 keywords per list.
- Campaign: wrong here, right elsewhere (brand terms in non-brand campaigns, Shopping priority routing).
- Ad group: only to route searches between ad groups of one campaign. Never for irrelevant traffic.
- Performance Max: campaign negatives or lists, which cover Search and Shopping inventory only. A Search campaign's negative does not reach Performance Max.
- Brand traffic in Performance Max or AI Max: brand exclusions, which also catch brand misspellings and other languages. A Search campaign needs AI Max turned on to add a new brand list; existing brand settings keep working outside AI Max. Google's AI Max rule: bad query gets a negative, cannibalisation gets a brand exclusion, bad landing page gets a URL exclusion.
- 10,000 negatives per campaign. Limits checked 2026-10-17, with detail in references/match-types-and-levels.md.
5. Choose the match type and length
- Length: take the shortest flagged or theme n-gram with
converting_termsof 0. If the unigram has converting terms, try the bigram, then the trigram, as phrase. If none is clean, add exact negatives on the bad terms. Skip any n-gram that a shorter one in the sheet already covers. - Broad, one word: a word wrong in every context (
jobs). - Phrase: a multi-word theme where order matters (
"what is"). - Exact: one bad search whose words also appear in good ones, and all routing negatives.
- Broad, several words: only when every order of the words is wrong.
- Negatives never match close variants: add singular, plural and synonyms yourself. Google's page says casing and misspellings are covered (2026-10-17); spot-check the next report.
- Accented and unaccented words, and
&versusand, are different negatives. Google says an ad may still show when the negative's word comes after the 16th word of a search. Keyword text holds at most 80 characters and 10 words. - Write each row into the approval sheet: theme, level, list, campaign, ad group, keyword, match type, evidence, and approver and date for decision rows (assets/example-negatives-approved.csv).
6. Check conflicts
node scripts/negatives.mjs conflicts --negatives draft.csv --keywords keywords.csv \
--existing lists.csv --terms search-terms.csv
- CONFLICT (blocks an enabled keyword) and CONVERTING (blocks a converted search term) must be fixed or carry an owner decision. The command exits 1 while any remain.
- DUPLICATE: delete that copy. REDUNDANT names the row that covers it: drop the redundant row only if that covering row stays in the approved file. Re-run after every drop.
- PAUSED lines matter only if the keyword, ad group or campaign will return.
- The check cannot see what broad or phrase keywords match by meaning, or misspellings Google applies to negatives. Day 7 monitoring is the second check. Detail: references/apply-and-monitor.md.
7. Draft the change and stop for approval
node scripts/negatives.mjs editor --negatives approved.csv --out negatives-import.csv
- Writes campaign and ad group negatives as an Editor import (UTF-16, tab separated), and one paste-ready text file per shared list and for the account-level list. It warns on text over 80 characters or 10 words or with symbols Google rejects.
- Show the user the sheet, the conflict output, the "IMPACT total" line and the manual steps. Wait for approval, with competitor, location and existing-customer rows approved by name and date.
- With Editor: the user imports (Account, Import), reviews, keeps, runs Check changes and posts. Steps and column values: references/apply-and-monitor.md.
- Without Editor: the user adds the same rows in the web interface. Paths, and why the search terms report's "Add as negative keyword" button is not the way to apply this sheet: references/apply-and-monitor.md.
8. Monitor
- Same day: confirm counts per campaign and list after Get recent changes.
- Day 7: negated themes should have no new clicks. New clicks mean a missed variant or wrong scope; any
Added / Excludedrow is a clash. - Day 28: clicks and cost should fall by about the IMPACT total scaled to 28 days. With 30 or more conversions in each 28-day window, a conversion drop above 20% while the blocked terms had none is a conflict until proven otherwise; with fewer, compare against the last eight weeks' range instead. Re-run the check with fresh exports.
- Check whether "Remove conflicting negative keywords" and "Add broad match keywords" are auto-applied.
- Re-mine every 30 days, or when spend since the last pass reaches 10 times the target CPA. Propose a dated
decisions.mdentry.
Common failure modes
- Brand split by a name fragment. Detect: a "Non-Brand" campaign under "campaigns in this run" of the brand run, or an empty non-brand run.
- Routing negative at campaign level. Detect: CONFLICT on the sibling ad group's keyword; that ad group's impressions near zero.
- Broad negative on a word inside converting searches (
freeagainst "free trial"). Detect: CONVERTING;converting_termsabove zero. - Whole queries negated from the search terms report. Detect: the same n-gram keeps clicking under new search terms after a pass.
- Plural or synonym missed. Detect:
jobsearches still clicking afterjobswas added. - Shared list clash nobody can see. Detect:
Added / Excludedrows; list contents missing from the Editor export. - Filter left on, or hidden terms ignored. Detect: the visible-share line from the n-gram run.
- Zero-conversion verdicts on last week's terms. Detect: flagged terms converting a week later.
- Auto-applied broad match. Detect: broad keywords nobody added; search terms widen on one day.
- Limits reached. Detect: account-level count near 1,000; REDUNDANT lines.
- Ad group thinking in Performance Max, which has no ad groups. Detect: negatives planned at ad group level for a Performance Max campaign.
Worked example
Acme Invoicing, a fictional US company, sells invoice automation software. Files: assets/example-search-terms.csv (90 days), assets/example-keywords.csv, assets/example-negatives-draft.csv, assets/example-negatives-approved.csv.
campaignslists "Search - Invoice Automation" and "Search - Brand";stack.mdnames the second as brand. The non-brand run (--not-campaign "Search - Brand"): visible terms carry 80% of account cost, baseline conversion rate 3.85%, CPA 176.03, so a zero-conversion n-gram needs 77 clicks.template: 115 clicks, 437.50, no conversions,no-conv-significant. Broadtemplateplustemplatesby hand.what is: 72 clicks, 432.00, no conversions,no-conv-over-target-cpa, wrong intent. Phrase"what is".jobs: 43 clicks, 301.00,no-conv-over-target-cpabut under the 77-click threshold. Job seekers cannot buy. A "Job seekers" list withjobs,job,salary,careerson every campaign.- The draft added broad
freebecause the bigramfree invoicewas flagged. The unigram row showsfreein 2 converting terms; the check printed CONVERTING for "invoice automation free trial" and "free invoice software". The bigram has 1 converting term too; the trigramfree invoice templateis clean buttemplatealready covers it. Dropped. "accounts payable"was drafted at campaign level to keep AP searches out of the Invoice automation ad group. CONFLICT with the keywordaccounts payable automation. Moved to the ad group.initech(a competitor): 32 clicks, 272.00, 1 conversion, CONVERTING. Moved to the owner's decision list.[invoice automation jobs]was REDUNDANT, covered by the list'sjobs, which stays. Dropped.- Brand run:
login, 65 clicks, 52.00, no conversions. Approved by the owner on 2026-10-17 as a brand-campaign negative because that campaign's goal is new trials. - The approved file checks clean (exit 0). The editor command wrote 10 rows and a paste file of 4 keywords for the "Job seekers" list. IMPACT total: 12 terms, 392 clicks and 1,775.50 of 5,765.00 visible cost, with no conversions, would have been blocked over the period.
Acceptance checks
- Coverage: the summary names the date range, currency, time zone, conversion column, the export file or GAQL query used, and the visible cost share. Pass: all stated, and the range ends before the conversion lag.
- Brand split: the campaigns each run printed match the brand and non-brand split in
stack.md. Pass: every campaign in exactly one run, neither run empty. - Evidence: every proposed negative has theme, level, match type and evidence. Pass: no blank cells in those columns.
- Conflicts: the final file was checked with keywords and all live negatives, including every shared list and the account-level list. Pass: the command printed "0 problems" and exited 0, or each remaining line has a named owner decision; no DUPLICATE lines; every REDUNDANT row dropped names a row still in the file.
- Converting traffic: no broad or phrase negative sits on an n-gram with
converting_termsabove zero. Pass: cross-checked against the n-gram table. - Variants: each single-word negative has its plural or singular and obvious synonyms considered. Pass: both forms are in the sheet, or a note says why not.
- Limits: counts after the change are stated. Pass: at most 1,000 account-level, 5,000 per list, 20 lists, 10,000 per campaign.
- Decisions: competitor, location and existing-customer rows have an approver and date. Pass: recorded in the sheet or the proposed
decisions.mdentry. - Applied: the Editor import showed no errors and Get recent changes shows the rows. Pass: counts per campaign and list match the approved sheet.
- Follow-up: day 7 and day 28 checks are dated in the proposal. Pass: both dates written.
Boundaries
- Read-only. The skill produces a sheet, a conflict report and an import file. A person imports, reviews and posts. Never post, and never call a write-capable tool without approval of that exact change list.
- It does not decide competitor bidding, trademark policy, served regions or whether existing-customer searches are wanted. The owner does, and the decision is recorded.
- It does not fix account structure, bidding or conversion tracking.
- Changing auto-apply settings is an account setting change for the owner.
- Hand-offs:
- Google's Google Ads MCP server (
googleads/google-ads-mcp) for search terms and existing negatives. The release checked on 2026-10-17 is read-only. If a connected server exposes write tools, confirm its publisher and version before using it in this workflow. - Google's
google-ads-api-mcp-setupskill to install the server, andgoogle-ads-api-account-diagnosticsfor performance questions beyond search terms, both ingoogle/skills. - Google Ads Editor for the import; the web interface for shared lists, account-level negatives and brand exclusions.
- Google's Google Ads MCP server (
Live docs
Platform settings, limits and menu paths change. Before stating any parameter name, limit, quota or UI path:
- Fetch the current page from the vendor docs MCP server or llms.txt listed in
sources.yaml, or open the canonical URL. - If the live page disagrees with this skill, follow the live page and tell the user what changed.
- Cite the URL you used.
The entries that matter most here: "About negative keywords" for match behaviour and symbols, "Add negative keywords to campaigns", "Get negative keyword ideas using the search terms report", "About negative keyword lists" and "About Google Ads account limits" for limits, the Performance Max negatives and search terms pages, the brand exclusions page, the AI Max reporting guide, the Editor import, export and match type pages, the shared sets guide, and the Google Ads MCP server guide. Everything in this skill was checked on 2026-10-17.