Generic Weather-based Campaign Management

Bidding icon

This guide introduces a generic weather management script that lets you perform campaign management tasks based on weather information.

Weather data

The script retrieves weather info from OpenWeather servers. You can request current weather data or the week's forecast by providing city names, for example:

// Get current weather information for New York City.
const nyWeather = getWeatherForLocation("New York City, US");

// Get the weather forecast for the next week in Toronto.
const torontoWeather = getWeatherForecastForLocation("Toronto, CA");

Data format

The weather information returned by the getWeatherForLocation() method has the following format:

{
  name: "New York",
  weather: {
    clouds: 48,
    windspeed: 2.66,
    status: {
      summary: "Clouds",
      id: 802,
      description: "scattered clouds"
    },
    snow: 0.0,
    rain: 0.0,
    temperature: 286.16
  },
  country: "United States of America"
}

The various properties can be interpreted as follows:

Field Detail
name Canonical name of the location, as returned by OpenWeather
clouds Cloudiness, as a percentage value.
windspeed Wind speed, in m/s.
snow Snow volume for last 3 hours, mm.
rain Rain volume for last 3 hours, mm.
summary A summary of the weather. See Weather Conditions for valid values.
description A description of the weather. See Weather Conditions for valid values.
id An ID for the weather condition, as returned by OpenWeather. See Weather Conditions for valid values.
temperature The temperature in Kelvin scale.

Similarly, the weather forecast information returned by the getWeatherForecastForLocation() method has the following format:

{
  name: "Toronto",
  country: "CA"
  forecast: {
    "20150416": {
       clouds: 0.0,
       windspeed: 2.06,
       status: {
         summary: "Rain",
         id: 500,
         description: "light rain"
       },
       snow: 0.0,
       rain: 1.89,
       temperature: 0.0
    },
    "20150417": {
      ...
    }
  }
}

The properties in the forecast feed have the same meaning as the weather feed. The extra forecast property is a map, with key being the date in yyyyMMdd format, and value as the weather forecast data for that day. By default, weather forecasts for seven days are returned. The script simplifies the JSON that is returned by the OpenWeather API.

Weather-based campaign management

Here are some examples on how you can manage your campaigns based on this weather information:

Current weather

Example 1: Use weather summary provided by OpenWeather.

const nyWeather = getWeatherForLocation("New York City, US");
if (nyWeather.weather.status.summary === "Rain") {
  const campaign = AdsApp.campaigns()
      .withCondition("campaign.name = 'Sunny Trips'")
      .get()
      .next();
  campaign.pause();
}

Example 2: Check more specific weather parameters.

const nyWeather = getWeatherForLocation("New York City, US");
if (nyWeather.weather.snow > 5 && nyWeather.weather.temperature < 273) {
  const adGroup = AdsApp.adGroups()
     .withCondition("campaign.name = 'New York Shoes'")
     .withCondition("ad_group.name = 'Snow boots'")
     .get()
     .next();
  adGroup.bidding().setCpc(adGroup.bidding().getCpc() + 0.3);
}

Weather forecast

Example 1: Use weather summary provided by OpenWeather.

const nyWeather = getWeatherForecastForLocation("New York City, US");
let rainyDays = 0;
for (const date in nyWeather.forecast) {
  const forecast = nyWeather.forecast[date];
  if (forecast.status.summary === "Rain") {
    rainyDays = rainyDays + 1;
  }
}

if (rainyDays > 4) {
  const campaign = AdsApp.campaigns()
      .withCondition("campaign.name = 'Sunny Trips'")
      .get()
      .next();
  campaign.pause();
}

Example 2: Check more specific weather parameters.

const nyWeather = getWeatherForecastForLocation("New York City, US");
let coldDays = 0;
for (const date in nyWeather.forecast) {
  const forecast = nyWeather.forecast[date];

  if (forecast.snow > 5 && forecast.temperature < 273) {
    coldDays = coldDays + 1;
  }
}

if (coldDays > 4) {
  const adGroup = AdsApp.adGroups()
      .withCondition("campaign.name = 'New York Shoes'")
      .withCondition("ad_group.name = 'Snow boots'")
      .get()
      .next();
  adGroup.bidding().setCpc(adGroup.bidding().getCpc() + 0.3);
}

