
Standards are high for PPC superheroes, and even the best of us can make a mistake.
Luckily, there’s a perfectly easy way to deal with human error: automation!
I’d like to share a script that will help you stay on top of the domains being used in your ads, by verifying the ads are linking to the correct website.
Start with a site visit
For most AdWords campaigns, the user’s journey to conversion starts with a site visit. Making sure users end up on the right page after clicking on an ad may seem obvious, but as careful as we might be, sometimes a rogue uniform resource locator (URL) slips through the cracks. This script checks if you’re inadvertently sending your potential customers to the wrong website entirely.
After setting up your accounts and campaigns, run the script with the desired domain in your AdWords account, and it will scan through your keywords and URLs to list which ones have final URLs that don’t use that domain. This could come in handy in lots of situations.
If you have different sub-domains or top-level domains for different countries or different parts of your business, this will point out that the wrong URL has sneaked in there somewhere.
For example: yourdomain.com instead of yourdomian.co.uk.
Check for old URLs
Another circumstance where I recommend using the script is after migrating to a new website. It is important to make sure the old URLs have been replaced or removed from your ads.
Have you changed your brand name? The script can also be effective if your brand name has undergone a change and you need a new domain name.
You definitely don’t want the old domain appearing in your ad; that doesn’t help you establish your new name. You also don’t want to accidentally send people to your old website instead of the new one.
Even if you have set up your redirects correctly, they will slow the page loading speed, which isn’t optimal.
According to an April 2017 report from The State of Online Retail Performance, conversions can fall by up to 20 percent for every second delay in mobile site load time in the retail sector.

This script will help you confirm whether you’ve got everything running as smoothly and speedily as possible.
Lastly, I want to mention the script is great for monitoring Google Ad Grant accounts, in which all ads are required to point to an approved domain. Avoiding mistakes is a must here.
Getting started
To use this script, make a blank Google spreadsheet for the report and note down its URL. On your AdWords interface, go to Bulk Actions, choose Scripts, then make a new one and paste in the script. Don’t forget to edit the options listed below.

Script outline

