AdWords scripts

Best Practices

Below are some programming practices making your scripts more efficient and reliable. After you've finished, check out some additional Tips & Tricks.

  1. Filter with selectors
  2. Avoid traversing the campaign hierarchy
  3. Batch changes
  4. Reports vs Selectors

Filter with selectors

Compare the following snippets of code:

  1. Filter using selectors:
    var keywords = AdWordsApp.keywords()
        .withCondition("Clicks > 10")
    while (keywords.hasNext()) {
      var keyword = keywords.next();
      // Do work here.
  2. Filter in code:
    var keywords = AdWordsApp.keywords().get();
    while (keywords.hasNext()) {
      var keyword = keywords.next();
      if (keyword.getStatsFor("LAST_MONTH").getClicks() > 10) {
        // Do work here.

The first way of filtering keywords is markedly better:

  • The code is simpler and easier to understand.
  • The script will execute much faster.
  • The second filtering attempt is much more likely to run into a fetching limit.

Whenever possible, get the Selectors to do filtering and sorting for you, instead of doing that in code.

Back to top

Avoid traversing the campaign hierarchy

One way to get all the ads is traversing the hierarchy—look at all campaigns, then their ad groups, and finally at ads:

var campaigns = AdWordsApp.campaigns().get();
while (campaigns.hasNext()) {
  var adGroups = campaigns.next().adGroups().get();
  while (adGroups.hasNext()) {
    // Finally!
    var ads = adGroups.next().ads().get();

The following approach is markedly easier:

var ads = AdWordsApp.ads();

In addition to being simpler, the second way will also perform much better: AdWords scripts will not have to unnecessarily read in all the campaigns and ad groups. Additionally, it's quicker to read 10,000 ads once than it is to execute 50 reads of 200 ads each.

Back to top

Batch changes

Whenever possible, AdWords scripts attempt to batch up the changes to campaign data. It is much quicker to execute a single 1000-keyword change than it is to execute 1,000 separate changes. Consider this example:


AdWords scripts treats this code as "change was requested; add it to the current batch of changes". The bid change is not immediately carried out.

Now suppose you execute


At this point, AdWords scripts will make sure the keyword data it provides is up-to-date; if there are any outstanding changes, they will now be carried out. The above line of code will indeed change the value of the keyword bid.

For this reason, this snippet of code will execute quickly:

while (keywords.hasNext()) {
  var keyword = keywords.next();

While this—much more slowly:

while (keywords.hasNext()) {
  var keyword = keywords.next();
  Logger.log("Keyword " + keyword.getText() + " is now paused");

The speed difference will be more pronounced in real executions than in preview mode.

Whenever possible, avoid alternating changes to objects and reads from objects in loops.

Back to top

Reports vs Selectors

Unlike regular selectors, Reports provide access to more data. For large queries, reports will often perform better, and they will not hit the normal fetching quotas. To modify the underlying entities, you will still need selectors. In summary,

Use Reports when

  • Fetching a large data set.
  • Looking for stats not available to regular entities.

Use Selectors when

  • Fetching a small number of entities.
  • Fetched entities need to be changed.
  • Ordering of results is important.

As an example, suppose you want to log the Impressions, Clicks and Ctr of every keyword with more than 10 clicks in the past 7 days. Using selectors, you would do this:

var keywords = AdWordsApp.keywords().withCondition("Clicks > 10").forDateRange("LAST_7_DAYS").get();
while (keywords.hasNext()) {
    var keyword = keywords.next();
    var stats = keyword.getStatsFor("LAST_7_DAYS");
    Logger.log("Keyword: %s Impressions: %s Clicks %s Ctr: %s", keyword.getText(), stats.getImpressions(), stats.getClicks(), stats.getCtr());

The above code makes one call to get the list of keywords and additional calls to fetch the stats. With reports, this is much simpler (and faster for large data sets!):

var rows = AdWordsApp.report("SELECT KeywordText, Impressions, Clicks, Ctr from KEYWORDS_PERFORMANCE_REPORT WHERE Clicks > 10 DURING LAST_7_DAYS").rows();
while (rows.hasNext()) {
    var row = rows.next();
    Logger.log("Keyword: %s Impressions: %s Clicks %s Ctr: %s", row['KeywordText'], row['Impressions'], row['Clicks'], row['Ctr']);

With reports, it takes a single call to download the report, complete with both attribute fields (such as KeywordText) and metrics (such as clicks, impressions, etc.). If you exclude segment fields (such as Date) and don't provide any conditions, you will get back one record for each entity (i.e. keyword in KEYWORDS_PERFORMANCE_REPORT). This lets you iterate over far more keywords than you normally could using regular selectors.

Back to top