Forked from BrainlabsDigital/Low Quality Score Alert.js
Last active
January 2, 2020 08:22
-
-
Save lewiss444/a90a8d402adb815e9ad5f4d3674778b4 to your computer and use it in GitHub Desktop.
Script to email you if you have low quality score keywords, and optionally label/pause them
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function main () { | |
var mccAccount = AdWordsApp.currentAccount(); | |
// OPTIONAL: Select your accounts based on conditions | |
// see https://developers.google.com/adwords/scripts/docs/reference/mccapp/mccapp_managedaccountselector#withCondition_1 | |
// example: this selector selects all accounts with over 100 impressions last month | |
var accountSelector = MccApp.accounts(); | |
// get the iterator to iterate over all selected accounts | |
var accountIterator = accountSelector.get(); | |
// Iterate through the list of accounts | |
while (accountIterator.hasNext()) { | |
var account = accountIterator.next(); | |
//var accountName = account.getName() ? account.getName() : '--'; | |
//Logger.log(accountName); | |
// Select the client account. | |
MccApp.select(account); | |
// now do the thing you want to do on every single account | |
runPerAccount(); | |
} | |
// Switch back to MCC account | |
MccApp.select(mccAccount); | |
} | |
// This is where you put the code that you want to run on each account | |
/** | |
* | |
* Low Quality Score Alert | |
* | |
* This script finds the low QS keywords (determined by a user defined threshold) | |
* and sends an email listing them. Optionally it also labels and/or pauses the | |
* keywords. | |
* | |
* Version: 1.0 | |
* Google AdWords Script maintained on brainlabsdigital.com | |
* | |
**/ | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// | |
//Options | |
var EMAIL_ADDRESSES = ["[email protected]"]; | |
// The address or addresses that will be emailed a list of low QS keywords | |
// eg ["[email protected]", "[email protected]"] or ["[email protected]"] | |
var QS_THRESHOLD = 4; | |
// Keywords with quality score less than or equal to this number are | |
// considered 'low QS' | |
var LABEL_KEYWORDS = false; | |
// If this is true, low QS keywords will be automatically labelled | |
var LOW_QS_LABEL_NAME = "Low QS Keyword"; | |
// The name of the label applied to low QS keywords | |
var PAUSE_KEYWORDS = false; | |
// If this is true, low QS keywords will be automatically paused | |
// Set to false if you want them to stay active. | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// | |
// Functions | |
function runPerAccount() { | |
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_NAME)) { | |
Logger.log(Utilities.formatString('Creating label: "%s"', LOW_QS_LABEL_NAME)); | |
AdWordsApp.createLabel(LOW_QS_LABEL_NAME, 'Automatically created by QS Alert', 'red'); | |
} | |
var mutations = [ | |
{ | |
enabled: PAUSE_KEYWORDS, | |
callback: function (keyword) { | |
keyword.pause(); | |
} | |
}, | |
{ | |
enabled: LABEL_KEYWORDS, | |
callback: function (keyword, currentLabels) { | |
if (currentLabels.indexOf(LOW_QS_LABEL_NAME) === -1) { | |
keyword.applyLabel(LOW_QS_LABEL_NAME); | |
} | |
} | |
} | |
]; | |
var chunkSize = 10000; | |
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, Cost, Labels' | |
+ ' FROM KEYWORDS_PERFORMANCE_REPORT WHERE Status = "ENABLED" AND CampaignStatus = "ENABLED" AND AdGroupStatus = "ENABLED"' | |
+ ' AND HasQualityScore = "TRUE" AND QualityScore <= ' + threshold; | |
var report = AdWordsApp.report(query); | |
var rows = report.rows(); | |
var lowQSKeywords = []; | |
while (rows.hasNext()) { | |
var row = rows.next(); | |
var lowQSKeyword = { | |
campaignName: row['CampaignName'], | |
adGroupName: row['AdGroupName'], | |
keywordText: row['Criteria'], | |
cost: row['Cost'], | |
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 AdWordsApp.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 adwordsKeywords = AdWordsApp.keywords().withIds(keywordIds).get(); | |
var i = 0; | |
while (adwordsKeywords.hasNext()) { | |
var currentKeywordLabels = keywords[i]['labels']; | |
var adwordsKeyword = adwordsKeywords.next(); | |
mutationsToApply.forEach(function(mutate) { | |
mutate(adwordsKeyword, currentKeywordLabels); | |
}); | |
i++; | |
} | |
} | |
function getMutationsToApply(mutations) { | |
var enabledMutations = mutations.filter(function (mutation) { | |
return mutation['enabled']; | |
}); | |
return enabledMutations.map(function (condition) { | |
return condition['callback']; | |
}); | |
} | |
function sendEmail(keywords) { | |
var nameAccount = AdWordsApp.currentAccount().getName(); | |
var subject = "Low Quality Keywords " + nameAccount; | |
var htmlBody = | |
"<p>Keywords with a quality score of less than " + QS_THRESHOLD + " found.<p>" | |
+ "<p>Actions Taken:<p>" | |
+ "<ul>" | |
+ "<li><b>Paused</b>: " + PAUSE_KEYWORDS + "</li>" | |
+ "<li><b>Labelled</b> with <code>" + LOW_QS_LABEL_NAME + "</code>: " + LABEL_KEYWORDS + "</li>" | |
+ "</ul>" | |
+ renderTable(keywords); | |
MailApp.sendEmail({ | |
to: EMAIL_ADDRESSES.join(","), | |
subject: subject, | |
htmlBody: htmlBody | |
}); | |
} | |
function renderTable(keywords) { | |
var header = '<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">' | |
+ '<thead><tr>' | |
+ '<th>Campaign Name</th>' | |
+ '<th>Ad Group Name</th>' | |
+ '<th>Keyword Text</th>' | |
+ '<th>Quality Score</th>' | |
+ '<th>Cost</th>' | |
+ '</tr></thead><tbody>'; | |
var rows = keywords.reduce(function(accumulator, keyword) { | |
return accumulator | |
+ '<tr><td>' + [ | |
keyword['campaignName'], | |
keyword['adGroupName'], | |
keyword['keywordText'], | |
keyword['qualityScore'], | |
keyword['cost'] | |
].join('</td><td>') | |
+ '</td></tr>'; | |
}, ""); | |
var footer = '</tbody></table>'; | |
var table = header + rows + footer; | |
return table; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment