The AdWords API will sunset on April 27, 2022. Migrate to the Google Ads API to take advantage of the latest Google Ads features.

Optimization Samples

The code samples below provide examples of common optimization functions using the AdWords API. Client Library.

Get keyword traffic estimates

#!/usr/bin/perl -w
#
# Copyright 2017, 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.
#
# This example gets keyword traffic estimates.

use strict;

use lib "../../../lib";

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201809::AdGroupEstimateRequest;
use Google::Ads::AdWords::v201809::CampaignEstimateRequest;
use Google::Ads::AdWords::v201809::Keyword;
use Google::Ads::AdWords::v201809::KeywordEstimateRequest;
use Google::Ads::AdWords::v201809::Language;
use Google::Ads::AdWords::v201809::Location;
use Google::Ads::AdWords::v201809::TrafficEstimatorSelector;

use Cwd qw(abs_path);

# Example main subroutine.
sub estimate_keyword_traffic {
  my $client = shift;

  # Create keywords. Refer to the TrafficEstimatorService documentation for
  # the maximum number of keywords that can be passed in a single request.
  # https://developers.google.com/adwords/api/docs/reference/latest/TrafficEstimatorService
  my @keywords = (
    Google::Ads::AdWords::v201809::Keyword->new({
        text      => "mars cruise",
        matchType => "BROAD"
      }
    ),
    Google::Ads::AdWords::v201809::Keyword->new({
        text      => "cheap cruise",
        matchType => "PHRASE"
      }
    ),
    Google::Ads::AdWords::v201809::Keyword->new({
        text      => "cruise",
        matchType => "EXACT"
      }));

  my @negative_keywords = (
    Google::Ads::AdWords::v201809::Keyword->new({
        text      => "moon walk",
        matchType => "BROAD"
      }));

  # Create a keyword estimate request for each keyword.
  my @keyword_estimate_requests;
  foreach my $keyword (@keywords) {
    push @keyword_estimate_requests,
      Google::Ads::AdWords::v201809::KeywordEstimateRequest->new(
      {keyword => $keyword,});
  }
  foreach my $keyword (@negative_keywords) {
    push @keyword_estimate_requests,
      Google::Ads::AdWords::v201809::KeywordEstimateRequest->new({
        keyword    => $keyword,
        isNegative => 1
      });
  }

  # Create ad group estimate requests.
  my $ad_group_estimate_request =
    Google::Ads::AdWords::v201809::AdGroupEstimateRequest->new({
      keywordEstimateRequests => \@keyword_estimate_requests,
      maxCpc =>
        Google::Ads::AdWords::v201809::Money->new({microAmount => 1000000})});

  my $location = Google::Ads::AdWords::v201809::Location->new({
      id => "2840"    # US - see http://goo.gl/rlrFr
  });
  my $language = Google::Ads::AdWords::v201809::Language->new({
      id => "1000"    # en - see http://goo.gl/LvMmS
  });

  # Create campaign estimate requests.
  my $campaign_estimate_request =
    Google::Ads::AdWords::v201809::CampaignEstimateRequest->new({
      adGroupEstimateRequests => [$ad_group_estimate_request],
      criteria                => [$location, $language]});

  # Optional: Request a list of campaign level estimates segmented by platform.
  my $platform_estimate_request = "1";

  # Create selector.
  my $selector = Google::Ads::AdWords::v201809::TrafficEstimatorSelector->new({
      campaignEstimateRequests  => [$campaign_estimate_request],
      platformEstimateRequested => [$platform_estimate_request]});

  # Get traffic estimates.
  my $result = $client->TrafficEstimatorService()->get({selector => $selector});

  # Display traffic estimates.
  if ($result) {
    my $campaign_estimates = $result->get_campaignEstimates();
    if ($campaign_estimates) {
      # Display the campaign level estimates segmented by platform.
      foreach my $campaign_estimate (@{$campaign_estimates}) {
        if ($campaign_estimate->get_platformEstimates()) {
          foreach
            my $platform_estimate (@{$campaign_estimate->get_platformEstimates()})
          {
            my $platform_message = sprintf(
              "Results for the platform with ID: %d and name : %s",
              $platform_estimate->get_platform()->get_id(),
              $platform_estimate->get_platform()->get_platformName());
            display_mean_estimates(
              $platform_message,
              $platform_estimate->get_minEstimate(),
              $platform_estimate->get_maxEstimate());
          }
        }

        if ($campaign_estimate->get_adGroupEstimates()) {
          my $keyword_estimates =
            $campaign_estimate->get_adGroupEstimates()->[0]
            ->get_keywordEstimates();
          for (my $i = 0 ; $i < scalar(@{$keyword_estimates}) ; $i++) {
            # Negative keywords don't generate estimates but instead affect
            # estimates of your other keywords, the following condition just
            # skips printing out estimates for a negative keyword.
            if ($keyword_estimate_requests[$i]->get_isNegative()) {
              next;
            }

            my $keyword = $keyword_estimate_requests[$i]->get_keyword();
            my $keyword_estimate = $keyword_estimates->[$i];
            my $keyword_message =
              sprintf
              "Results for the keyword with text '%s' and match type '%s':\n",
              $keyword->get_text(), $keyword->get_matchType();
            display_mean_estimates(
              $keyword_message,
              $keyword_estimate->get_min(),
              $keyword_estimate->get_max());
          }
        }
      }
    }
  } else {
    print "No traffic estimates were returned.\n";
  }
  return 1;
}