Setup

  • Register for an API key.

  • Create a new script with the source code below.

    • Update the OPEN_WEATHER_MAP_API_KEY.
    • Uncomment the appropriate block of code in the main() method depending on whether you want to run this script on an advertiser account or a manager account.
    • Uncomment the appropriate block of code in the processSingleAccount() method depending on whether you want to use current weather or weather forecast information.
    • Replace the contents of manageCampaignsBasedOnCurrentWeather() or manageCampaignsBasedOnWeatherForecast() with your own campaign management logic.
  • Schedule to run as required.

Source code

// Copyright 2015, Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @name Weather Based Campaign Management
 *
 * @overview The Weather Based Campaign management script allows you to perform
 *     various campaign management tasks based on weather information. See
 *     https://developers.google.com/google-ads/scripts/docs/solutions/weather-based-campaign-management#generic-weather
 *     for more details.
 *
 * @author Google Ads Scripts Team [adwords-scripts@googlegroups.com]
 *
 * @version 2.0
 *
 * @changelog
 * - version 2.0
 *   - Updated to use new Google Ads Scripts features.
 * - version 1.0
 *   - Released initial version.
 */

// Register for an API key at http://openweathermap.org/appid
// and enter the key below.
const OPEN_WEATHER_MAP_API_KEY = `INSERT_OPEN_WEATHER_MAP_API_KEY_HERE`;

// Set up URLs to access various weather features. Do not modify this section.
const OPEN_WEATHER_MAP_SERVER_URL = `http://api.openweathermap.org/data/2.5`;
const FORECAST_ENDPOINT = OPEN_WEATHER_MAP_SERVER_URL +
    `/forecast?APPID=${OPEN_WEATHER_MAP_API_KEY}&units=metric&cnt=7&lang=en&q=`;
const WEATHER_ENDPOINT = OPEN_WEATHER_MAP_SERVER_URL +
    `/weather?APPID=${OPEN_WEATHER_MAP_API_KEY}&q=`;

/**
 * Performs campaign management tasks based on weather information.
 */
function main() {
  // Uncomment the following lines if you are writing code for a single account.
  // processSingleAccount();

  // Uncomment the following lines if you are writing code for an MCC account.
  // var accounts = AdsManagerApp.accounts().withIds(['1234567890', '3456789012']);
  // accounts.executeInParallel("processSingleAccount");
}

/**
 * Process a single account.
 */
function processSingleAccount() {
  // Uncomment this block if you want to do campaign management based on
  // current weather.
  // manageCampaignsBasedOnCurrentWeather();

  // Uncomment this block if you want to do campaign management based on
  // weather forecast.
  // manageCampaignsBasedOnWeatherForecast();
}

/**
 * Manage your campaigns based on current weather. The contents of
 * this method are for your reference; replace it with your campaign
 * management logic.
 */
function manageCampaignsBasedOnCurrentWeather() {
  const nyWeather = getWeatherForLocation('New York City, US');

  // Example 1: Use weather summary provided by OpenWeathermap.
  // See http://openweathermap.org/weather-conditions for more details.
  if (nyWeather.weather.status.summary === 'Rain') {
    // Add your logic here.
  }

  // Example 2: Check more specific weather parameters.
  if (nyWeather.weather.snow > 5 && nyWeather.weather.temperature < 273) {
    // Add your logic here.
  }
}

/**
 * Manage your campaigns based on weather forecast. The contents of
 * this method are for your reference; replace it with your campaign
 * management logic.
 */
function manageCampaignsBasedOnWeatherForecast() {
  const nyWeather = getWeatherForecastForLocation('Toronto, CA');

  // Example 1: Use weather summary provided by OpenWeathermap.
  let rainyDays = 0;
  for (const date in nyWeather.forecast) {
    const forecast = nyWeather.forecast[date];
    if (forecast.status.summary === 'Rain') {
      rainyDays = rainyDays + 1;
    }
  }
  if (rainyDays > 4) {
    // Add your logic here.
  }

  // Example 2: Check more specific weather parameters.
  let coldDays = 0;
  for (const date in nyWeather.forecast) {
    const forecast = nyWeather.forecast[date];
    if (forecast.snow > 5 && forecast.temperature < 273) {
      coldDays = coldDays + 1;
    }
  }
  if (coldDays > 4) {
    // Add your logic here.
  }
}

