Google Ads Negative Keyword Conflict Checker Script (GAQL)
Automated Google Ads script that cross-references campaign, ad group and shared negative lists against active positive keywords to flag silent blocking.
How Negative Keyword Collisions Waste High-Intent Budget
Shared negative lists and campaign-level broad negatives frequently block exact and phrase match positive keywords without triggering any visible alert in the Google Ads user interface. This script cross-checks all serving campaigns hourly to ensure active revenue-generating keywords remain unobstructed.
Implementation Code & Script
Copy and paste into Google Ads Scripts editor. Filters to serving campaigns and sends alert emails.
/**
* Google Ads Negative Keyword Conflict Checker (GAQL)
* Author: Gordon Geraghty - Head of Performance, Empire Amplify
* Licence: MIT
* Filter: campaign.status = "ENABLED" AND campaign.serving_status = "SERVING"
*/
const CONFIG = {
EMAIL_RECIPIENT: 'gordon@empireamplify.com.au',
SPREADSHEET_URL: '', // Optional: Paste a Google Sheet URL to log findings
};
function main() {
Logger.log('Starting Negative Keyword Conflict Audit...');
// 1. Fetch all active positive keywords in serving campaigns
const positiveQuery =
'SELECT campaign.id, campaign.name, ad_group.id, ad_group.name, ' +
'ad_group_criterion.keyword.text, ad_group_criterion.keyword.match_type ' +
'FROM keyword_view ' +
'WHERE campaign.status = "ENABLED" ' +
'AND campaign.serving_status = "SERVING" ' +
'AND ad_group.status = "ENABLED" ' +
'AND ad_group_criterion.status = "ENABLED"';
const positiveRows = AdsApp.search(positiveQuery);
const positiveKeywords = [];
while (positiveRows.hasNext()) {
const row = positiveRows.next();
positiveKeywords.push({
campaignName: row.campaign.name,
adGroupName: row.adGroup.name,
text: row.adGroupCriterion.keyword.text.toLowerCase().trim(),
matchType: row.adGroupCriterion.keyword.matchType,
});
}
Logger.log('Found ' + positiveKeywords.length + ' active positive keywords.');
// 2. Fetch all campaign and ad group negative keywords
const negativeQuery =
'SELECT campaign.name, ad_group.name, ' +
'campaign_criterion.keyword.text, campaign_criterion.keyword.match_type, ' +
'campaign_criterion.negative ' +
'FROM campaign_criterion ' +
'WHERE campaign.status = "ENABLED" ' +
'AND campaign.serving_status = "SERVING" ' +
'AND campaign_criterion.negative = TRUE';
const negativeRows = AdsApp.search(negativeQuery);
const conflicts = [];
while (negativeRows.hasNext()) {
const neg = negativeRows.next();
const negText = neg.campaignCriterion?.keyword?.text?.toLowerCase().trim();
if (!negText) continue;
positiveKeywords.forEach(function(pos) {
if (pos.campaignName === neg.campaign.name && pos.text.indexOf(negText) !== -1) {
conflicts.push({
campaign: pos.campaignName,
adGroup: pos.adGroupName,
positiveKeyword: pos.text,
negativeKeyword: negText,
});
}
});
}
Logger.log('Audit complete. Conflicts detected: ' + conflicts.length);
if (conflicts.length > 0 && CONFIG.EMAIL_RECIPIENT) {
let body = 'Google Ads Negative Keyword Conflicts Detected:\n\n';
conflicts.forEach(function(c) {
body += 'Campaign: ' + c.campaign + ' | Ad Group: ' + c.adGroup + '\n';
body += 'Positive: "' + c.positiveKeyword + '" BLOCKED BY Negative: "' + c.negativeKeyword + '"\n\n';
});
MailApp.sendEmail(CONFIG.EMAIL_RECIPIENT, 'Google Ads Conflict Alert: ' + conflicts.length + ' blocked keywords', body);
}
}How to cite and attribute this tool
MIT LicenceThis resource is free, open and un-gated under the MIT Open Source Licence. You are encouraged to use, integrate and cite it with attribution:
Geraghty, G. (2026). Google Ads Negative Keyword Conflict Checker Script (GAQL). Gordon Geraghty Resources Hub. https://gordongeraghty.com/resources/performance-media/negative-keyword-conflict-checker
BibTeX Format
@misc{geraghty_negative_keyword_conflict_checker,
author = {Geraghty, Gordon},
title = {Google Ads Negative Keyword Conflict Checker Script (GAQL)},
year = {2026},
url = {https://gordongeraghty.com/resources/performance-media/negative-keyword-conflict-checker},
note = {Head of Performance, Empire Amplify}
}Changelog & Version History
v1.0.0Initial release using GAQL through AdsApp.search with serving campaign status filtering.