-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlow-quality-score-alert.js
More file actions
197 lines (164 loc) · 5.69 KB
/
low-quality-score-alert.js
File metadata and controls
197 lines (164 loc) · 5.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// ID: 61daad0e8fb8188eb2257bc8ee01bc5b
/**
*
* 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 = ["alice@example.com", "bob@example.co.uk"];
// The address or addresses that will be emailed a list of low QS keywords
// eg ["alice@example.com", "bob@example.co.uk"] or ["eve@example.org"]
var QS_THRESHOLD = 3;
// Keywords with quality score less than or equal to this number are
// considered 'low QS'
var LABEL_KEYWORDS = true;
// 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 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_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, 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'],
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 subject = "Low Quality Keywords Paused";
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>'
+ '</tr></thead><tbody>';
var rows = keywords.reduce(function (accumulator, keyword) {
return accumulator
+ '<tr><td>' + [
keyword['campaignName'],
keyword['adGroupName'],
keyword['keywordText'],
keyword['qualityScore']
].join('</td><td>')
+ '</td></tr>';
}, "");
var footer = '</tbody></table>';
var table = header + rows + footer;
return table;
}