Years ago I inherited a Google Ads account from another agency. It had been built by someone who believed in keyword sculpting — the practice of using negative keywords across campaigns to force traffic into the “right” ad group.
I built new campaigns in that account. They underperformed. Some keywords weren’t serving at all. The Search Terms report was thin. Keyword status said “Eligible.” Nothing in the UI told me what was wrong.
It took me three days to find the answer.
A campaign in that account had been duplicated at some point in its history. The duplication carried over the campaign-level negatives. More campaigns were built from that template later. By the time I touched the account, there were negative keywords scattered across campaigns and shared lists that nobody could remember adding. Several of those negatives were now blocking the positive keywords in my new campaigns.
The fix was simple. The hard part was finding them.
Three days of opening campaign settings, exporting keyword lists, cross-referencing positives against negatives at every level, eventually realizing some of the conflicts lived in MCC-level shared lists I couldn’t even see from the account-level view. By the time I’d traced the problem, I’d burned a week of optimization opportunity and given Google a week of bad data to learn from.
The hard question that forced me to build this:
How many “why isn’t this keyword serving?” debugging sessions could have been a one-line answer from a Google Sheet?
That question is what the neg-conflict-finder skill exists to answer. It’s open-sourced as part of my PPC AI Skills repo, and it runs daily across every account I manage. I’ve wished I had it at every agency I’ve ever worked at.
Here’s what it does, why it works, and why every operator inheriting accounts needs some version of it.
Get the Neg Conflict Finder skill → github.com/fourteenwm/ppc-ai-skills/neg-conflict-finder
Free and open-sourced. Drop the Google Ads Script into your MCC, set a label, hit run. No configuration beyond the label.
The Core Problem: Negatives Don’t Announce Themselves
The Google Ads UI shows you what served. It doesn’t show you what got blocked.
A negative keyword silently filtering out your positive looks identical to a positive that just isn’t matching queries yet. The keyword shows “Eligible.” The campaign shows “Enabled.” The Search Terms report is just… empty. There’s no banner that says “by the way, this keyword is being blocked by a negative in a shared list applied at the MCC level six years ago.”
You find out by accident. Usually because someone asks why a specific term isn’t showing up. Then you start looking. Then you find a campaign-level negative that doesn’t make sense. Then you wonder how many other terms are being quietly suffocated.
This is the failure mode that compounds. Every quarter, more negatives get added — by you, by the previous manager, by some optimization tool, by a campaign duplicated for a new property. Most of those negatives are doing real work. A few are blocking active keywords you bid on. There’s no way to tell which is which without an audit.
The audit is the work nobody does. Because doing it manually across an MCC is hours of tedium.
Where Negatives Actually Hide
Negative keywords live at five levels in Google Ads, and they all inherit down:
- Ad group level — applied to a single ad group
- Campaign level — applied to every ad group in a campaign
- Account-level shared lists — reusable lists applied to one or more campaigns
- MCC-level shared lists — lists owned by the manager account, applied to child accounts
- Account-level negatives — applied across the entire account
Most agencies audit the first two. They open a campaign, they look at the negatives tab, they call it good.
The other three are where the real surprises live.
MCC-level shared lists are the worst offenders when you take over an account from another agency. They’re owned at the manager level, so they don’t even appear in the child account’s shared library. You can see they’re applied — you can’t always see the contents without manager access. If the previous agency built a “Universal Negatives” list at the MCC level and never told you, you’re inheriting their decisions silently every time you touch a campaign.
Account-level negatives are newer and less commonly used, but they’re the catch-all for “I want this term blocked everywhere in this account, forever.” Easy to add. Hard to remember.
This script audits all five levels in a single pass. Every negative, every level, against every active positive in every enabled ad group, in every account under a label.
How Conflicts Actually Block Keywords
Match-type behavior is where most manual audits get the answer wrong.
Broad-match negatives are the easy case. A broad neg blocks broad, phrase, and exact positives that share a keyword token. Most people get this right.
Phrase-match negatives are where it gets subtle. A phrase neg "amberglen" doesn’t just block phrase positives that contain the word “amberglen.” It blocks exact-match positives where “amberglen” appears anywhere in the keyword phrase. So phrase neg "amberglen" blocks exact pos [apartments amberglen], even though the strings aren’t equal.
This is how Google actually evaluates the conflict. The two strings don’t have to match — the phrase neg just has to be a subsequence of the words in the exact pos. Most audit tools (including some early versions of Google’s own reference script) check for string equality and miss this entire class of conflict.
Exact-match negatives are the strict case. Exact [brand reviews] only blocks exact [brand reviews]. Same word order, same words, no extras.
The script does match-type-aware detection at every level, including subsequence matching for phrase negs against exact positives. It’s the difference between catching the conflicts a manual scan can see and catching the entire set, including the ones where the strings aren’t equal but the blocking still happens.
Why You Run This Scoped, Not Across Everything
An MCC can have hundreds of child accounts. Running this audit across all of them, every time, is slow and noisy.
The script uses a label-based filter. You apply a label to the accounts you want to audit — say, kw-conflict-audit — and the script only iterates labeled accounts. This lets you scope by portfolio, service tier, client, or whatever organizational frame fits your agency.
There’s also an optional spend filter. By default, accounts with no spend in the last seven days are skipped. This cuts the noise from accounts that are paused for the season, between budget cycles, or just sitting dormant on a label. You can turn the filter off if you want a true full audit, or tune the threshold to match your portfolio’s pacing.
The result is an audit you can actually schedule. Daily for active portfolios. Weekly for stable ones. The script overwrites the same Google Sheet each run, so you always have the current state — no version sprawl, no stale reports.
What the Audit Output Looks Like
One row per conflict. Four columns:
| Column | What it shows |
|---|---|
| Account Name | Which account the conflict is in |
| Conflicting Negative Keyword | The negative that’s blocking |
| Level & Location | Where the negative lives — ad group name, campaign name, shared list name, or account-level |
| Blocked Positive Keywords | Which positive(s) it’s blocking |
Read-only. The script writes to a Sheet. It never modifies an account.
That’s intentional. Some conflicts are deliberate. A brand campaign with exact-match [brand_name] as a positive and broad-match brand name reviews as a negative is a clean traffic split — not a bug. An automatic remover would tear that apart and call it cleanup.
So the script identifies. You judge. The judgment call only takes a few seconds per row once you have the data in front of you, and that’s a different problem than spending three days finding the data in the first place.
What This Has Actually Caught
Across the accounts I run this on now:
- Inherited campaign negatives from copied campaigns — the original failure mode. New campaigns built from a template inherit the template’s negatives. Years later, the negatives are still there, blocking keywords nobody remembers adding to the negative list.
- Stale shared list entries — a negative added to a shared list for a specific seasonal promotion, never removed when the promotion ended, now blocking the active keyword for the year-round version of the same product.
- Match-type-blind conflicts — phrase negatives blocking exact positives via subsequence match. The conflicts that look invisible to anyone scanning by eye because the strings aren’t equal.
- MCC-level shared lists I didn’t know existed — applied to a client account by a previous agency, owned at the manager level, blocking keywords I’d built in good faith.
- Geo-name negatives blocking branded queries — neg
"amberglen"(the neighborhood name) silently blocking the actual property’s branded keyword[amberglen apartments]. This one is so common I check for it on every account intake.
None of these are dramatic. None of them produce headlines. They produce a slow steady drip of wasted impressions, missed clicks, and Smart Bidding learning from the wrong data. Catching them turns a quarter of mediocre performance into a quarter of clean performance, and Google’s algorithms are fed the data they actually need.
Get the Neg Conflict Finder Skill
Install in 60 seconds
This one’s a Google Ads Script, not a Claude Code skill. Paste the script directly into your MCC:
1. Open your MCC → Tools → Scripts → New Script
2. Paste mcc-neg-keyword-conflict.js from the repo
3. Set ACCOUNT_LABEL to a label you've applied to target accounts
4. Authorize, run, open the linked Sheet
5. Schedule it daily or weeklyBuilt on Google’s official reference script with substantial fixes for match-type-aware blocking detection (subsequence match for phrase-vs-exact), MCC-level shared list support, and an optional spend filter to skip dormant accounts.
Free. Open-sourced. Apache 2.0 licensed.
The full repo has thirty-five other PPC AI skills I use in production every day — mutation safety, search query classification, ad copy verification, RSA refresh, and more. All at github.com/fourteenwm/ppc-ai-skills.
The Bigger Point
Negative keyword hygiene is the work nobody does because it’s tedious. There’s no dashboard that pages you when a negative is blocking a positive. No client asks “have you audited my MCC-level shared lists lately?” The work isn’t visible until something breaks, and by then you’ve already paid for the breakage.
This is the texture of agency operations at scale. The audits that pay off most are the ones that feel least productive while you’re doing them. Three days of cross-referencing keyword lists looks like nothing. The same audit running automatically every Monday morning catches a quarter’s worth of silent waste before it compounds.
I built this skill because I’d lived through the manual version too many times. Every PPC operator who’s ever inherited a legacy account has lived through the manual version too. The work shouldn’t be hard. The data is all there in the API. It just needs to be pulled, cross-referenced, and written to a Sheet — which is exactly what a Google Ads Script is for.
Run the audit. Trust the boring work. Most of the value in this job lives in the rooms nobody walks into.