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

Reporting Samples

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

Download a criteria performance report with AWQL

#!/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 code example gets and downloads a criteria report using an AWQL query.
# Currently, there is only production support for reports download.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::Utilities::ReportQueryBuilder;
use Google::Ads::Common::ReportUtils;

use Cwd qw(abs_path);
use File::HomeDir;
use File::Spec;

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

  # Create report query.
  my (undef, undef, undef, $mday, $mon, $year) = localtime(time - 60 * 60 * 24);
  my $yesterday = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);
  (undef, undef, undef, $mday, $mon, $year) =
    localtime(time - 60 * 60 * 24 * 4);
  my $four_days_ago = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);

  my $report_query =
    Google::Ads::AdWords::Utilities::ReportQueryBuilder->new(
    {client => $client})
    ->select([
      "CampaignId",   "AdGroupId",   "Id",     "Criteria",
      "CriteriaType", "Impressions", "Clicks", "Cost"
    ]
    )->from("CRITERIA_PERFORMANCE_REPORT")
    ->where("Status")
    ->in(["ENABLED", "PAUSED"])
    ->during($four_days_ago, $yesterday)
    ->build();

  # Optional: Modify the reporting configuration of the client to suppress
  # header, column, or summary rows in the report output and include data with
  # zero impressions. You can choose to return enum field values as enum
  # values instead of display values.
  # You can also configure this via your adwords.properties configuration file.
  $client->get_reporting_config()->set_skip_header(0);
  $client->get_reporting_config()->set_skip_column_header(0);
  $client->get_reporting_config()->set_skip_summary(0);
  $client->get_reporting_config()->set_include_zero_impressions(1);
  $client->get_reporting_config()->set_use_raw_enum_values(0);

  # Get the report handler.
  my $report_handler = Google::Ads::Common::ReportUtils::get_report_handler({
      query  => $report_query,
      format => "CSV"
    },
    $client
  );

  # Download the report using the appropriate method on ReportDownloadHandler.
  my $result;
  if ($output_file) {
    $result = $report_handler->save($output_file);
  } else {
    $result = $report_handler->get_as_string();
  }

  if (!$result) {
    printf("An error has occurred of type '%s', triggered by '%s'.\n",
      $result->get_type(), $result->get_trigger());
  } elsif ($output_file) {
    printf("Report was downloaded to \"%s\".\n", $output_file);
  } else {
    printf("%s\n", $result);
  }

  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);

my $output_file =
  File::Spec->catfile(File::HomeDir->my_home, "criteria_report.csv");

# Call the example
download_criteria_report_with_awql($client, $output_file);

Download a criteria performance report using selectors

#!/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 code example gets and downloads a criteria report from an XML
# report definition.
# Currently, there is only production support for reports download.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::Reports::Predicate;
use Google::Ads::AdWords::Reports::ReportDefinition;
use Google::Ads::AdWords::Reports::Selector;
use Google::Ads::Common::ReportUtils;

use Cwd qw(abs_path);
use File::HomeDir;
use File::Spec;

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

  # Create criteria status predicate.
  my $predicate = Google::Ads::AdWords::Reports::Predicate->new({
      field    => "Status",
      operator => "IN",
      values   => ["ENABLED", "PAUSED"]});

  # Create selector.
  my $selector = Google::Ads::AdWords::Reports::Selector->new({
      fields => [
        "CampaignId", "AdGroupId", "Id",          "CriteriaType",
        "Criteria",   "FinalUrls", "Impressions", "Clicks",
        "Cost"
      ],
      predicates => [$predicate]});

  # Create report definition.
  my (undef, undef, undef, $mday, $mon, $year) = localtime(time);
  my $today = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);

  my $report_definition = Google::Ads::AdWords::Reports::ReportDefinition->new({
      reportName     => "Last 7 days CRITERIA_PERFORMANCE_REPORT #" . $today,
      dateRangeType  => "LAST_7_DAYS",
      reportType     => "CRITERIA_PERFORMANCE_REPORT",
      downloadFormat => "CSV",
      selector       => $selector
  });

  # Optional: Modify the reporting configuration of the client to suppress
  # header, column, or summary rows in the report output and include data with
  # zero impressions. You can choose to return enum field values as enum
  # values instead of display values.
  # You can also configure this via your adwords.properties configuration file.
  $client->get_reporting_config()->set_skip_header(0);
  $client->get_reporting_config()->set_skip_column_header(0);
  $client->get_reporting_config()->set_skip_summary(0);
  $client->get_reporting_config()->set_include_zero_impressions(0);
  $client->get_reporting_config()->set_use_raw_enum_values(0);

  # Get the report handler.
  my $report_handler =
    Google::Ads::Common::ReportUtils::get_report_handler($report_definition,
    $client);

  # Download the report using the appropriate method on ReportDownloadHandler.
  my $result;
  if ($output_file) {
    $result = $report_handler->save($output_file);
  } else {
    $result = $report_handler->get_as_string();
  }

  if (!$result) {
    printf("An error has occurred of type '%s', triggered by '%s'.\n",
      $result->get_type(), $result->get_trigger());
  } elsif ($output_file) {
    printf("Report was downloaded to \"%s\".\n", $output_file);
  } else {
    printf("%s\n", $result);
  }

  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);