# Display the mean estimates.
sub display_mean_estimates {
  my ($message, $min_estimate, $max_estimate) = @_;

  # Find the mean of the min and max values.
  my $mean_average_cpc = calculate_money_mean($min_estimate->get_averageCpc(),
    $max_estimate->get_averageCpc());
  my $mean_average_position = calculate_mean(
    $min_estimate->get_averagePosition(),
    $max_estimate->get_averagePosition());
  my $mean_clicks = calculate_mean($min_estimate->get_clicksPerDay(),
    $max_estimate->get_clicksPerDay());
  my $mean_total_cost = calculate_money_mean($min_estimate->get_totalCost(),
    $max_estimate->get_totalCost());

  printf "%s:\n",                            $message;
  printf "  Estimated average CPC: %.2f\n",  $mean_average_cpc;
  printf "  Estimated ad position: %.2f\n",  $mean_average_position;
  printf "  Estimated daily clicks: %.2f\n", $mean_clicks;
  printf "  Estimated daily cost: %.2f\n\n", $mean_total_cost;
}

# Calculates the mean microAmount of two Money objects if neither is
# null, else returns NaN.
sub calculate_money_mean {
  my ($min_money, $max_money) = @_;

  if ($min_money && $max_money) {
    return calculate_mean($min_money->get_microAmount(),
      $max_money->get_microAmount());
  }
  return 'NaN';
}

# Calculates the mean of two numbers if neither is null, else returns NaN.
sub calculate_mean {
  my ($min, $max) = @_;

  if (defined($min) && defined($max)) {
    return ($min + $max) / 2;
  }
  return 'NaN';
}

# Don't run the example if the file is being included.
if (abs_path($0) ne abs_path(__FILE__)) {
  return 1;
}

# Log SOAP XML request, response and API errors.
Google::Ads::AdWords::Logging::enable_all_logging();

# Get AdWords Client, credentials will be read from ~/adwords.properties.
my $client = Google::Ads::AdWords::Client->new({version => "v201809"});

# By default examples are set to die on any server returned fault.
$client->set_die_on_faults(1);

# Call the example
estimate_keyword_traffic($client);

Get all mobile bid modifier landscapes for a campaign

#!/usr/bin/perl -w
#
# Copyright 2017, 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.
#
# This example gets all available campaign mobile bid modifier landscapes
# for a given campaign.
# To get campaigns, run basic_operations/get_campaigns.pl.

use strict;
use lib "../../../lib";

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201809::OrderBy;
use Google::Ads::AdWords::v201809::Paging;
use Google::Ads::AdWords::v201809::Predicate;
use Google::Ads::AdWords::v201809::Selector;

use Cwd qw(abs_path);

use constant PAGE_SIZE => 100;

# Replace with a valid value of your account.
my $campaign_id = "INSERT_CAMPAIGN_ID_HERE";

