The Marketing Technologist.

We talk about analytics, code, data science and everything related to marketing technology. Backed by the tech geeks of Greenhouse Group.

Pause your Adwords campaigns automatically when a site is down with an Adwords script

When working in the field of SEA, one of your main goals is to get people to click on your ads. But what if the website is down, or not working properly because of a technical issue? That's a waste of that CPC, right? At Greenhouse Group we monitor all our clients' websites with uptime monitoring tools, like Uptime Robot and Pingdom, so when one of a site goes down we can - if necessary - immediately pause our campaigns. But what if the site breaks at night, or in the weekend? At moments we're away from our keyboards? We certainly don't want to be the ones that sneak away from a gathering with friends to pause our Adwords campaigns.

That's why we use the Uptime Robot API in a Adwords script to automatically pause our campaigns when we are not at our desks. You deserve the weekend off as well, so let me show you how it works.

Create a Uptime Robot monitor

In this example, we'll use Uptime Robot to check whether our website is still running or not. If you don't already have one, go to uptimerobot.com and create a new account for free. Now go to the dashboard and create a new monitor. This proces should all be pretty straightforward. We'll create a monitor for The Marketing Technologist:

Get a Uptime Robot API key

To access your monitor information from your Adwords script, you'll need a API key. In your Uptime Robot dashboard go to My Settings. In the bottom right you'll see the API Settings.

Copy the Main API key and save it somewhere. You'll need it later.

Get the monitor information in a Adwords script

Okey, let's dive into some code now. The first thing we want to do is call the Uptime Robot API to get information about the status of our website. Everytime we need to call a API from our script, we can use Adwords' great URL Fetch Service. In the next snippet we load the monitor data and save it to the reponse variable. Make sure you replace the value of uptimeRobotKey with the key you saved in the previous step.

var uptimeRobotKey = 'XXXXXXXXXXXXXX';

function main() {
  var response = UrlFetchApp.fetch('https://api.uptimerobot.com/getMonitors?apiKey='+uptimeRobotKey+'&format=xml');
  if (response.getResponseCode() != 200) {
    throw Utilities.formatString(
      'Error returned by API: %s, Location searched: %s.',
      response.getContentText(), location);
  }
}

The value of reponse now holds the monitor data in XML format. It looks something like this:

<monitors offset="0" limit="50" total="1">
<monitor id="XXXXXXX" friendlyname="The Marketing Technologist" url="https://www.themarketingtechnologist.co" type="1" subtype="" keywordtype="" keywordvalue="" httpusername="" httppassword="" port="" interval="300" status="2" alltimeuptimeratio="99.99"/>
</monitors>

We get the information about all our monitors that we've set set up in our Uptime Robot account. This is because we've used the Main API key earlier. To only get a specific monitor in the response, create a API key for a specific monitor. For now, because we only have one monitor in our account, we'll continue as is. Luckily, it's very easy to work with XML in Adwords script with the XMLService. We can get all monitors available as JavaScript by using this simple snippet:

var document = XmlService.parse(response.getContentText());
var root = document.getRootElement();
var entries = root.getChildren('monitor');

Check your site's status

In the XML response of Uptime Robot there's a status attribute for every monitor. This status contains the value 9 if the site is down, so we'd check for that value in our code. Before checking whether your site is up or down, we need the specify what URL's we should check for in our script.

var domains = ['http://www.themarketingtechnologist.co'];

Now we can loop through the monitors and see if the site is down or not.

var hasDownDomain = false;
for (var i = 0; i < entries.length; i++) {
  var url = entries[i].getAttribute('url').getValue();
  var status = entries[i].getAttribute('status').getValue();
  // Uptime Robots status code for down is 9
  var looksDown = status == '9';
  
  // Check if the site is down and whether it's a site we want to check
  if (looksDown && domains.indexOf(url) > -1) {
    hasDownDomain = true;
    Logger.log(url + ' is down. We\'re going to pause the campaigns');
  }
}

Now we can simple check for the value of hasDownDomain to see if one of our sites is down and what action we should take.

if (hasDownDomain) {
  pauseCampaign();
} else {
  enableCampaign();
}

Pausing campaigns

The implementation of the pauseCampaign function is pretty straightforward. We loop through all campaigns, check if the campaign is active and if so, pause it.

