The Marketing Technologist.

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

A moving object in your campaign? Update Adwords accordingly every hour.

We are running a campaign for one of our clients that is about a fluffy heart with GPS hardware that is travelling through the country. It looks something like this:

We'll get deeper into this campaign in another post on The Marketing Technologist, but for now it's enough to know that for every kilometre the heart travels our client will donate 10 euro to a good cause.

We are already using the GPS location, which was made available using an public API, in our display ads (in both our creatives and targeting). But we are also doing some SEA for this campaign, so why not also use the GPS coordinates in Adwords?

We want to achieve two things:

  • Only target people that are in a radius of 20 kilometres around the heart.
  • Show the distance the heart has already travelled so far, and the current location of the heart.

In this post I'll talk about the first goal. Let's get started.

Find the campaign

Go to the Scripts section in the Adwords Web application (Bulk operations > Scripts). Before we can update the campaign's targeting location, let's find our campaign first.

// What's the name of the campaign?
var campaignName = 'your campaign name';

function main() {
    // Find our campaign
    var campaignIterator = AdWordsApp.campaigns()
            .withCondition(Utilities.formatString('CampaignName = "%s"', campaignName))
            .get();

    while (campaignIterator.hasNext()) {
        var campaign = campaignIterator.next();
    }
}

Now the variable campaign refers to your campaign. In our scenario we have only one campaign that matches our campaign name.

Update the campaign's targeting location

When you want to get the proximate location (remember we want to target with a radius), we need to use targetedProximities() of your campaign's targeting() method. Unfortunately there is no good way to update a location, so we first have to remove the existing ones. To do this we have to get all the locations and call the remove method on them one by one.

// Get our current targeted proximity locations
var locations = campaign.targeting().targetedProximities().get();

// Loop through all locations
while(locations.hasNext()) {
    var location = locations.next();
    // Remove the existing proximity location
    location.remove();
}

Now your campaign has no more proximity locations. It's time to add our new location. We have to add this location by using its lattitude/longitude coordinates. It's easy to get these coordinates for an address using a service like http://www.latlong.net.

We can now add the coordinates to the campaign using addProximity. The first two arguments of this function are the lattitude and longitude values. The third one is the radius, followed by the unit of the radius (KILOMETRES or MILES). Make sure your coordinates are both numbers.

var radius = 10;
var lat = 51.507351;
var lng = -0.127758;

campaign.addProximity(lat, lng, radius, 'KILOMETRES')

Save your script and preview it. Your preview panel should look something like this.

We've just changed your campaign's location targeting with code. Nice!

Get location data from a remote source

Although it's fun to write these scripts, it's not really useful to hardcode those lat/lng coordinates. In our case we have these data available through an API, so let's see how we can use this data in our script.

I've seen some people use a spread sheet to read an API, and load the spread sheet with the API in Adwords. I'm not going to do that; I want to load the API directly in our code.

Our API returns this JSON data:

{
  lat: 51.507351,
  lng: -0.127758,
  city: 'London',
  distance: 22304
}

We can read this API using the fetch method of UrlFetchApp. We only need to pass the URL of our API.

var url = 'http://yourapi';
var response = UrlFetchApp.fetch(url);

To easily get the values we can parse the response text to JSON.

var data = JSON.parse(response.getContentText());

Now we can read the lat and long like this:

var lat = data.lat;
var lng = data.lng;

Awesome. We also have to handle any errors that may occur, like a 404 when the API is not available. We want to check if the HTTP response code is not 200 ('Response is OK'), and print an error otherwise.

if (response.getResponseCode() != 200) {
        throw Utilities.formatString(
                'Error returned by API: %s, Location searched: %s.',
                , location);
    }

The complete script

We've written a script that updates a campaign's targeting location based on data that is loaded from an external data source. Our complete script looks like this:

// What's the name of the campaign?
var campaignName = 'your campaign name';

// Url of the API
var url = 'http://yourapi'

// The radius in KM around the location you want to use in the campaign targeting
var radius = 20;

function getTheLocationOfTheHeart(url) {
    var response = UrlFetchApp.fetch(url);
    if (response.getResponseCode() != 200) {
        throw Utilities.formatString(
                'Error returned by API: %s, Location searched: %s.',
                response.getContentText(), location);
    }

    return JSON.parse(response.getContentText());
}

function main() {
    // Find our campaign
    var campaignIterator = AdWordsApp.campaigns()
            .withCondition(Utilities.formatString('CampaignName = "%s"', campaignName))
            .get();

    // Get the GPS location of the heart
    var heartLocation = getTheLocationOfTheHeart(url);

    while (campaignIterator.hasNext()) {
        var campaign = campaignIterator.next();

        // Get our current targeted proximities
        var locations = campaign.targeting().targetedProximities().get();

        // Remove the existing proximities
        while(locations.hasNext()) {
            var location = locations.next();
            location.remove();
        }

        // Add the new location of the heart
campaign.addProximity(Number(heartLocation.lat), Number(heartLocation.lng), radius, 'KILOMETRES')
    }
}

Make it run hourly

We want to update the location every hour. Return to your scripts overview page. You should see something like this:

Click 'Create schedule'. In the appeared popout select 'Hourly' and save it.

You script will now run every hour.

What's next?

Next time I'll get into how to display the distance the heart travelled in our ads by the hour. I also have a post coming up about how we've used GPS in our display campaigns, so stay tuned!