/** * * Make Exact Match Exact * * Adds negatives for any search query that doesn't actually exactly match an exact * match keyword. * * Version: 2.0 * Google AdWords Script maintained on brainlabsdigital.com * **/ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //Options var campaignNameDoesNotContain = []; // Use this if you want to exclude some campaigns. Case insensitive. // For example ["Brand"] would ignore any campaigns with 'brand' in the name, // while ["Brand","Competitor"] would ignore any campaigns with 'brand' or // 'competitor' in the name. // Leave as [] to not exclude any campaigns. var campaignNameContains = []; // Use this if you only want to look at some campaigns. Case insensitive. // For example ["Brand"] would only look at campaigns with 'brand' in the name, // while ["Brand","Generic"] would only look at campaigns with 'brand' or 'generic' // in the name. // Leave as [] to include all campaigns. //Choose whether the negatives are created, or if you just get an email to review var makeChanges = true; // These addresses will be emailed when the tool is run, eg "daniel@example.com" // If there are multiple addresses then separate them with commas, eg "a@a.com, b@b.com" // Leave as "" to not send any emails var emailAddresses = ""; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// function main() { var campaigns = {}; var adGroups = {}; var exactKeywords = []; var exactGroupIds = {}; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //Pull a list of all exact match keywords in the account var campaignIds = getCampaignIds(); var report = AdWordsApp.report( "SELECT AdGroupId, Id, Criteria " + "FROM KEYWORDS_PERFORMANCE_REPORT " + "WHERE Impressions > 0 AND KeywordMatchType = EXACT " + "AND CampaignId IN [" + campaignIds.join(",") + "] " + "AND AdGroupStatus IN [ENABLED, PAUSED] " + "AND Status IN [ENABLED, PAUSED] " + "DURING LAST_30_DAYS"); var rows = report.rows(); while (rows.hasNext()) { var row = rows.next(); var keywordId = row['Id']; var adGroupId = row['AdGroupId']; exactKeywords.push(adGroupId + "#" + keywordId); exactGroupIds[adGroupId] = true; if(!adGroups.hasOwnProperty(adGroupId)){ adGroups[adGroupId] = [[], [], []]; } adGroups[adGroupId][2].push(row['Criteria'].toLowerCase().trim()); } exactGroupIds = Object.keys(exactGroupIds); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// // Remove ad groups with non-exact keywords var nonExactGroupIds = {}; for (var i=0; i -1) { // This query is a positive keyword in the ad group // so we don't want to add is as a negative continue; } if(!campaigns.hasOwnProperty(campaignId)){ campaigns[campaignId] = [[], []]; } campaigns[campaignId][0].push(searchQuery); campaigns[campaignId][1].push(adGroupId + "#" + keywordId); if(!adGroups.hasOwnProperty(adGroupId)){ adGroups[adGroupId] = [[], []]; } adGroups[adGroupId][0].push(searchQuery); adGroups[adGroupId][1].push(adGroupId + "#" + keywordId); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //Parse data correctly var adGroupIds = []; var adGroupNegatives = []; for(var x in adGroups){ adGroupIds.push(parseInt(x)); adGroupNegatives.push([]); for(var y = 0; y < adGroups[x][0].length; y++){ var keywordId = adGroups[x][1][y]; var keywordText = adGroups[x][0][y]; if(exactKeywords.indexOf(keywordId) !== -1){ adGroupNegatives[adGroupIds.indexOf(parseInt(x))].push(keywordText); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// //Create the new negative exact keywords var results = []; for (var i=0; i