Pause Adwords Ads Script using Final URLs

339 views
Skip to first unread message

Jason-Rakuten

unread,
Oct 16, 2015, 9:53:28 PM10/16/15
to AdWords Scripts Forum
Hello,

I am by no means a coder and that's is why I am likely running into this problem with this script that I am sure has been copied 100K times.

I am trying to pause Ads in campaigns with labels that are "ooss," and have final URLs that are crawled to find "This product is currently not available" on the final URLs page source. I am using the following script and I am getting the following error:

Cannot retrieve the next object: iterator has reached the end. (line 79)
Am I doing something wrong to modify the campaign label to only check labels that have "ooss" and ignoring the other?
For reference, here is line 79:
var label = AdWordsApp.labels().withCondition("Name = '"+CAMPAIGN_LABEL+"'").get().next();

Thanks for the help on this! Here is the script I am trying to use:


/************************************
* Item Out Of Stock Checker
* Version 1.1
* 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 for all ads or keywords
var CAMPAIGN_LABEL = 'ooss'; // 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 to search for
// on the page that indicates the item
// is out of stock.
var OUT_OF_STOCK_TEXT = 'This product is currently not available';

function main() {
var alreadyCheckedUrls = {};
var iter = buildSelector().get();
while(iter.hasNext()) {
var entity = iter.next();
var url = cleanUrl(entity.urls().getFinalUrl());
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;
}
if(htmlCode.indexOf(OUT_OF_STOCK_TEXT) >= 0) {
alreadyCheckedUrls[url] = 'out of stock';
entity.pause();
} else {
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').withCondition('Status = ENABLED');
if(URL_LEVEL !== 'Ad') {
selector = selector.withCondition('AdGroupStatus = ENABLED');
}
}
if(CAMPAIGN_LABEL) {
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("','")+"']");
}
return selector;
}

Tyler Sidell (AdWords Scripts Team)

unread,
Oct 19, 2015, 10:52:53 AM10/19/15
to AdWords Scripts Forum
Hi Jason,

You want to make sure that the campaign label "ooss" exists.  Otherwise, you will get the error that the iterator has reached the end.  You can create the label through the AdWords dashboard or through Scripts itself.

Thanks,
Tyler Sidell
AdWords Scripts Team

Jason-Rakuten

unread,
Oct 19, 2015, 12:14:12 PM10/19/15
to AdWords Scripts Forum
Thank you Tyler! You helped me to double check and realize that the label feature was case sensitive. Works great! Appreciate the helpful hand.

Jason-Rakuten

unread,
Oct 19, 2015, 1:01:40 PM10/19/15
to AdWords Scripts Forum
Would anyone happen to know if this script will reactivate a Text Ad that has a final URL that does not contain the text "This product is currently not available" or will those pages remain paused? If they remain paused, do you have a recommendation for modifying this script to reactivate Text Ads that do not contain "This product is currently not available" in the final URL. Thanks!

Tyler Sidell (AdWords Scripts Team)

unread,
Oct 19, 2015, 2:27:26 PM10/19/15
to AdWords Scripts Forum
Hi Jason,

If the Text Ad has a final URL that directs to a page that contains the text, "This product is currently not available", then those ads will be enabled based on entity.enable(). This script will only pause Ads or Keywords that link to the page with the out of stock product.


Thanks,
Tyler Sidell
AdWords Scripts Team

Jason-Rakuten

unread,
Oct 20, 2015, 12:18:53 PM10/20/15
to AdWords Scripts Forum
Thanks Tyler for being so helpful. Can I clarify your last statement. Are you saying that the script will only pause the ads that contain "This product is currently not available" in the final URL? In other words, let's say the script previously paused an ad that contained "This product is currently not available" on the page in the final URL, but let's say the product later came back in stock. Now the page does not contain "This product is currently not available" in the final url. Will this script reactivate the ad, or will it still remain paused? I am trying to fully understand your comment, "then those ads will be enabled based on entity.enable()."

If it does not enable the paused ads when
"This product is currently not available" is not found on the page, can you help me modify the script above to reactive those keywords. Just want to have the reverse mechanism in place if it is missing. Thanks again for all your help.

Tyler Sidell (AdWords Scripts Team)

unread,
Oct 20, 2015, 2:02:50 PM10/20/15
to AdWords Scripts Forum
Hi Jason,

If the item comes back in stock and you want to unpause those ads, you would have to change the following line in your script:

var ONLY_ACTIVE = true; // set to false for all ads or keywords

Set that value to false to 'unpause' items that are back in stock.


Thanks,
Tyler Sidell
AdWords Scripts Team

Jason-Rakuten

unread,
Oct 20, 2015, 5:22:26 PM10/20/15
to AdWords Scripts Forum
I see, thats a simple change and makes sense. Except it creates another issue, if I change that to "false," it will then activate all the paused ads that I didn't want to have be unpaused (ie. promotional text copy).

We do use a label for all text ads that are manually paused because of bad performance and seasonality, label = "forced pause" and I cant find seem to find a way to exclude those text ad with a "withCondition("LabelNames..." type. Would you know a way to set up a variable to the script to exclude those ad level labels that = "forced pause" for this to not activate the wrong ads? Again I appreaciate all the help Tyler.

Jason-Rakuten

unread,
Oct 20, 2015, 5:47:56 PM10/20/15
to AdWords Scripts Forum
Second question about additional modifications, is it possible to run this script where it checks for two phrases different phrases to see if the final URL contains either of the following phrases:

Such as something like: var OUT_OF_STOCK_TEXT = 'This product is currently not available' OR 'did not return an exact match'

Tyler Sidell (AdWords Scripts Team)

unread,
Oct 21, 2015, 9:34:56 AM10/21/15
to AdWords Scripts Forum
Hi Jason,

I'm glad to see that we are making progress.  To answer your first question, we can add a label to the campaign level:
var CAMPAIGN_LABEL = 'forced pause'; // set this if you want to only check campaigns with this label

For the second question, it may be a bit tricky but you can try to set up the OUT_OF_STOCK_TEXT variable as an array instead:
var OUT_OF_STOCK_TEXT = ['Text1', 'Text2'];

Thanks,
Tyler Sidell
AdWords Scripts Team


Jason-Rakuten

unread,
Oct 21, 2015, 12:31:50 PM10/21/15
to AdWords Scripts Forum
Thanks Tyler, I cannot thank you enough for all the progress we have made. The second suggestion for the "OUT_OF_STOCK_TEXT" array worked great.

The first question actually regarded the ad level label instead of the campaign level label. I gave this some thought, and I really don't think I can create an automated method that does not adhere to labels we make to the specific ad copy. We have too many cases where we pause an ad for notable reasons, but desire run other ad in that same adgroup. A campaign label would not treat these special cases. I just don't know the VAR definition to direct the script to only look at Text Ads that have not been forcibly paused and labeled 'forced pause'

Another thought I had, it would be nice to add a label to the text ads that are paused because the LP was recognized as Out of Stock. This way we can create documentation and reports based on the label. So if we are able to create a script that recognizes text ad level labels, then it would be nice to also assign a text ad level label "OOS" when a text ad is paused. This is not necessary, but I think it would also remove a lot of potential confusion if something was forcibly paused or the script paused it. To be clear, I would only need to set up a variable to excluse text ads with the label "forced pause" from being included in this script. The script would include this 'OOS' label by default as it does not match 'forced pause'

Does that make sense?

Tyler Sidell (AdWords Scripts Team)

unread,
Oct 21, 2015, 4:48:02 PM10/21/15
to AdWords Scripts Forum
Hi Jason,

You should be able to modify the buildSelector function as follows to add a withCondition that checks for a certain label:
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').withCondition('Status = ENABLED');
if(URL_LEVEL !== 'Ad') {

selector
= selector.withCondition('AdGroupStatus = ENABLED').withCondition("LabelNames CONTAINS_ANY ['forced pause', 'label 2 if necessary']");
}
}

Thanks,
Tyler Sidell
AdWords Scripts Team

Jason-Rakuten

unread,
Oct 21, 2015, 7:03:24 PM10/21/15
to AdWords Scripts Forum
Here is the the updates that I included. Unfortunately, it doesn't look like it is correctly identifying the "Out of Stock" text anymore. It caused all of the paused ads to be enabled and more than 50% products I spot checked were still out of stock and contained one of the phrases we included in the script. It did however properly exclude the "forced pause" labels.


/************************************
* Item Out Of Stock Checker
* Version 1.1
* ChangeLog v1.1 - Filtered out deleted Campaigns and AdGroups
* Created By: Russ Savage
* FreeAdWordsScripts.com
***********************************/
var URL_LEVEL = 'Ad'; // or Keyword
var ONLY_ACTIVE = false; // set to false for all ads or keywords
var CAMPAIGN_LABEL = 'OOSS'; // set this if you want to only check campaigns with this label
var STRIP_QUERY_STRING = false; // 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 to search for
// on the page that indicates the item
// is out of stock.
var OUT_OF_STOCK_TEXT = ['This product is currently not available', 'did not return an exact match'];
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').withCondition('Status = ENABLED');
if(URL_LEVEL !== 'Ad') {

selector = selector.withCondition('AdGroupStatus = ENABLED').withCondition("LabelNames CONTAINS_ANY ['forced pause', 'label 2 if necessary']");
    }
  }

Tyler Sidell (AdWords Scripts Team)

unread,
Oct 22, 2015, 10:13:37 AM10/22/15
to AdWords Scripts Forum
Hi Jason, 

What happens if you remove the array for var OUT_OF_STOCK_TEXT = ['This product is currently not available', 'did not return an exact match']; that you set up and revert it back to one string? Also, this won't change much but you may want to remove the second label from 

selector = selector.withCondition('AdGroupStatus = ENABLED').withCondition("LabelNames CONTAINS_ANY ['forced pause', 'label 2 if necessary']");

You can also send your CID (reply privately to the author) with the name of the script and we'll take a look.


Thanks,
Tyler Sidell
AdWords Scripts Team

Jason-Rakuten

unread,
Nov 2, 2015, 1:14:16 PM11/2/15
to AdWords Scripts Forum
Sorry Tyler, I was out of the office last week. I have send you a private message with my CID and essentially the requirements I put for my team to create the code. Thanks.
Reply all
Reply to author
Forward
0 new messages