# Example main subroutine.
sub get_campaign_criterion_bid_modifier_simulations {
  my $client      = shift;
  my $campaign_id = shift;

  # Create predicates.
  my $campaign_predicate = Google::Ads::AdWords::v201809::Predicate->new({
      field    => "CampaignId",
      operator => "IN",
      values   => [$campaign_id]});
  # Create selector.
  my $paging = Google::Ads::AdWords::v201809::Paging->new({
    startIndex    => 0,
    numberResults => PAGE_SIZE
  });
  my $selector = Google::Ads::AdWords::v201809::Selector->new({
      fields => [
        "BidModifier",           "CampaignId",
        "CriterionId",           "StartDate",
        "EndDate",               "LocalClicks",
        "LocalCost",             "LocalImpressions",
        "TotalLocalClicks",      "TotalLocalCost",
        "TotalLocalImpressions", "RequiredBudget"
      ],
      paging     => $paging,
      predicates => [$campaign_predicate]});

  # Display bid landscapes.
  my $landscape_points_in_previous_page = 0;
  my $start_index                       = 0;
  do {
    # Offset the start index by the number of landscape points in the last
    # retrieved page, NOT the number of entries (bid landscapes) in the page.
    $start_index += $landscape_points_in_previous_page;
    $selector->get_paging()->set_startIndex($start_index);

    # Reset the count of landscape points in preparation for processing the
    # next page.
    $landscape_points_in_previous_page = 0;

    # Request the next page of bid landscapes.
    my $page =
      $client->DataService()
      ->getCampaignCriterionBidLandscape({serviceSelector => $selector});

    if ($page->get_entries()) {
      foreach my $criterion_bid_landscape (@{$page->get_entries()}) {
        printf "Found campaign-level criterion bid modifier landscapes for" .
          " criterion with ID %d, start date '%s', end date '%s', and" .
          " landscape points:\n",
          $criterion_bid_landscape->get_criterionId(),
          $criterion_bid_landscape->get_startDate(),
          $criterion_bid_landscape->get_endDate();
        my @landscape_points = @{$criterion_bid_landscape
          ->get_landscapePoints()};
        foreach my $landscape_point (@landscape_points) {
          $landscape_points_in_previous_page++;
          printf "  bid modifier: %.2f => clicks: %d, cost: %.0f, " .
            "impressions: %d, total clicks: %d, total cost: %.0f, " .
            "total impressions: %d, and required budget: %.0f\n",
            $landscape_point->get_bidModifier(),
            $landscape_point->get_clicks(),
            $landscape_point->get_cost()->get_microAmount(),
            $landscape_point->get_impressions(),
            $landscape_point->get_totalLocalClicks(),
            $landscape_point->get_totalLocalCost()->get_microAmount(),
            $landscape_point->get_totalLocalImpressions(),
            $landscape_point->get_requiredBudget()->get_microAmount();
        }
      }
    }
  } while ($landscape_points_in_previous_page >= PAGE_SIZE);

  return 1;
}

# Don't run the example if the file is being included.
if (abs_path($0) ne abs_path(__FILE__)) {
  return 1;
}

# Log SOAP XML request, response and API errors.
Google::Ads::AdWords::Logging::enable_all_logging();

# Get AdWords Client, credentials will be read from ~/adwords.properties.
my $client = Google::Ads::AdWords::Client->new({version => "v201809"});

# By default examples are set to die on any server returned fault.
$client->set_die_on_faults(1);

# Call the example
get_campaign_criterion_bid_modifier_simulations($client, $campaign_id);


Get a bid landscape for an ad group and criterion

#!/usr/bin/perl -w
#
# Copyright 2017, 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.
#
# This example gets bid landscapes for a keywords. To get keywords, run
# basic_operations/get_keywords.pl.

use strict;
use lib "../../../lib";

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::Utilities::ServiceQueryBuilder;

use Cwd qw(abs_path);

use constant PAGE_SIZE => 100;

# Replace with valid values of your account.
my $ad_group_id = "INSERT_AD_GROUP_ID_HERE";
my $keyword_id  = "INSERT_CRITERION_ID_HERE";