function pauseCampaign() {
  var campaignIterator = AdWordsApp.campaigns().get();
  // Go over all campaigns 
  while (campaignIterator.hasNext()) {
    var campaign = campaignIterator.next();
    // Check if the campaign is active
    if (!campaign.isPaused()) {
      // Pause campaign
      campaign.pause();
      Logger.log("campaign " + campaign.getName() + " was paused.");
    }
  }
}

Enable campaigns

When your site gets up again, of course we want to re-enable all campaigns again. The code to do so looks very similar:

function enableCampaign() {
  var campaignIterator = AdWordsApp.campaigns().get();
  // Go over all campaigns 
  while (campaignIterator.hasNext()) {
    var campaign = campaignIterator.next();
    // Check if the campaign is paused
    if (campaign.isPaused()) {
      // Enable campaign
      campaign.enable();
      Logger.log("campaign " + campaign.getName() + " was enabled.");
    }
  }
}

Keep track of paused campaigns

There's one big problem with this implementation. When you'd already paused a campaign manually, the script will automatically re-enable it when your site gets up again. That's not what we want! We only want the script to re-enable the campaigns it paused earlier. Here's where Labels come in. We're going to add a label campaign_paused_by_code to every campaign we pause. Before we can do so, we need to create the label in our Adwords account.


Labels Admin section - Image from support.google.com

After you added the label, we can use it in our code. First, we add the label in our code where we also pause it (pauseCampaigns).

...
campaign.applyLabel('campaign_paused_by_code');
campaign.pause();
...

In the enableCampaigns function, before removing the label, we should do a check if the campaign has the label.

...
var labelIter = campaign.labels().withCondition("Name = 'campaign_paused_by_code'").get();
// Check if the label exists in this campaign
if (labelIter.hasNext()) {
  campaign.enable();
  campaign.removeLabel('uptime_paused');
  Logger.log("campaign " + campaign.getName() + " was enabled.");
}
...

Only execute script outside office hours

During business hours we manually want to pause our campaigns, so we don't want to run the script then. I created a small function that checks if it's weekend, or evening:

function isDuringBusinessHours() {
  var businessHours = [8, 17];
  var today = new Date();
  var day = today.getDay();
  var hour = today.getUTCHours() + 1; // UTC
  if ([0, 6].indexOf(day) > -1) return false; // weekend
  return hour >= businessHours[0] && hour < businessHours[1];
}

Now at the beginning of the main function, we can run this check:

function main() {
  if (isDuringBusinessHours()) {
    // Don't run the script when we're during business hours
    return;
  }
  ...
}

This should be all the code you need to pause and enable your campaigns. To see the complete script, check this Github gist.

Bonus: send a mail when campaigns are paused/enabled

You might want to know what happens when you're not in control of the campaigns at night. Therefore it's wise to let the script send you an email when it paused or enabled campaigns. This is very easy with Adwords MailApp utility. First we create a function that sends the email.

function sendMail(subject, content) {
  MailApp.sendEmail('youremail@domain.com', subject, content);
}

Next we can use this in our enableCampaigns and pauseCampaigns functions. Just like this:

sendMail('Campaigns were paused', 'Some campaigns were paused because the website is down.'

You might want to consider to put some more useful information in the email (What campaigns were paused? What site was down? etc), but I think you get the idea.

Next steps

With Uptime Robot we only check whether a site responds properly or not. But in some cases we also want to check if the website's sales funnel is working properly. Therefore, we use Pingdom's transaction checks, which allow us to check the flow of a website. We've also automated this using Pingdom's API, but that something we'll get into in a next post.

Also, one big flaw in this script is that it only runs every hour because of Adword's limitation. Therefore, if a site is only down for 5 minutes, your campaigns will be paused for a full hour. To overcome this, we can create a custom service that runs outside of Adwords that pauses/enables the campaigns using the Adwords API, and schedule it every 5 minutes. This would be a bit more work to setup, but definitely a good next step.

Internally we managed to partly solve this flaw by using a tool called Adjestic. Adjestic is developed internally and helps our marketeers to improve their campaigns and optimize budgets. One of the features is nearly real-time status and stock checking. The tool achieves this by tracking 'final urls'. When it detects downtime, it will incease the check frequency for that specfic url. This way we decrease the chance of accidentally pausing campaings.