- domainName is the domain you expect to be in all your keyword and ad URLs.
- isWholeDomainName should be set to true if the domainName is everything between the https:// and the next /.
- Set it to false if domainName is the top-level domain, and you don’t mind what subdomains your ads point to.
- targetSheetUrl is the URL of your blank Google Doc spreadsheet, which the results will be written into.
- campaignNameContains and campaignNameDoesNotContain filter which campaigns the script gets data from. For example, if campaignNameContains is [“Brand”, “Generic”], then only campaigns with names containing “brand” or “generic” are included. If campaignNameDoesNotContain is [“Display”, “Competitor”], then any campaigns with names containing “display” or “competitor” are ignored.
- This is not case-sensitive.
- Leave blank, [], to include all campaigns.
- If you need to put a double quote into campaignNameContains or campaignNameDoesNotContain, put a backslash before it.
- ignorePausedCampaigns should be set to true if you only want to look at currently active campaigns, or false if you want to include them.
If you’re having trouble with the script timing out, try running the script multiple times using campaignNameContains and campaignNameDoesNotContain to look at different campaigns for each run.
And there you have it. Hopefully, your domains are all set up right, but it never hurts to be extra careful at every step, especially when a convenient script can take care of the work for you.
/** | |
* | |
* Domain Name Checker | |
* | |
* This script will scan through your keyword and ad URLs, checking the domain | |
* names for anything out of place, and output any discrepancies it finds into a | |
* Google Sheet. | |
* | |
* Version: 1.0 | |
* Google AdWords Script maintained on brainlabsdigital.com | |
* | |
**/ | |
//////////////////////////////////////////////////////////////////////////////// | |
// Options | |
var domainName = "brainlabsdigital.com"; | |
// The domain you expect to be in all your keyword and ad URLs. | |
// Can be a whole URL (www.brainlabsdigital.com) or a partial URL | |
// (brainlabsdigital.com) to cover multiple subdomains. | |
var isWholeDomainName = true; | |
// If the domain name you gave is a whole URL, set this to true. Otherwise, | |
// leave it as false. | |
var targetSheetUrl = "https://docs.google.com/YOUR-SPREADSHEET-URL-HERE"; | |
// Replace this with the URL of a blank Google Sheet; this is where the script | |
// will output its results | |
var campaignNameContains = []; | |
// Use this if you only want to look at some campaigns. | |
// For example ["Generic"] would only look at campaigns with 'generic' in the | |
// name, while ["Generic", "Competitor"] would only look at campaigns with | |
// either 'generic' or 'competitor' in the name. | |
// Leave as [] to include all campaigns. | |
var campaignNameDoesNotContain = []; | |
// Use this if you want to exclude some campaigns. | |
// For example ["Brand"] would ignore any campaigns with 'brand' in the name, | |
// while ["Brand", "Key Terms"] would ignore any campaigns with 'brand' or | |
// 'key terms' in the name. | |
// Leave as [] to not exclude any 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. | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// | |
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// | |
// Functions | |
function main() { | |
// Escape any special characters in the given domain name. | |
prepareDomainName(); | |
Logger.log("Prepared domain name for checking."); | |
// Fetch the URLs of keywords and ads attached to valid campaigns, filtering | |
// out those with the correct domain name. | |
var urlData = getUrlData(); | |
Logger.log("Fetched all URLs."); | |
var numberOfBadUrls = Object.keys(urlData).length; | |
if (numberOfBadUrls === 0) { | |
Logger.log("No incorrect URLs found."); | |
} else { | |
// Output the bad URLs and their keywords and ads to the target sheet. | |
outputToSheet(urlData); | |
Logger.log("Output " + numberOfBadUrls + " incorrect URLs to sheet."); | |
} | |
Logger.log("Finished."); | |
} | |
// Escape any special characters in the given domain name. | |
function prepareDomainName() { | |
domainName = domainName.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); | |
}; | |
// This function returns an object containing the URLs and details of keywords | |
// and ads attached to valid campaigns. | |
function getUrlData() { | |
var urlData = new Object(); | |
var expectedPattern = /./; | |
var whereStatements = ["Status = 'ENABLED'", | |
"AdGroupStatus = 'ENABLED'" | |
]; | |
if (ignorePausedCampaigns) { | |
whereStatements.push("CampaignStatus IN ['ENABLED']"); | |
} else { | |
whereStatements.push("CampaignStatus IN ['ENABLED','PAUSED']"); | |
} | |
if (isWholeDomainName) { | |
expectedPattern = new RegExp("^https?://" + domainName); | |
} else { | |
expectedPattern = new RegExp("^https?://([^/]*?\\.)*" + domainName); | |
} | |
if (campaignNameContains.length == 0) { | |
campaignNameContains.push(false); | |
} | |
for (var i = 0; i < campaignNameDoesNotContain.length; i++) { | |
whereStatements.push("CampaignName DOES_NOT_CONTAIN_IGNORE_CASE '" | |
+ campaignNameDoesNotContain[i].replace(/"/g,'\\\"') + "'"); | |
} | |
for (var i = 0; i < campaignNameContains.length; i++) { | |
if (campaignNameContains[i] === false) { | |
var finalWhereStatements = whereStatements; | |
} else { | |
var finalWhereStatements = whereStatements.concat( | |
["CampaignName CONTAINS_IGNORE_CASE '" + campaignNameContains[i] + "'"] | |
); | |
} | |
var keywordReport = AdWordsApp.report( | |
"SELECT CampaignName, AdGroupName, Criteria, FinalMobileUrls, FinalUrls " + | |
"FROM KEYWORDS_PERFORMANCE_REPORT " + | |
"WHERE FinalUrls != '--' AND " + finalWhereStatements.join(" AND ")); | |
var rows = keywordReport.rows(); | |
while (rows.hasNext()) { | |
var row = rows.next(); | |
var urls = jsonToArray(row['FinalMobileUrls']).concat( | |
jsonToArray(row['FinalUrls']) | |
); | |
for (var j in urls) { | |
var url = urls[j].toLowerCase(); | |
if (url.match(expectedPattern) === null) { | |
var rowData = {"CampaignName": row['CampaignName'], | |
"AdGroupName": row['AdGroupName'], | |
"Keyword": row['Criteria'] | |
}; | |
if (!urlData.hasOwnProperty(url)) { | |
urlData[url] = {"keywords": {}, "ads": {}}; | |
} | |
urlData[url]["keywords"][row['Id']] = rowData; | |
} | |
} | |
} | |
var adReport = AdWordsApp.report( | |
"SELECT CampaignName, AdGroupName, HeadlinePart1, HeadlinePart2, " + | |
"CreativeFinalMobileUrls, CreativeFinalUrls " + | |
"FROM AD_PERFORMANCE_REPORT " + | |
"WHERE CreativeFinalUrls != '--' AND " | |
+ finalWhereStatements.join(" AND ")); | |
var rows = adReport.rows(); | |
while (rows.hasNext()) { | |
var row = rows.next(); | |
var urls = jsonToArray(row['CreativeFinalMobileUrls']).concat( | |
jsonToArray(row['CreativeFinalUrls']) | |
); | |
for (var j in urls) { | |
var url = urls[j].toLowerCase(); | |
if (url.match(expectedPattern) === null) { | |
var rowData = {"CampaignName": row['CampaignName'], | |
"AdGroupName": row['AdGroupName'], | |
"Headline": row['HeadlinePart1'] + " - " | |
+ row['HeadlinePart2'] | |
}; | |
if (!urlData.hasOwnProperty(url)) { | |
urlData[url] = {"keywords": {}, "ads": {}}; | |
} | |
urlData[url]["ads"][rowData['Headline']] = rowData; | |
} | |
} | |
} | |
whereStatements.push("CampaignName DOES_NOT_CONTAIN_IGNORE_CASE '" | |
+ campaignNameContains[i] + "'"); | |
} | |
return urlData; | |
} | |
// This function outputs details about any invalid URLs to the given Google | |
// Sheet. | |
function outputToSheet(urlData) { | |
var ss = checkSpreadsheet(targetSheetUrl, "the spreadsheet"); | |
var keywordsSheet = ss.getSheetByName("Results - Keywords"); | |
var adsSheet = ss.getSheetByName("Results - Ads"); | |
if (keywordsSheet == null) { | |
keywordsSheet = ss.insertSheet("Results - Keywords"); | |
} | |
if (adsSheet == null) { | |
adsSheet = ss.insertSheet("Results - Ads"); | |
} | |
keywordsSheet.clear(); | |
adsSheet.clear(); | |
var keywordsRange = [["Bad URL", "Keyword", "Ad Group", "Campaign"]]; | |
var adsRange = [["Bad URL", "Ad Headline", "Ad Group", "Campaign"]]; | |
for (var url in urlData) { | |
for (var j in urlData[url]["keywords"]) { | |
var data = urlData[url]["keywords"][j]; | |
keywordsRange.push([url, | |
data["Keyword"], | |
data["AdGroupName"], | |
data["CampaignName"]]); | |
} | |
for (var j in urlData[url]["ads"]) { | |
var data = urlData[url]["ads"][j]; | |
adsRange.push([url, | |
data["Headline"], | |
data["AdGroupName"], | |
data["CampaignName"]]); | |
} | |
} | |
keywordsSheet.getRange(1,1,keywordsRange.length,4).setValues(keywordsRange); | |
adsSheet.getRange(1,1,adsRange.length,4).setValues(adsRange); | |
} | |
// A small helper function for processing AdWords report fields. | |
function jsonToArray(str) { | |
return str == "--" ? [] : JSON.parse(str); | |
} | |
// 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); | |
// Checks if you can edit the spreadsheet | |
var sheet = spreadsheet.getSheets()[0]; | |
var sheetName = sheet.getName(); | |
sheet.setName(sheetName); | |
return spreadsheet; | |
} catch (e) { | |
throw("Problem with " + spreadsheetName + " URL: '" + e + "'"); | |
} | |
} |
The post Are your ads pointing to the right domain? Here’s a script to find out. appeared first on Search Engine Land.
from SEO Rank Video Blog https://ift.tt/2IZhVSg
via IFTTT
No comments:
Post a Comment