# Example main subroutine.
sub get_keyword_bid_simulations {
  my ($client, $ad_group_id, $keyword_id) = @_;


  # Create a query to select all keyword bid simulations for the
  # specified ad group.
  my $query_builder = Google::Ads::AdWords::Utilities::ServiceQueryBuilder->new(
      {client => $client})
      ->select([
      "AdGroupId",                "CriterionId",
      "StartDate",                "EndDate",
      "Bid",                      "BiddableConversions",
      "BiddableConversionsValue", "LocalClicks",
      "LocalCost",                "LocalImpressions"])
      ->where("AdGroupId")->in([$ad_group_id])
      ->where("CriterionId")->in([$keyword_id])
      ->limit(0, PAGE_SIZE);

  # Display bid landscapes.
  my $landscape_points_in_previous_page = 0;
  my $page;
  do {
    # Offset the start index by the number of landscape points in the last
    # retrieved page, NOT the number of entries (bid landscapes) in the page.
    if (defined($page)) {
      $query_builder->next_page($landscape_points_in_previous_page);
    }

    # Reset the count of landscape points in preparation for processing the
    # next page.
    $landscape_points_in_previous_page = 0;

    # Request the next page of bid landscapes.
    $page =
      $client->DataService()
      ->queryCriterionBidLandscape({query => $query_builder->build()});

    if ($page->get_entries()) {
      foreach my $criterion_bid_landscape (@{$page->get_entries()}) {
        printf "Criterion bid landscape with ad group ID %d, criterion ID " .
          " %d, start date %s, end date %s, with landscape points:\n",
          $criterion_bid_landscape->get_adGroupId(),
          $criterion_bid_landscape->get_criterionId(),
          $criterion_bid_landscape->get_startDate(),
          $criterion_bid_landscape->get_endDate();
        foreach my $bid_landscape_point (
          @{$criterion_bid_landscape->get_landscapePoints()})
        {
          $landscape_points_in_previous_page++;
          printf "  bid: %d => clicks: %d, cost: %d, impressions: %d" .
            ", biddable conversions: %.2f, biddable " .
            "conversions value: %.2f\n",
            $bid_landscape_point->get_bid()->get_microAmount(),
            $bid_landscape_point->get_clicks(),
            $bid_landscape_point->get_cost()->get_microAmount(),
            $bid_landscape_point->get_impressions(),
            $bid_landscape_point->get_biddableConversions(),
            $bid_landscape_point->get_biddableConversionsValue();
        }
        printf(" was found.");
      }
    }
  } while ($query_builder->has_next($page, $landscape_points_in_previous_page));
  return 1;
}

# Don't run the example if the file is being included.
if (abs_path($0) ne abs_path(__FILE__)) {
  return 1;
}

# Log SOAP XML request, response and API errors.
Google::Ads::AdWords::Logging::enable_all_logging();

# Get AdWords Client, credentials will be read from ~/adwords.properties.
my $client = Google::Ads::AdWords::Client->new({version => "v201809"});

# By default examples are set to die on any server returned fault.
$client->set_die_on_faults(1);

# Call the example
get_keyword_bid_simulations($client, $ad_group_id, $keyword_id);

#!/usr/bin/perl -w
#
# Copyright 2017, 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.
#
# This example gets keywords related to a list of seed keywords.

use strict;
use lib "../../../lib";

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201809::Language;
use Google::Ads::AdWords::v201809::LanguageSearchParameter;
use Google::Ads::AdWords::v201809::NetworkSearchParameter;
use Google::Ads::AdWords::v201809::NetworkSetting;
use Google::Ads::AdWords::v201809::Paging;
use Google::Ads::AdWords::v201809::RelatedToQuerySearchParameter;
use Google::Ads::AdWords::v201809::SeedAdGroupIdSearchParameter;
use Google::Ads::AdWords::v201809::TargetingIdeaSelector;
use Google::Ads::Common::MapUtils;

use Cwd qw(abs_path);

# Replace with valid values of your account.
# If you do not want to use an existing ad group to seed your request, you can
# set this to undef.
my $ad_group_id = "INSERT_AD_GROUP_ID_HERE";

