/** * * Keyword Quality Score Report * * This script will find and label keywords with low quality scores, and will pause those keywords * automatically. After labeling and pausing keywords, an email will be sent listing all of the labeled and * paused keywords. * * Version 1.0 * Google Ads script developed by Vladimir Jones - 2019 * **/ //-------------------------------------------------------------------------------------------------------------// var EMAIL_ADDRESSES = ["example1@example.com", "example2@example.com"]; //Be sure to change this to your desired email address(es)// //If you would like to add multiple email addresses they must be seperated by commas// var QS_THRESHOLD = 3; //Change this number to whatever your organization considers to be a low QS// //Must be between 1 and 10// var PAUSE_KEYWORDS = false; //Change this to true if you want to pause low QS keywords automatically// var LABEL_KEYWORDS = true; //Change this to false if you do not want to add labels to keywords// var LOW_QS_LABEL = "Low QS"; //This is the name that the label will read// //This can be changed to any text desired// //-------------------------------------------------------------------------------------------------------------// function main () { Logger.log("Pause Keywords: " + PAUSE_KEYWORDS); Logger.log("Label Keywords: " + LABEL_KEYWORDS); var keywords = findKeywordsWithQSBelow(QS_THRESHOLD) Logger.log("Found " + keywords.length + " keywords with low quality score"); if (!labelExists(LOW_QS_LABEL)) { Logger.log(Utilities.formatString('Creating label: "%s"', LOW_QS_LABEL)); AdsApp.createLabel(LOW_QS_LABEL, 'green'); } var mutations = [ { enabled: PAUSE_KEYWORDS, callback: function (keyword) { keyword.pause(); } }, { enabled: LABEL_KEYWORDS, callback: function (keyword, currentLabels) { if (currentLabels.indexOf(LOW_QS_LABEL) === -1) { keyword.applyLabel(LOW_QS_LABEL); } } } ]; //This variable can be changed to any number. It is the maximum number of keywords the script will search through// var chunkSize = 100000; var chunkedKeywords = chunkList(keywords, chunkSize); Logger.log("Making changes to keywords.."); chunkedKeywords.forEach(function (keywordChunk) { mutateKeywords(keywordChunk, mutations); }); if (keywords.length > 0) { sendEmail(keywords); Logger.log("Email sent."); } else { Logger.log("No email to send."); } } function findKeywordsWithQSBelow(threshold) { var query = 'SELECT Id, AdGroupId, CampaignName, AdGroupName, Criteria, QualityScore, Labels' + ' FROM KEYWORDS_PERFORMANCE_REPORT WHERE Status = "ENABLED" AND CampaignStatus = "ENABLED" AND AdGroupStatus = "ENABLED"' + ' AND HasQualityScore = "TRUE" AND QualityScore <= ' + threshold; var report = AdsApp.report(query); var rows = report.rows(); var lowQSKeywords = []; while (rows.hasNext()) { var row = rows.next(); var lowQSKeyword = { campaignName: row['CampaignName'], adGroupName: row['AdGroupName'], keyword: row['Criteria'], labels: (row['Labels'].trim() === '--') ? [] : JSON.parse(row['Labels']), uniqueId: [row['AdGroupId'], row['Id']], qualityScore: row['QualityScore'] }; lowQSKeywords.push(lowQSKeyword); } return lowQSKeywords; } function labelExists(labelName) { var condition = Utilities.formatString('LabelName = "%s"', labelName); return AdsApp.labels().withCondition(condition).get().hasNext(); } function chunkList(list, chunkSize) { var chunks = []; for (var i = 0; i < list.length; i += chunkSize) { chunks.push(list.slice(i, i + chunkSize)); } return chunks; } function mutateKeywords(keywords, mutations) { var keywordIds = keywords.map(function (keyword) { return keyword['uniqueId']; }); var mutationsToApply = getMutationsToApply(mutations); var adsKeywords = AdsApp.keywords().withIds(keywordIds).get(); var i = 0; while (adsKeywords.hasNext()) { var currentKeywordLabels = keywords[i]['labels']; var adsKeyword = adsKeywords.next(); mutationsToApply.forEach(function(mutate) { mutate(adsKeyword, currentKeywordLabels); }); i++; } } function getMutationsToApply(mutations) { var enabledMutations = mutations.filter(function (mutation) { return mutation['enabled']; }); return enabledMutations.map(function (condition) { return condition['callback']; }); } function renderTable(keywords) { var header = '' + '' + '' + '' + '' + '' + ''; var rows = keywords.reduce(function(accumulator, keyword) { return accumulator + ''; }, ""); var footer = '
Campaign NameAd Group NameKeywordQuality Score
' + [ keyword['campaignName'], keyword['adGroupName'], keyword['keyword'], keyword['qualityScore'] ].join('') + '
'; var table = header + rows + footer; return table; } function sendEmail(keywords) { var subject = "QS Keyword Report"; var htmlBody = "

The following keywords have a low quality score.

" + "

Actions Taken:

" + "

" + renderTable(keywords); MailApp.sendEmail({ to: EMAIL_ADDRESSES.join(","), subject: subject, htmlBody: htmlBody }); }