-
-
Save BrainlabsDigital/df8fe8fb5bed16e3d882e1642e3dcad5 to your computer and use it in GitHub Desktop.
/** | |
* | |
* AdWords Script for keyword and ad checking. | |
* Checks keyword text for punctuation suggesting the wrong match type, checks | |
* broad match keywords for missing BMM. Checks ad text for text that suggests | |
* ads are out-of-date (like previous years) and for common English spelling | |
* mistakes. | |
* | |
* Version: 1.1 | |
* Updated 2017-01-05: changed 'CreativeApprovalStatus' to 'CombinedApprovalStatus' | |
* Google AdWords Script maintained by brainlabsdigital.com | |
* | |
**/ | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// | |
//Options | |
var spreadsheetUrl = "https://docs.google.com/YOUR-SPREADSHEET-URL-HERE"; | |
// The URL of the Google Doc the results will be put into. | |
var campaignNameDoesNotContain = []; | |
// Use this if you want to exclude some campaigns. | |
// For example ["Display"] would ignore any campaigns with 'Display' in the name, | |
// while ["Display","Shopping"] would ignore any campaigns with 'Display' or | |
// 'Shopping' in the name. | |
// Leave as [] to not exclude any campaigns. | |
var campaignNameContains = []; | |
// Use this if you only want to look at some campaigns. | |
// 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. | |
var ignorePausedCampaigns = true; | |
// Set this to true to only look at currently active campaigns. | |
// Set to false to include campaigns that had impressions but are currently paused. | |
var checkKeywords = true; | |
// Set this to true to look at keyword text for errors like missing BMM. | |
var checkAdText = true; | |
// Set this to true to look at ad text for errors like previous years. | |
var checkSpelling = true; | |
// Set this to true to check ad text for some common spelling errors. | |
var checkAdsFor = ["2013", "2014", "2015", "Easter"]; | |
// This is the text that the script will look for in ad copy. Feel free to add more! | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// | |
// Advanced Options | |
var misspellingsSheetUrl = "https://docs.google.com/spreadsheets/d/1Z2Fg_F8WhmY8Ey5Bv4Zuk8vcTW7A2EoVwMbGVz7TNms/edit#gid=0"; | |
// This spreadsheet has the list of English spelling errors, used if checkSpelling | |
// is true. | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// | |
// Functions | |
function main() { | |
var spreadsheet = checkSpreadsheet(spreadsheetUrl, "the spreadsheet"); | |
var sheet = spreadsheet.getSheets()[0]; | |
var campaignIds = getCampaignIds(); | |
if (checkKeywords) { | |
keywordChecking(campaignIds, sheet); | |
Logger.log("Finished keyword checks."); | |
} | |
if (checkAdText) { | |
adTextChecking(campaignIds, sheet); | |
Logger.log("Finished ad text checks."); | |
} | |
if (checkSpelling) { | |
adSpellingChecking(campaignIds, sheet); | |
Logger.log("Finished common misspelling checks."); | |
} | |
} | |
// Check the spreadsheet URL has been entered, and that it works | |
function checkSpreadsheet(spreadsheetUrl, spreadsheetName) { | |
if (spreadsheetUrl.replace(/[AEIOU]/g,"X") == "https://docs.google.com/YXXR-SPRXXDSHXXT-XRL-HXRX") { | |
throw("Problem with " + spreadsheetName + " URL: make sure you've replaced the default with a valid spreadsheet URL."); | |
} | |
try { | |
var spreadsheet = SpreadsheetApp.openByUrl(spreadsheetUrl); | |
return spreadsheet; | |
} catch (e) { | |
throw("Problem with " + spreadsheetName + " URL: '" + e + "'"); | |
} | |
} | |
// Get the IDs of campaigns which match the given options | |
function getCampaignIds() { | |
var whereStatement = "WHERE "; | |
var whereStatementsArray = []; | |
var campaignIds = []; | |
if (ignorePausedCampaigns) { | |
whereStatement += "CampaignStatus = ENABLED "; | |
} else { | |
whereStatement += "CampaignStatus IN ['ENABLED','PAUSED'] "; | |
} | |
for (var i=0; i<campaignNameDoesNotContain.length; i++) { | |
whereStatement += "AND CampaignName DOES_NOT_CONTAIN_IGNORE_CASE '" + campaignNameDoesNotContain[i].replace(/"/g,'\\\"') + "' "; | |
} | |
if (campaignNameContains.length == 0) { | |
whereStatementsArray = [whereStatement]; | |
} else { | |
for (var i=0; i<campaignNameContains.length; i++) { | |
whereStatementsArray.push(whereStatement + 'AND CampaignName CONTAINS_IGNORE_CASE "' + campaignNameContains[i].replace(/"/g,'\\\"') + '" '); | |
} | |
} | |
for (var i=0; i<whereStatementsArray.length; i++) { | |
var adTextReport = AdWordsApp.report( | |
"SELECT CampaignId " + | |
"FROM CAMPAIGN_PERFORMANCE_REPORT " + | |
whereStatementsArray[i] + | |
"DURING LAST_30_DAYS"); | |
var rows = adTextReport.rows(); | |
while (rows.hasNext()) { | |
var row = rows.next(); | |
campaignIds.push(row['CampaignId']); | |
} | |
} | |
if (campaignIds.length == 0) { | |
throw("No campaigns found with the given settings."); | |
} | |
Logger.log(campaignIds.length + " campaigns found"); | |
return campaignIds; | |
} | |
// Prints an array of rows into the spreadsheet | |
function printRows(sheet, title, headers, rows) { | |
try { | |
var printArray = []; | |
sheet.getRange("R" + (sheet.getLastRow()+2) + "C1").setValue(title); | |
if (rows.length == 0) { | |
sheet.appendRow(["No issues found"]); | |
Logger.log("Nothing to output for '" + title + "'"); | |
return; | |
} | |
sheet.appendRow(headers); | |
for (var i=0; i < rows.length; i++) { | |
printArray.push(rows[i]); | |
} | |
var lastRow = sheet.getLastRow(); | |
sheet.getRange("R" + (lastRow + 1) + "C1:R" + (lastRow+printArray.length) | |
+ "C" + (printArray[0].length) ).setValues(printArray); | |
Logger.log("Printed " + rows.length + " rows for '" + title + "'"); | |
} catch (e) { | |
Logger.log("Printing rows '" + title + "' failed: " + e); | |
} | |
} | |
function keywordChecking(campaignIds, sheet) { | |
try { | |
var broadMissingPlusses = []; | |
var nonBroadWithPlusses = []; | |
var nonExactWithBrackets = []; | |
var nonPhraseWithQuotes = []; | |
var keywordMatchReport = AdWordsApp.report( | |
"SELECT CampaignName, AdGroupName, Criteria, KeywordMatchType " + | |
"FROM KEYWORDS_PERFORMANCE_REPORT " + | |
"WHERE AdGroupStatus = ENABLED AND Status = ENABLED AND IsNegative = FALSE " + | |
"AND CampaignId IN [" + campaignIds.join(",") + "] " + | |
"DURING LAST_30_DAYS"); | |
var keywordMatchRows = keywordMatchReport.rows(); | |
while (keywordMatchRows.hasNext()) { | |
var keywordMatchRow = keywordMatchRows.next(); | |
if (keywordMatchRow["KeywordMatchType"].toLowerCase() === "broad") { | |
if(keywordMatchRow["Criteria"].indexOf("+") <0) { | |
//if the broad KW is entirely missing +s | |
broadMissingPlusses.push([keywordMatchRow["CampaignName"],keywordMatchRow["AdGroupName"],"'"+keywordMatchRow["Criteria"],keywordMatchRow["KeywordMatchType"]]); | |
} else { | |
// check that each word starts with a + | |
var words = keywordMatchRow["Criteria"].split(" "); | |
var missingPlus = false; | |
for (var j=0; j<words.length; j++) { | |
if (words[j].substr(0,1) != "+") { | |
missingPlus = true; | |
break; | |
} | |
} | |
if (missingPlus) { | |
broadMissingPlusses.push([keywordMatchRow["CampaignName"],keywordMatchRow["AdGroupName"],"'"+keywordMatchRow["Criteria"],keywordMatchRow["KeywordMatchType"]]); | |
} | |
} | |
} else { | |
// If the keyword is not broad | |
if(keywordMatchRow["Criteria"].indexOf("+") > -1) { | |
nonBroadWithPlusses.push([keywordMatchRow["CampaignName"],keywordMatchRow["AdGroupName"],"'"+keywordMatchRow["Criteria"],keywordMatchRow["KeywordMatchType"]]); | |
} | |
} | |
if (keywordMatchRow["KeywordMatchType"].toLowerCase() != "exact") { | |
if(keywordMatchRow["Criteria"].indexOf("[") > -1 || keywordMatchRow["Criteria"].indexOf("]") > -1) { | |
nonExactWithBrackets.push([keywordMatchRow["CampaignName"],keywordMatchRow["AdGroupName"],"'"+keywordMatchRow["Criteria"],keywordMatchRow["KeywordMatchType"]]); | |
} | |
} | |
if (keywordMatchRow["KeywordMatchType"].toLowerCase() != "phrase") { | |
if(keywordMatchRow["Criteria"].indexOf('"') > -1) { | |
nonPhraseWithQuotes.push([keywordMatchRow["CampaignName"],keywordMatchRow["AdGroupName"],"'"+keywordMatchRow["Criteria"],keywordMatchRow["KeywordMatchType"]]); | |
} | |
} | |
}//end while | |
var headers = ["Campaign", "Ad Group", "Keyword", "Match"]; | |
printRows(sheet, "Broad Match Keywords Missing +s", headers, broadMissingPlusses); | |
printRows(sheet, "Non-Broad Match Keywords With +s", headers, nonBroadWithPlusses); | |
printRows(sheet, "Non-Exact Match Keywords With [ or ]", headers, nonExactWithBrackets); | |
printRows(sheet, 'Non-Phrase Match Keywords With "s', headers, nonPhraseWithQuotes); | |
} catch (e) { | |
Logger.log("Keyword checking failed: " + e); | |
} | |
} // end function keywordChecking | |
function adTextChecking(campaignIds, sheet) { | |
try { | |
var adLines = ['Headline', 'Description1', 'Description2', 'DisplayUrl']; | |
var adsWithBadText = []; | |
var patterns = []; | |
var charactersToEscape = ["\\", "/", ".", "?", "+", "*", "^", "$", "[", "]", "(", ")", "{", "}"]; | |
for (var k=0; k<checkAdsFor.length; k++) { | |
var cleanedText = checkAdsFor[k].toLowerCase(); | |
for (var i=0; i<charactersToEscape.length; i++) { | |
cleanedText = cleanedText.replace(charactersToEscape[i],"\\" + charactersToEscape[i]); | |
} | |
patterns.push( RegExp("(^|\\W)" + cleanedText + "($|\\W)")); | |
} | |
var adTextReport = AdWordsApp.report( | |
"SELECT CampaignName, AdGroupName, Headline, Description1, Description2, DisplayUrl " + | |
"FROM AD_PERFORMANCE_REPORT " + | |
"WHERE AdGroupStatus = ENABLED AND Status = ENABLED " + | |
"AND AdType = TEXT_AD AND CombinedApprovalStatus != DISAPPROVED " + | |
"AND CampaignId IN [" + campaignIds.join(",") + "] " + | |
"DURING LAST_30_DAYS"); | |
var rows = adTextReport.rows(); | |
while (rows.hasNext()) { | |
var row = rows.next(); | |
var adCopy = ""; | |
for (var j=0; j<adLines.length; j++) { | |
adCopy += " " + row[adLines[j]]; | |
} | |
adCopy = adCopy.toLowerCase(); | |
var textFound = []; | |
for (var k=0; k<checkAdsFor.length; k++) { | |
if (adCopy.match(patterns[k])) { | |
textFound.push(checkAdsFor[k]); | |
} | |
} | |
if (textFound.length > 0) { | |
adsWithBadText.push([row["CampaignName"], row["AdGroupName"], row['Headline'], | |
row['Description1'], row['Description2'], row['DisplayUrl'], | |
textFound.join(", ")]); | |
} | |
} // end while | |
var headers = ["Campaign", "Ad Group", 'Headline', 'Description 1', 'Description 2', | |
'Display Url', 'Problematic Text']; | |
printRows(sheet, "Ad Copy With Problematic Text", headers, adsWithBadText); | |
} catch (e) { | |
Logger.log("Ad text checking failed: " + e); | |
} | |
} // function adTextChecking | |
function adSpellingChecking(campaignIds, sheet) { | |
try { | |
var misspellingsSpreadsheet = checkSpreadsheet(misspellingsSheetUrl, "the misspelling spreadsheet"); | |
var misspellingsSheet = misspellingsSpreadsheet.getSheets()[0]; | |
var misspellings = misspellingsSheet.getRange(2, 1, misspellingsSheet.getLastRow()-1, 2).getValues() | |
for (var k=0; k<misspellings.length; k++) { | |
misspellings[k][0] = " " + misspellings[k][0] + " "; | |
} | |
var adLines = ['Headline', 'Description1', 'Description2', 'DisplayUrl']; | |
var adsWithBadText = []; | |
var adTextReport = AdWordsApp.report( | |
"SELECT CampaignName, AdGroupName, Headline, Description1, Description2, DisplayUrl " + | |
"FROM AD_PERFORMANCE_REPORT " + | |
"WHERE AdGroupStatus = ENABLED AND Status = ENABLED " + | |
"AND AdType = TEXT_AD AND CombinedApprovalStatus != DISAPPROVED " + | |
"AND CampaignId IN [" + campaignIds.join(",") + "] " + | |
"DURING LAST_30_DAYS"); | |
var rows = adTextReport.rows(); | |
while (rows.hasNext()) { | |
var row = rows.next(); | |
var adCopy = " "; | |
for (var j=0; j<adLines.length; j++) { | |
adCopy += " " + row[adLines[j]]; | |
} | |
adCopy += " "; | |
adCopy = adCopy.toLowerCase(); | |
adCopy = adCopy.replace(/(_|[^\w\-'0-9])/g," "); | |
var textFound = []; | |
var didYouMean = []; | |
for (var k=0; k<misspellings.length; k++) { | |
if (adCopy.indexOf(misspellings[k][0]) > -1) { | |
textFound.push(misspellings[k][0].trim()); | |
didYouMean.push(misspellings[k][1]); | |
} | |
} | |
if (textFound.length > 0) { | |
adsWithBadText.push([row["CampaignName"], row["AdGroupName"], row['Headline'], | |
row['Description1'], row['Description2'], row['DisplayUrl'], | |
textFound.join(", "), didYouMean.join(", ")]); | |
} | |
} // end while | |
var headers = ["Campaign", "Ad Group", 'Headline', 'Description 1', 'Description 2', | |
'Display Url', 'Possible Misspelling', 'Possible Corrections']; | |
printRows(sheet, "Ad Copy With Possible Misspellings", headers, adsWithBadText); | |
} catch (e) { | |
Logger.log("Ad spell checking failed: " + e); | |
} | |
} // function adSpellingChecking |
I'm thinking that the ad checking parts are using the old text ad names, not ones updated for the new expanded text ads.
This code should work - I've commented out the old code & added the updated items:
**
*
- AdWords Script for keyword and ad checking.
- Checks keyword text for punctuation suggesting the wrong match type, checks
- broad match keywords for missing BMM. Checks ad text for text that suggests
- ads are out-of-date (like previous years) and for common English spelling
- mistakes.
- Version: 1.1
- Updated 2017-01-05: changed 'CreativeApprovalStatus' to 'CombinedApprovalStatus'
- Google AdWords Script maintained by brainlabsdigital.com
- MODIFIED by Markg7 15-6-18 - Checks extended text ads rather than old text ad format
**/
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//Options
var spreadsheetUrl = "https://docs.google.com/YOUR-SPREADSHEET-URL-HERE";
// The URL of the Google Doc the results will be put into.
var campaignNameDoesNotContain = [];
// Use this if you want to exclude some campaigns.
// For example ["Display"] would ignore any campaigns with 'Display' in the name,
// while ["Display","Shopping"] would ignore any campaigns with 'Display' or
// 'Shopping' in the name.
// Leave as [] to not exclude any campaigns.
var campaignNameContains = [];
// Use this if you only want to look at some campaigns.
// 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.
var ignorePausedCampaigns = true;
// Set this to true to only look at currently active campaigns.
// Set to false to include campaigns that had impressions but are currently paused.
var checkKeywords = true;
// Set this to true to look at keyword text for errors like missing BMM.
var checkAdText = true;
// Set this to true to look at ad text for errors like previous years.
var checkSpelling = true;
// Set this to true to check ad text for some common spelling errors.
var checkAdsFor = ["2013", "2014", "2015", "Easter"];
// This is the text that the script will look for in ad copy. Feel free to add more!
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Advanced Options
var misspellingsSheetUrl = "https://docs.google.com/spreadsheets/d/1Z2Fg_F8WhmY8Ey5Bv4Zuk8vcTW7A2EoVwMbGVz7TNms/edit#gid=0";
// This spreadsheet has the list of English spelling errors, used if checkSpelling
// is true.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
// Functions
function main() {
var spreadsheet = checkSpreadsheet(spreadsheetUrl, "the spreadsheet");
var sheet = spreadsheet.getSheets()[0];
var campaignIds = getCampaignIds();
if (checkKeywords) {
keywordChecking(campaignIds, sheet);
Logger.log("Finished keyword checks.");
}
if (checkAdText) {
adTextChecking(campaignIds, sheet);
Logger.log("Finished ad text checks.");
}
if (checkSpelling) {
adSpellingChecking(campaignIds, sheet);
Logger.log("Finished common misspelling checks.");
}
}
// Check the spreadsheet URL has been entered, and that it works
function checkSpreadsheet(spreadsheetUrl, spreadsheetName) {
if (spreadsheetUrl.replace(/[AEIOU]/g,"X") == "https://docs.google.com/YXXR-SPRXXDSHXXT-XRL-HXRX") {
throw("Problem with " + spreadsheetName + " URL: make sure you've replaced the default with a valid spreadsheet URL.");
}
try {
var spreadsheet = SpreadsheetApp.openByUrl(spreadsheetUrl);
return spreadsheet;
} catch (e) {
throw("Problem with " + spreadsheetName + " URL: '" + e + "'");
}
}
// Get the IDs of campaigns which match the given options
function getCampaignIds() {
var whereStatement = "WHERE ";
var whereStatementsArray = [];
var campaignIds = [];
if (ignorePausedCampaigns) {
whereStatement += "CampaignStatus = ENABLED ";
} else {
whereStatement += "CampaignStatus IN ['ENABLED','PAUSED'] ";
}
for (var i=0; i<campaignNameDoesNotContain.length; i++) {
whereStatement += "AND CampaignName DOES_NOT_CONTAIN_IGNORE_CASE '" + campaignNameDoesNotContain[i].replace(/"/g,'\"') + "' ";
}
if (campaignNameContains.length == 0) {
whereStatementsArray = [whereStatement];
} else {
for (var i=0; i<campaignNameContains.length; i++) {
whereStatementsArray.push(whereStatement + 'AND CampaignName CONTAINS_IGNORE_CASE "' + campaignNameContains[i].replace(/"/g,'\"') + '" ');
}
}
for (var i=0; i<whereStatementsArray.length; i++) {
var adTextReport = AdWordsApp.report(
"SELECT CampaignId " +
"FROM CAMPAIGN_PERFORMANCE_REPORT " +
whereStatementsArray[i] +
"DURING LAST_30_DAYS");
var rows = adTextReport.rows();
while (rows.hasNext()) {
var row = rows.next();
campaignIds.push(row['CampaignId']);
}
}
if (campaignIds.length == 0) {
throw("No campaigns found with the given settings.");
}
Logger.log(campaignIds.length + " campaigns found");
return campaignIds;
}
// Prints an array of rows into the spreadsheet
function printRows(sheet, title, headers, rows) {
try {
var printArray = [];
sheet.getRange("R" + (sheet.getLastRow()+2) + "C1").setValue(title);
if (rows.length == 0) {
sheet.appendRow(["No issues found"]);
Logger.log("Nothing to output for '" + title + "'");
return;
}
sheet.appendRow(headers);
for (var i=0; i < rows.length; i++) {
printArray.push(rows[i]);
}
var lastRow = sheet.getLastRow();
sheet.getRange("R" + (lastRow + 1) + "C1:R" + (lastRow+printArray.length)
+ "C" + (printArray[0].length) ).setValues(printArray);
Logger.log("Printed " + rows.length + " rows for '" + title + "'");
} catch (e) {
Logger.log("Printing rows '" + title + "' failed: " + e);
}
}
function keywordChecking(campaignIds, sheet) {
try {
var broadMissingPlusses = [];
var nonBroadWithPlusses = [];
var nonExactWithBrackets = [];
var nonPhraseWithQuotes = [];
var keywordMatchReport = AdWordsApp.report(
"SELECT CampaignName, AdGroupName, Criteria, KeywordMatchType " +
"FROM KEYWORDS_PERFORMANCE_REPORT " +
"WHERE AdGroupStatus = ENABLED AND Status = ENABLED AND IsNegative = FALSE " +
"AND CampaignId IN [" + campaignIds.join(",") + "] " +
"DURING LAST_30_DAYS");
var keywordMatchRows = keywordMatchReport.rows();
while (keywordMatchRows.hasNext()) {
var keywordMatchRow = keywordMatchRows.next();
if (keywordMatchRow["KeywordMatchType"].toLowerCase() === "broad") {
if(keywordMatchRow["Criteria"].indexOf("+") <0) {
//if the broad KW is entirely missing +s
broadMissingPlusses.push([keywordMatchRow["CampaignName"],keywordMatchRow["AdGroupName"],"'"+keywordMatchRow["Criteria"],keywordMatchRow["KeywordMatchType"]]);
} else {
// check that each word starts with a +
var words = keywordMatchRow["Criteria"].split(" ");
var missingPlus = false;
for (var j=0; j<words.length; j++) {
if (words[j].substr(0,1) != "+") {
missingPlus = true;
break;
}
}
if (missingPlus) {
broadMissingPlusses.push([keywordMatchRow["CampaignName"],keywordMatchRow["AdGroupName"],"'"+keywordMatchRow["Criteria"],keywordMatchRow["KeywordMatchType"]]);
}
}
} else {
// If the keyword is not broad
if(keywordMatchRow["Criteria"].indexOf("+") > -1) {
nonBroadWithPlusses.push([keywordMatchRow["CampaignName"],keywordMatchRow["AdGroupName"],"'"+keywordMatchRow["Criteria"],keywordMatchRow["KeywordMatchType"]]);
}
}
if (keywordMatchRow["KeywordMatchType"].toLowerCase() != "exact") {
if(keywordMatchRow["Criteria"].indexOf("[") > -1 || keywordMatchRow["Criteria"].indexOf("]") > -1) {
nonExactWithBrackets.push([keywordMatchRow["CampaignName"],keywordMatchRow["AdGroupName"],"'"+keywordMatchRow["Criteria"],keywordMatchRow["KeywordMatchType"]]);
}
}
if (keywordMatchRow["KeywordMatchType"].toLowerCase() != "phrase") {
if(keywordMatchRow["Criteria"].indexOf('"') > -1) {
nonPhraseWithQuotes.push([keywordMatchRow["CampaignName"],keywordMatchRow["AdGroupName"],"'"+keywordMatchRow["Criteria"],keywordMatchRow["KeywordMatchType"]]);
}
}
}//end while
var headers = ["Campaign", "Ad Group", "Keyword", "Match"];
printRows(sheet, "Broad Match Keywords Missing +s", headers, broadMissingPlusses);
printRows(sheet, "Non-Broad Match Keywords With +s", headers, nonBroadWithPlusses);
printRows(sheet, "Non-Exact Match Keywords With [ or ]", headers, nonExactWithBrackets);
printRows(sheet, 'Non-Phrase Match Keywords With "s', headers, nonPhraseWithQuotes);
} catch (e) {
Logger.log("Keyword checking failed: " + e);
}
} // end function keywordChecking
function adTextChecking(campaignIds, sheet) {
try {
// var adLines = ['Headline', 'Description1', 'Description2', 'DisplayUrl'];
var adLines = ['HeadlinePart1', 'HeadlinePart2', 'Description', 'Path1', 'Path2'];
var adsWithBadText = [];
var patterns = [];
var charactersToEscape = ["\", "/", ".", "?", "+", "*", "^", "$", "[", "]", "(", ")", "{", "}"];
for (var k=0; k<checkAdsFor.length; k++) {
var cleanedText = checkAdsFor[k].toLowerCase();
for (var i=0; i<charactersToEscape.length; i++) {
cleanedText = cleanedText.replace(charactersToEscape[i],"\" + charactersToEscape[i]);
}
patterns.push( RegExp("(^|\W)" + cleanedText + "($|\W)"));
}
var adTextReport = AdWordsApp.report(
//"SELECT CampaignName, AdGroupName, Headline, Description1, Description2, DisplayUrl " +
"SELECT CampaignName, AdGroupName, HeadlinePart1, HeadlinePart2, Description, Path1, Path2 " +
"FROM AD_PERFORMANCE_REPORT " +
"WHERE AdGroupStatus = ENABLED AND Status = ENABLED " +
//"AND AdType = TEXT_AD AND CombinedApprovalStatus != DISAPPROVED " +
"AND AdType = EXPANDED_TEXT_AD AND CombinedApprovalStatus != DISAPPROVED " +
"AND CampaignId IN [" + campaignIds.join(",") + "] " +
"DURING LAST_30_DAYS");
var rows = adTextReport.rows();
while (rows.hasNext()) {
var row = rows.next();
var adCopy = "";
for (var j=0; j<adLines.length; j++) {
adCopy += " " + row[adLines[j]];
}
adCopy = adCopy.toLowerCase();
var textFound = [];
for (var k=0; k<checkAdsFor.length; k++) {
if (adCopy.match(patterns[k])) {
textFound.push(checkAdsFor[k]);
}
}
if (textFound.length > 0) {
//adsWithBadText.push([row["CampaignName"], row["AdGroupName"], row['Headline'],
// row['Description1'], row['Description2'], row['DisplayUrl'],
// textFound.join(", ")]);
adsWithBadText.push([row["CampaignName"], row["AdGroupName"], row['HeadlinePart1'],
row['HeadlinePart2'], row['Description'], row['Path1'], row['Path2'],
textFound.join(", ")]);
}
} // end while
//var headers = ["Campaign", "Ad Group", 'Headline', 'Description 1', 'Description 2',
// 'Display Url', 'Problematic Text'];
var headers = ["Campaign", "Ad Group", 'HeadlinePart1', 'HeadlinePart2', 'Description',
'Path1', 'Path2', 'Problematic Text'];
printRows(sheet, "Ad Copy With Problematic Text", headers, adsWithBadText);
} catch (e) {
Logger.log("Ad text checking failed: " + e);
}
} // function adTextChecking
function adSpellingChecking(campaignIds, sheet) {
try {
var misspellingsSpreadsheet = checkSpreadsheet(misspellingsSheetUrl, "the misspelling spreadsheet");
var misspellingsSheet = misspellingsSpreadsheet.getSheets()[0];
var misspellings = misspellingsSheet.getRange(2, 1, misspellingsSheet.getLastRow()-1, 2).getValues()
for (var k=0; k<misspellings.length; k++) {
misspellings[k][0] = " " + misspellings[k][0] + " ";
}
//var adLines = ['Headline', 'Description1', 'Description2', 'DisplayUrl'];
var adLines = ['HeadlinePart1', 'HeadlinePart2', 'Description', 'Path1', 'Path2'];
var adsWithBadText = [];
var adTextReport = AdWordsApp.report(
//"SELECT CampaignName, AdGroupName, Headline, Description1, Description2, DisplayUrl " +
"SELECT CampaignName, AdGroupName, HeadlinePart1, HeadlinePart2, Description, Path1, Path2 " +
"FROM AD_PERFORMANCE_REPORT " +
"WHERE AdGroupStatus = ENABLED AND Status = ENABLED " +
//"AND AdType = TEXT_AD AND CombinedApprovalStatus != DISAPPROVED " +
"AND AdType = EXPANDED_TEXT_AD AND CombinedApprovalStatus != DISAPPROVED " +
"AND CampaignId IN [" + campaignIds.join(",") + "] " +
"DURING LAST_30_DAYS");
var rows = adTextReport.rows();
while (rows.hasNext()) {
var row = rows.next();
var adCopy = " ";
for (var j=0; j<adLines.length; j++) {
adCopy += " " + row[adLines[j]];
}
adCopy += " ";
adCopy = adCopy.toLowerCase();
adCopy = adCopy.replace(/(_|[^\w\-'0-9])/g," ");
var textFound = [];
var didYouMean = [];
for (var k=0; k<misspellings.length; k++) {
if (adCopy.indexOf(misspellings[k][0]) > -1) {
textFound.push(misspellings[k][0].trim());
didYouMean.push(misspellings[k][1]);
}
}
if (textFound.length > 0) {
//adsWithBadText.push([row["CampaignName"], row["AdGroupName"], row['Headline'],
// row['Description1'], row['Description2'], row['DisplayUrl'],
adsWithBadText.push([row["CampaignName"], row["AdGroupName"], row['HeadlinePart1'],
row['HeadlinePart2'], row['Description'], row['Path1'], row['Path2'],
textFound.join(", "), didYouMean.join(", ")]);
}
} // end while
//var headers = ["Campaign", "Ad Group", 'Headline', 'Description 1', 'Description 2',
// 'Display Url', 'Possible Misspelling', 'Possible Corrections'];
var headers = ["Campaign", "Ad Group", 'HeadlinePart1', 'HeadlinePart2', 'Description',
'Path1', 'Path2', 'Possible Misspelling', 'Possible Corrections'];
printRows(sheet, "Ad Copy With Possible Misspellings", headers, adsWithBadText);
} catch (e) {
Logger.log("Ad spell checking failed: " + e);
}
} // function adSpellingChecking
Has anyone tested this? The keyword checker is great, but I tried inserting several of the Common Misspellings into my ads and the script couldn't identify them.