# Example main subroutine.
sub get_keyword_ideas {
  my ($client, $ad_group_id) = @_;

  # Create selector.
  my $selector = Google::Ads::AdWords::v201809::TargetingIdeaSelector->new({
    requestType => "IDEAS",
    ideaType    => "KEYWORD"
  });
  $selector->set_requestedAttributeTypes([
    "KEYWORD_TEXT", "SEARCH_VOLUME",
    "AVERAGE_CPC",  "COMPETITION",
    "CATEGORY_PRODUCTS_AND_SERVICES"
  ]);

  # Create related to query search parameter.
  my @search_parameters = ();
  my $related_to_query_search_parameter =
    Google::Ads::AdWords::v201809::RelatedToQuerySearchParameter->new(
    {queries => ["bakery", "pastries", "birthday cake"]});
  push @search_parameters, $related_to_query_search_parameter;

  # Set selector paging (required for targeting idea service).
  my $paging = Google::Ads::AdWords::v201809::Paging->new({
    startIndex    => 0,
    numberResults => 10
  });
  $selector->set_paging($paging);

  # Language setting (not-required).
  # The ID can be found in the documentation:
  #   https://developers.google.com/adwords/api/docs/appendix/languagecodes
  my $language_english =
    Google::Ads::AdWords::v201809::Language->new({id => 1000});
  my $language_search_parameter =
    Google::Ads::AdWords::v201809::LanguageSearchParameter->new(
    {languages => [$language_english]});
  push @search_parameters, $language_search_parameter;

  # Create network search paramter (optional).
  my $network_setting = Google::Ads::AdWords::v201809::NetworkSetting->new({
    targetGoogleSearch         => 1,
    targetSearchNetwork        => 0,
    targetContentNetwork       => 0,
    targetPartnerSearchNetwork => 0
  });
  my $network_setting_parameter =
    Google::Ads::AdWords::v201809::NetworkSearchParameter->new(
    {networkSetting => $network_setting});
  push @search_parameters, $network_setting_parameter;

  # Optional: Use an existing ad group to generate ideas.
  if ($ad_group_id) {
    my $seed_ad_group_id_search_parameter =
      Google::Ads::AdWords::v201809::SeedAdGroupIdSearchParameter->new({
        adGroupId => $ad_group_id
      });
    push @search_parameters, $seed_ad_group_id_search_parameter;
  }

  $selector->set_searchParameters(\@search_parameters);

  # Get keyword ideas.
  my $page = $client->TargetingIdeaService()->get({selector => $selector});

  # Display keyword ideas.
  if ($page->get_entries()) {
    foreach my $targeting_idea (@{$page->get_entries()}) {
      my $data =
        Google::Ads::Common::MapUtils::get_map($targeting_idea->get_data());
      my $keyword = $data->{"KEYWORD_TEXT"}->get_value();
      my $search_volume =
          $data->{"SEARCH_VOLUME"}->get_value()
        ? $data->{"SEARCH_VOLUME"}->get_value()
        : 0;
      my $categories =
          $data->{"CATEGORY_PRODUCTS_AND_SERVICES"}->get_value()
        ? $data->{"CATEGORY_PRODUCTS_AND_SERVICES"}->get_value()
        : [];
      my $average_cpc =
        $data->{"AVERAGE_CPC"}->get_value()->get_microAmount();
      my $competition = $data->{"COMPETITION"}->get_value();
      printf "Keyword with text '%s', monthly search volume %d, average CPC" .
        " %d, and competition %.2f was found with categories: '%s'\n", $keyword,
        $search_volume, $average_cpc, $competition, join(", ", @{$categories});
    }
  } else {
    print "No related keywords were found.\n";
  }

  return 1;
}

# Don't run the example if the file is being included.
if (abs_path($0) ne abs_path(__FILE__)) {
  return 1;
}

# Log SOAP XML request, response and API errors.
Google::Ads::AdWords::Logging::enable_all_logging();

# Get AdWords Client, credentials will be read from ~/adwords.properties.
my $client = Google::Ads::AdWords::Client->new({version => "v201809"});

# By default examples are set to die on any server returned fault.
$client->set_die_on_faults(1);

# Call the example
get_keyword_ideas($client, $ad_group_id);