my $output_file =
  File::Spec->catfile(File::HomeDir->my_home, "criteria_report.csv");

# Call the example
download_criteria_report_with_selector($client, $output_file);

Get the report fields from a report

#!/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 report fields of a CRITERIA_PERFORMANCE_REPORT.

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

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

use Cwd qw(abs_path);

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

  # The type of the report to get fields for.
  my $report_type = "CRITERIA_PERFORMANCE_REPORT";

  # Get report fields.
  my $report_definition_fields =
    $client->ReportDefinitionService()
    ->getReportFields({reportType => $report_type});

  # Display report fields.
  printf "The report type \"%s\" contains the following fields:\n",
    $report_type;

  foreach my $report_definition_field (@{$report_definition_fields}) {
    printf("- %s (%s)",
      $report_definition_field->get_fieldName(),
      $report_definition_field->get_fieldType());
    if ($report_definition_field->get_enumValues()) {
      printf " := [%s]",
        join(", ", @{$report_definition_field->get_enumValues()});
    }
    print "\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_report_fields($client);

Download a report for multiple accounts

#!/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 and downloads an Ad Hoc report from an XML report
# definition for all accounts directly under a manager account.
# This example should be run against an AdWords manager account.
# NOTE: Even though this example is called parallel_report_download, this shows
# how to download the reports serially.

use strict;
use warnings;
use lib "../../../lib";
use utf8;

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::Reports::ReportDefinition;
use Google::Ads::AdWords::Reports::Selector;
use Google::Ads::Common::ReportUtils;
use Google::Ads::AdWords::v201809::Paging;
use Google::Ads::AdWords::v201809::Selector;

use Cwd qw(abs_path);
use File::Spec;
use File::Temp qw/ tempdir /;

use constant PAGE_SIZE => 500;
# Set a timeout to fail if the report is not downloaded in a specified amount
# of time.
use constant JOB_TIMEOUT_IN_MILLISECONDS => 180000;
# The time to sleep in between retries will start at this time. Then an
# exponential back-off will be instituted.
use constant JOB_BASE_WAITTIME_IN_MILLISECONDS => 10000;

# Example main subroutine.
sub parallel_report_download {
  my $client           = shift;
  my $report_directory = tempdir();

  # Retrieve all accounts under the manager account.
  my @customers = __get_all_managed_customers($client);

  # Create selector.
  my $selector = Google::Ads::AdWords::Reports::Selector->new(
    {fields => ["CampaignId", "AdGroupId", "Impressions", "Clicks", "Cost"]});

  # Create report definition.
  my $report_definition = Google::Ads::AdWords::Reports::ReportDefinition->new({
      reportName     => "Custom ADGROUP_PERFORMANCE_REPORT",
      dateRangeType  => "LAST_7_DAYS",
      reportType     => "ADGROUP_PERFORMANCE_REPORT",
      downloadFormat => "CSV",
      selector       => $selector
  });

  # Optional: Modify the reporting configuration of the client to suppress
  # header, column, or summary rows in the report output and include data with
  # zero impressions. You can choose to return enum field values as enum
  # values instead of display values.
  # You can also configure this via your adwords.properties configuration file.
  $client->get_reporting_config()->set_skip_header(0);
  $client->get_reporting_config()->set_skip_column_header(0);
  $client->get_reporting_config()->set_skip_summary(0);
  $client->get_reporting_config()->set_include_zero_impressions(0);
  $client->get_reporting_config()->set_use_raw_enum_values(0);

  printf("Downloading report for %d managed customers.\n", scalar @customers);

  my $successful_reports = {};
  my $failed_reports     = {};
  foreach my $customer_id (@customers) {
    my $output_file =
      File::Spec->catfile($report_directory,
      sprintf("adgroup_%010d.csv", $customer_id));
    $client->set_client_id($customer_id);

    # Get the report handler.
    my $report_handler =
      Google::Ads::Common::ReportUtils::get_report_handler($report_definition,
      $client);

    # If there is a failure, then retry the request.
    my $result;
    my $retries  = 0;
    my $end_time = time + JOB_TIMEOUT_IN_MILLISECONDS;
    do {
      # Download the report.
      $result = $report_handler->save($output_file);

      my $waittime_in_milliseconds =
        JOB_BASE_WAITTIME_IN_MILLISECONDS * (2**$retries);
      if (  ((time + $waittime_in_milliseconds) < $end_time)
        and !$result
        and $result->get_response_code() >= 500)
      {
        printf("Report for client customer ID %s was not downloaded" .
            " due to: %s - %s\n",
          $customer_id, $result->get_type(), $result->get_trigger());
        printf("Sleeping %d milliseconds before retrying...\n",
          $waittime_in_milliseconds);
        sleep($waittime_in_milliseconds / 1000);    # Convert to seconds.
        $retries++;
      }
    } while (time < $end_time
      and !$result
      and $result->get_response_code() >= 500);

    if (!$result) {
      printf("Report for client customer ID %s was not downloaded" .
          " due to: %s - %s\n",
        $customer_id, $result->get_type(), $result->get_trigger());
      $failed_reports->{$customer_id} = sprintf("%s: %s - %s",
        $output_file, $result->get_type(), $result->get_trigger());
    } else {
      printf(
        "Report for client customer ID %s successfully downloaded to: %s\n",
        $customer_id, $output_file);
      $successful_reports->{$customer_id} = $output_file;
    }
  }

  printf("All downloads completed. Results:\n");
  printf("Successful reports:\n");
  foreach my $client_customer_id (keys $successful_reports) {
    printf("\tClient ID %s => '%s'\n",
      $client_customer_id, $successful_reports->{$client_customer_id});
  }
  printf("Failed reports:\n");
  foreach my $client_customer_id (keys $failed_reports) {
    printf("\tClient ID %s => '%s'\n",
      $client_customer_id, $failed_reports->{$client_customer_id});
  }
  printf("End of results.");

  return 1;
}

# Retrieve all the customers under a manager account.
sub __get_all_managed_customers {
  my ($client) = @_;

  # Create selector.
  my $paging = Google::Ads::AdWords::v201809::Paging->new({
      startIndex    => 0,
      numberResults => PAGE_SIZE
  });
  my $predicate = Google::Ads::AdWords::v201809::Predicate->new({
      field    => "CanManageClients",
      operator => "EQUALS",
      values   => "false"
  });
  my $selector = Google::Ads::AdWords::v201809::Selector->new({
      fields     => ["CustomerId"],
      paging     => $paging,
      predicates => [$predicate]});

  my $page;
  my @customers = ();
  do {
    $page =
      $client->ManagedCustomerService()->get({serviceSelector => $selector});

    if ($page->get_entries()) {
      foreach my $customer (@{$page->get_entries()}) {
        push @customers, $customer->get_customerId();
      }
    }
    $paging->set_startIndex($paging->get_startIndex() + PAGE_SIZE);
  } while ($paging->get_startIndex() < $page->get_totalNumEntries());

  return @customers;
}

# 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
parallel_report_download($client);

Stream results from a report

#!/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 streams the result of an ad hoc report, collecting total
# impressions by campaign for each line. This demonstrates how you can extract
# data from a large report without holding the entire result set in memory
# or using files.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::Utilities::ReportQueryBuilder;
use Google::Ads::Common::ReportUtils;

use Cwd qw(abs_path);

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

  my $report_query =
      Google::Ads::AdWords::Utilities::ReportQueryBuilder->new(
          {client => $client})
          ->select([
          "Id", "AdNetworkType1", "Impressions",
      ])->from("CRITERIA_PERFORMANCE_REPORT")
          ->where("Status")
          ->in(["ENABLED", "PAUSED"])
          ->during("LAST_7_DAYS")
          ->build();

  # Optional: Set the reporting configuration of the session to suppress
  # header, column name, or summary rows in the report output. You can also
  # configure this via your adwords.properties configuration file.
  # In addition, you can set whether you want to explicitly include or
  # exclude zero impression rows and you can set whether to return enum values
  # or display values for enum fields.
  $client->get_reporting_config()->set_skip_header(1);
  $client->get_reporting_config()->set_skip_column_header(1);
  $client->get_reporting_config()->set_skip_summary(1);
  $client->get_reporting_config()->set_include_zero_impressions(0);
  $client->get_reporting_config()->set_use_raw_enum_values(0);

  # Get the report handler.
  my $report_handler = Google::Ads::Common::ReportUtils::get_report_handler({
      query  => $report_query,
      format => "CSV"
    },
    $client
  );

  # Pass in the anonymous subroutine that will be called as data is available
  # for processing.
  my %impressions_by_ad_network_type1 = ();
  my $incomplete_line                 = '';
  my $result                          = $report_handler->process_contents(
    sub {
      my ($data, $response) = @_;
      # If the line is starting in the middle, then prepend the incomplete line
      # from last time.
      $data            = $incomplete_line . $data;
      $incomplete_line = '';
      # Match the line that is ID,AdNetworkType1,Impressions
      # Example: 123456,Search Network,5
      while ($data =~ /(\d+),([^,]+),(\d+)\n/g) {
        my ($ad_network_type1, $impressions) = ($2, $3);
        my $impressions_total =
          $impressions_by_ad_network_type1{$ad_network_type1};
        $impressions_total =
          (defined($impressions_total)) ? $impressions_total : 0;
        $impressions_by_ad_network_type1{$ad_network_type1} =
          $impressions_total + $impressions;
      }
      # If everything wasn't processed, then save off the incomplete line to
      # be prepended the next time this subroutine is called.
      if ($data =~ /\n(.*)$/) {
        $incomplete_line = $1;
      }
    });

  if (!$result) {
    printf("An error has occurred of type '%s', triggered by '%s'.\n",
      $result->get_type(), $result->get_trigger());
    return 1;
  }

  # Print the impression totals by ad network type 1.
  print("Total impressions by ad network type 1:\n");
  while (my ($key, $val) = each %impressions_by_ad_network_type1) {
    printf "$key\t$val\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.
stream_criteria_report_results($client);