/**
 * Make a call to the OpenWeatherMap server.
 *
 * @param {string} endpoint the server endpoint.
 * @param {string} location the location for which weather
 *     information is retrieved.
 * @return {Object} the server response.
 */
function callWeatherServer(endpoint, location) {
  const url = Utilities.formatString('%s%s',
      endpoint,
      encodeURIComponent(location));
  const response = UrlFetchApp.fetch(url);
  if (response.getResponseCode() != 200) {
    throw Utilities.formatString(
        'Error returned by API: %s, Location searched: %s.',
        response.getContentText(), location);
  }
  const result = JSON.parse(response.getContentText());

  // OpenWeatherMap's way of returning errors.
  if (result.cod != 200) {
    throw Utilities.formatString(
        'Error returned by API: %s,  Location searched: %s.',
        response.getContentText(), location);
  }
  return result;
}

/**
 * Parse the weather response from the OpenWeatherMap server.
 *
 * @param {Object} weather the weather information from
 *     OpenWeatherMap server.
 * @return {!Object} the parsed weather response.
 */
function parseWeather(weather) {
  const retval = {
    'rain': 0,
    'temperature': 0,
    'windspeed': 0,
    'snow': 0,
    'clouds': 0,
    'status': {
      'id': 0,
      'summary': '',
      'description': ''
    }
  };

  if (weather.rain) {
    if (typeof weather.rain === 'object' && weather.rain['3h']) {
      retval.rain = weather.rain['3h'];
    } else {
      retval.rain = weather.rain;
    }
  }

  if (weather.snow) {
    if (typeof weather.snow === 'object' && weather.snow['3h']) {
      retval.snow = weather.snow['3h'];
    } else {
      retval.snow = weather.snow;
    }
  }

  if (weather.clouds && weather.clouds.all) {
    retval.clouds = weather.clouds.all;
  }

  if (weather.main) {
    retval.temperature = weather.main.temp.toFixed(2);
  } else if (main.temp) {
    retval.temperature = weather.temp.toFixed(2);
  }

  if (weather.wind) {
    retval.windspeed = weather.wind.speed;
  } else if (weather.speed) {
    retval.windspeed = weather.speed;
  }

  if (weather.weather && weather.weather.length > 0) {
    retval.status.id = weather.weather[0].id;
    retval.status.summary = weather.weather[0].main;
    retval.status.description = weather.weather[0].description;
  }
  return retval;
}

/**
 * Get the weather forecast for a location for the next 7 days.
 *
 * @param {string} location the location for which weather
 *     forecast information is retrieved.
 * @return {!Object} the parsed weather response.
 */
function getWeatherForecastForLocation(location) {
  const result = callWeatherServer(FORECAST_ENDPOINT, location);
  const retval = {
    'name': result.city.name,
    'country': result.city.country,
    'forecast': {
    }
  };
  for (const forecast of result.list) {
    const date = formatDate(forecast.dt);
    retval.forecast[date] = parseWeather(forecast);
  }
  return retval;
}

/**
 * Get the current weather information for a location.
 *
 * @param {string} location the location for which weather
 *     information is retrieved.
 * @return {!Object} the parsed weather response.
 */
function getWeatherForLocation(location) {
  const result = callWeatherServer(WEATHER_ENDPOINT, location);
  return {
    'name': result.name,
    'country': result.sys.country,
    'weather': parseWeather(result)
  };
}

/**
 * Formats the date in yyyyMMdd format.
 *
 * @param {number} dt unix timestamp from OpenWeatherMap server.
 * @return {string} the formatted date.
 */
function formatDate(dt) {
  const date = new Date(dt * 1000);
  return Utilities.formatDate(date, 'GMT', 'yyyyMMdd');
}