As a follow up to my questions about cool scripts for Black Friday / Cyber Monday, today I put together a script to run through your urls and check if the item is out of stock on the website. If it is, we will pause the AdGroup.
This script has some of the same elements of my script on checking for broken links in your account, but it actually pulls the html source of each page and searches for a configurable string that lets it know when it is out of stock.
Let's walk through an example. I love some of the quirky gifts I find on ModCloth.com. But like any online store, some items go out of stock. Here is one I found while testing this script.
In order to get this script to work, I need to find out what is different about the page when it goes out of stock. If I right click and view the page source, and search for the work "stock", I can see a few different places where it is used. One of them is the following that says "in_stock":false.
That looks promising. I check on an in stock item and sure enough, "in_stock":true is on that page.
Alright, so now I know what text I need to use to fill in the OUT_OF_STOCK_TEXT variable in my code. Now each site is going to be a little different, so I have a simple script that uses the same url logic as the complete script that you can use for testing.
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
/************************************ | |
* Quick Url In Stock/Out Of Stock Checker | |
* Version 1.0 | |
* Created By: Russ Savage | |
* FreeAdWordsScripts.com | |
***********************************/ | |
var STRIP_QUERY_STRING = true; | |
var WRAPPED_URLS = true; | |
var OUT_OF_STOCK_TEXT = 'The Text That Identifies An Out Of Stock Item Goes Here'; | |
var URL_TO_TEST = 'Your Url To Check Goes Here'; | |
function main() { | |
var urlToTest = URL_TO_TEST; | |
urlToTest = cleanUrl(urlToTest); | |
var htmlCode = UrlFetchApp.fetch(urlToTest).getContentText(); | |
if(htmlCode.indexOf(OUT_OF_STOCK_TEXT) >= 0) { | |
Logger.log('The item is out of stock.'); | |
} else { | |
Logger.log('The item is in stock.'); | |
} | |
} | |
function cleanUrl(url) { | |
if(WRAPPED_URLS) { | |
url = url.substr(url.lastIndexOf('http')); | |
if(decodeURIComponent(url) !== url) { | |
url = decodeURIComponent(url); | |
} | |
} | |
if(STRIP_QUERY_STRING) { | |
if(url.indexOf('?')>=0) { | |
url = url.split('?')[0]; | |
} | |
} | |
if(url.indexOf('{') >= 0) { | |
//Let's remove the value track parameters | |
url = url.replace(/\{[0-9a-zA-Z]+\}/g,''); | |
} | |
return url; | |
} |
Once you find some HTML text in the source of the landing page that identifies if an item is out of stock, you should be good to go on the full script. There are a few other options in the script that allow you to enable or disable various url manipulations in the script. And remember, this will pause only the Ads or Keywords that link to the page with the out of stock item.
Thanks,
Russ
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
/************************************ | |
* Item Out Of Stock Checker | |
* Version 1.2 | |
* ChangeLog v1.2 | |
* - ONLY_ACTIVE is used to filter campaigns and adgroups only. All Keywords and Ads in the AdGroups will | |
* be checked which solves the "once disabled, always disabled" issue. | |
* - Updated call to get the Final Urls. Now calls getFinalUrl and getMobileFinalUrl instead of getDestinationUrl | |
* - OUT_OF_STOCK_TEXTS can now contain multiple things to check for. | |
* - If the CAMPAIGN_LABEL does not exist, it is ignored with a warning. | |
* ChangeLog v1.1 - Filtered out deleted Campaigns and AdGroups | |
* Created By: Russ Savage | |
* FreeAdWordsScripts.com | |
***********************************/ | |
var URL_LEVEL = 'Ad'; // or Keyword | |
var ONLY_ACTIVE = true; // set to false to check keywords or ads in all campaigns (paused and active) | |
var CAMPAIGN_LABEL = ''; // set this if you want to only check campaigns with this label | |
var STRIP_QUERY_STRING = true; // set this to false if the stuff that comes after the question mark is important | |
var WRAPPED_URLS = true; // set this to true if you use a 3rd party like Marin or Kenshoo for managing you account | |
// This is the specific text (or texts) to search for | |
// on the page that indicates the item | |
// is out of stock. If ANY of these match the html | |
// on the page, the item is considered "out of stock" | |
var OUT_OF_STOCK_TEXTS = [ | |
'The Text That Identifies An Out Of Stock Item Goes Here', | |
'Another string might go here but does not need to' | |
]; | |
function main() { | |
var alreadyCheckedUrls = {}; | |
var iter = buildSelector().get(); | |
while(iter.hasNext()) { | |
var entity = iter.next(); | |
var urls = []; | |
if(entity.urls().getFinalUrl()) { | |
urls.push(entity.urls().getFinalUrl()); | |
} | |
if(entity.urls().getMobileFinalUrl()) { | |
urls.push(entity.urls().getMobileFinalUrl()); | |
} | |
for(var i in urls) { | |
var url = cleanUrl(urls[i]); | |
if(alreadyCheckedUrls[url]) { | |
if(alreadyCheckedUrls[url] === 'out of stock') { | |
entity.pause(); | |
} else { | |
entity.enable(); | |
} | |
} else { | |
var htmlCode; | |
try { | |
htmlCode = UrlFetchApp.fetch(url).getContentText(); | |
} catch(e) { | |
Logger.log('There was an issue checking:'+url+', Skipping.'); | |
continue; | |
} | |
var did_pause = false; | |
for(var x in OUT_OF_STOCK_TEXTS) { | |
if(htmlCode.indexOf(OUT_OF_STOCK_TEXTS[x]) >= 0) { | |
alreadyCheckedUrls[url] = 'out of stock'; | |
entity.pause(); | |
did_pause = true; | |
break; | |
} | |
} | |
if(!did_pause) { | |
alreadyCheckedUrls[url] = 'in stock'; | |
entity.enable(); | |
} | |
} | |
Logger.log('Url: '+url+' is '+alreadyCheckedUrls[url]); | |
} | |
} | |
} | |
function cleanUrl(url) { | |
if(WRAPPED_URLS) { | |
url = url.substr(url.lastIndexOf('http')); | |
if(decodeURIComponent(url) !== url) { | |
url = decodeURIComponent(url); | |
} | |
} | |
if(STRIP_QUERY_STRING) { | |
if(url.indexOf('?')>=0) { | |
url = url.split('?')[0]; | |
} | |
} | |
if(url.indexOf('{') >= 0) { | |
//Let's remove the value track parameters | |
url = url.replace(/\{[0-9a-zA-Z]+\}/g,''); | |
} | |
return url; | |
} | |
function buildSelector() { | |
var selector = (URL_LEVEL === 'Ad') ? AdWordsApp.ads() : AdWordsApp.keywords(); | |
selector = selector.withCondition('CampaignStatus != DELETED').withCondition('AdGroupStatus != DELETED'); | |
if(ONLY_ACTIVE) { | |
selector = selector.withCondition('CampaignStatus = ENABLED'); | |
if(URL_LEVEL !== 'Ad') { | |
selector = selector.withCondition('AdGroupStatus = ENABLED'); | |
} | |
} | |
if(CAMPAIGN_LABEL) { | |
if(AdWordsApp.labels().withCondition("Name = '"+CAMPAIGN_LABEL+"'").get().hasNext()) { | |
var label = AdWordsApp.labels().withCondition("Name = '"+CAMPAIGN_LABEL+"'").get().next(); | |
var campIter = label.campaigns().get(); | |
var campaignNames = []; | |
while(campIter.hasNext()) { | |
campaignNames.push(campIter.next().getName()); | |
} | |
selector = selector.withCondition("CampaignName IN ['"+campaignNames.join("','")+"']"); | |
} else { | |
Logger.log('WARNING: Campaign label does not exist: '+CAMPAIGN_LABEL); | |
} | |
} | |
return selector; | |
} |