Sale Countdown

Displaying up-to-date and dynamic values in ad text can be very compelling for viewers. Ad parameters allow you to update numeric values in text ads without having to delete and re-add the ad or wait for policy checks. This script demonstrates how to update your ad parameters hourly to count down until a sale you'd like to promote.

How it works

Suppose you have an upcoming sale:

Countdown sale

This script calculates how many days and hours remain until the target date, then finds the specific ad group set up for this promotion, and updates the ad parameters of all keywords in this ad group with the results of the calculation.

Which ad group?

The script assumes you have a single ad group for which you want to run this promotion. But what if you wanted to run this promotion for more than one ad group? You have a few options.

Multiple ad groups

If you want to affect multiple ad groups, you can first create an array

var AD_GROUP_NAMES = ['Widget Sale', 'Widget Sale 2'];

and then modify the getAdGroup to getAdGroups like so:

function getAdGroups(names) {
  var predicateValues = "['" + names.join("','") + "']";
  Logger.log(predicateValues);
  return AdsApp.adGroups()
      .withCondition('Name IN ' + predicateValues)
      .withLimit(names.length)
      .get();
}

Next, modify the main() function to use multiple ad groups:

var adGroups = getAdGroups(AD_GROUP_NAMES);
while (adGroups.hasNext()) {
  var adGroup = adGroups.next();
  var keywords = adGroup.keywords().get();
  // ...
}

All ad groups in a campaign

You could also run this script for a single campaign by using a similar function to getAdGroup for Campaigns, invoking campaign.adGroups().get() and structuring your main() function in the same manner as the example script.

What about keyword bids?

We're updating the ad parameters tied to our keywords, which makes the ad copy more dynamic. But what if we wanted to modify our keyword bids at the same time? That's fairly straightforward, since we're already looping over the target keywords.

while (keywords.hasNext()) {
  var keyword = keywords.next();
  // We want to update {param1} to use our calculated days and {param2}
  // for hours.
  keyword.setAdParam(1, timeLeft['days']);
  keyword.setAdParam(2, timeLeft['hours']);
  if (timeLeft['days'] < 5) {
    keyword.bidding().setCpc(keyword.getTopOfPageCpc());
  } else {
    keyword.bidding().setCpc(keyword.getFirstPageCpc());
  }
}

This code updates the max CPC bid of the keyword to match the TopOfPageCpc for that keyword if we have less than 5 days remaining until our deadline, making sure we're strongly promoting this campaign right before our deadline. It otherwise sets the bid to the first page CPC, making sure that the ad is seen, but not paying for top slot.

Our sale has started, now what?

Once we've finished the countdown period and our sale has started, our ad doesn't make as much sense. It would be much more relevant to promote the sale with different verbiage. Let's enhance our example to better promote the sale while it is on.

First, let's imagine that we've already created a second ad group that is promoting the ongoing sale. We'll call it "Widget Sale In Progress". Let's add some new variables at the top of the script, like so:

// Ad Group that has text ads with AdParams for use while the sale is ongoing.
var AD_GROUP_NAME_IN_PROGRESS = 'Widget Sale In Progress';
var END_DATE_OF_SALE = new Date('December 31, 2012');

Next, let's alter the rest of the main function body to incorporate this new logic:

function main() {
  var timeLeft = calculateTimeLeftUntil(END_DATE, new Date());
  var adGroup = getAdGroup(AD_GROUP_NAME);
  if (timeLeft['days'] <= 0 && timeLeft['hours'] <= 0) {
    adGroup.pause();
    adGroup = getAdGroup(AD_GROUP_NAME_IN_PROGRESS);
    adGroup.enable();
    timeLeft = calculateTimeLeftUntil(END_DATE_OF_SALE, new Date());
  }
  var keywords = adGroup.keywords().get();
  // ...
}

We've added some logic to check if we've passed the start of the sale. If we have, we pause the (countdown) adGroup, get the adGroup for the in-progress portion, enable it and calculate a new timeLeft based on the end of the sale.

Scheduling

Scheduled to run hourly, the script creates dynamic ad text that counts down the hours to the sale.

Setup

  • Create a new ad group with a text ad. On one of the ad's description lines, add some ad params, e.g.:
    • Description: Only {param1:a few} days {param2:and} hours left!
    Use any value you like for the other fields.
  • Add a few relevant keywords to this ad group.
  • Create a new Google Ads script with the source code below.
  • At the top of the script replace the value of the AD_GROUP_NAME variable with the name of the ad group you created.
  • Upon previewing, you'll see that it will set the ad parameters to the days and hours left until your target date for each keyword in the ad group you specified. You can preview how your ads with the Preview Tool.

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 Sales Countdown
 *
 * @overview The sales countdown script demonstrates how to update your ad
 *     parameters hourly to count down until a sale you'd like to promote. See
 *     https://developers.google.com/google-ads/scripts/docs/solutions/sale-countdown
 *     for more details.
 *
 * @author Google Ads Scripts Team [adwords-scripts@googlegroups.com]
 *
 * @version 1.0
 *
 * @changelog
 * - version 1.0
 *   - Released initial version.
 */

// Date and time for the end of the sale. Be sure to include a time and timezone
// so that the sale ends exactly when you intend.
var END_DATE = new Date('February 17, 2016 13:00:00 -0500');
// Change this to the Ad Group you set up with text ads with AdParams.
var AD_GROUP_NAME = 'Widget Sale';

var DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;

function main() {
  var timeLeft = calculateTimeLeftUntil(END_DATE);
  var adGroup = getAdGroup(AD_GROUP_NAME);
  var keywords = adGroup.keywords().get();
  while (keywords.hasNext()) {
    var keyword = keywords.next();
    // We want to update {param1} to use our calculated days and {param2}
    // for hours.
    keyword.setAdParam(1, timeLeft['days']);
    keyword.setAdParam(2, timeLeft['hours']);
  }
}

function calculateTimeLeftUntil(end) {
  var current = new Date();
  var timeLeft = {};
  var daysFloat = (end - current) / (DAY_IN_MILLISECONDS);
  timeLeft['days'] = Math.floor(daysFloat);
  timeLeft['hours'] = Math.floor(24 * (daysFloat - timeLeft['days']));

  // Prevent countdown to negative time period.
  if (timeLeft['days'] < 0) {
    timeLeft['days'] = 0;
  }
  if (timeLeft['hours'] < 0) {
    timeLeft['hours'] = 0;
  }

  return timeLeft;
}

function getAdGroup(name) {
  var adGroupIterator = AdsApp.adGroups()
      .withCondition('Name = "' + name + '"')
      .withLimit(1)
      .get();
  if (adGroupIterator.hasNext()) {
    return adGroupIterator.next();
  }
}