Campaign Management Samples

The code samples below provide examples for managing campaigns using the AdWords API. Client Library.

Add a campaign group and sets a performance target for that group

#!/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 adds a campaign group and sets a performance target for
# that group. To get campaigns, run get_campaigns.pl. To download reports, run
# download_criteria_report_with_awql.pl.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201708::Campaign;
use Google::Ads::AdWords::v201708::CampaignGroup;
use Google::Ads::AdWords::v201708::CampaignGroupOperation;
use Google::Ads::AdWords::v201708::CampaignGroupPerformanceTarget;
use Google::Ads::AdWords::v201708::CampaignGroupPerformanceTargetOperation;
use Google::Ads::AdWords::v201708::CampaignOperation;
use Google::Ads::AdWords::v201708::Money;
use Google::Ads::AdWords::v201708::PerformanceTarget;

use Cwd qw(abs_path);
use Data::Uniqid qw(uniqid);

# Replace with valid values of your account.
my $campaign_ids = ["INSERT_CAMPAIGN_ID_1_HERE", "INSERT_CAMPAIGN_ID_2_HERE"];

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

  my $campaign_group = _create_campaign_group($client);
  _add_campaigns_to_group($client, $campaign_group->get_id(), $campaign_ids);
  _create_performance_target($client, $campaign_group->get_id());
  printf(
    "Campaign group and its performance target were setup successfully.\n");
  return 1;
}

# Create a campaign group.
sub _create_campaign_group {
  my ($client) = @_;

  # Create the campaign group.
  my $campaign_group = Google::Ads::AdWords::v201708::CampaignGroup->new({
    name => sprintf("Mars campaign group - #%s", uniqid()),
  });
  # Create the operation.
  my $operation = Google::Ads::AdWords::v201708::CampaignGroupOperation->new({
    operator => "ADD",
    operand  => $campaign_group
  });

  my $result =
    $client->CampaignGroupService()->mutate({operations => [$operation]});

  $campaign_group = $result->get_value()->[0];

  printf(
    "Campaign group with ID %d and name '%s' was created.\n",
    $campaign_group->get_id(),
    $campaign_group->get_name());
  return $campaign_group;
}

# Add multiple campaigns to the campaign group.
sub _add_campaigns_to_group {
  my ($client, $campaign_group_id, $campaign_ids) = @_;

  my @operations = ();
  foreach my $campaign_id (@{$campaign_ids}) {
    my $campaign = Google::Ads::AdWords::v201708::Campaign->new({
      id              => $campaign_id,
      campaignGroupId => $campaign_group_id
    });

    # Create operation.
    my $campaign_operation =
      Google::Ads::AdWords::v201708::CampaignOperation->new({
        operator => "SET",
        operand  => $campaign
      });
    push @operations, $campaign_operation;
  }

  # Add campaigns.
  my $result = $client->CampaignService()->mutate({operations => \@operations});

  # Display campaigns.
  foreach my $campaign (@{$result->get_value()}) {
    printf "Campaign with ID %d was added to campaign group with ID %d.\n",
      $campaign->get_id(), $campaign->get_campaignGroupId();
  }
}

# Creates a performance target for the campaign group.
sub _create_performance_target {
  my ($client, $campaign_group_id) = @_;

  # Start the performance target today, and run it for the next 90 days.
  my (undef, undef, undef, $mday, $mon, $year) = localtime(time);
  my $start_date = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);
  (undef, undef, undef, $mday, $mon, $year) =
    localtime(time + 60 * 60 * 24 * 90);
  my $end_date = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);

  my $performance_target =
    Google::Ads::AdWords::v201708::PerformanceTarget->new({
      # Keep the CPC for the campaigns < $3.
      efficiencyTargetType  => "CPC_LESS_THAN_OR_EQUAL_TO",
      efficiencyTargetValue => 3000000,
      # Keep the maximum spend under $50.
      spendTargetType => "MAXIMUM",
      spendTarget =>
        Google::Ads::AdWords::v201708::Money->new({microAmount => 500000000}),
      # Aim for at least 3000 clicks.
      volumeTargetValue => 3000,
      volumeGoalType    => "MAXIMIZE_CLICKS",
      startDate         => $start_date,
      endDate           => $end_date
    });

  # Create the performance target.
  my $campaign_group_performance_target =
    Google::Ads::AdWords::v201708::CampaignGroupPerformanceTarget->new({
      campaignGroupId   => $campaign_group_id,
      performanceTarget => $performance_target
    });
  # Create the operation.
  my $operation =
    Google::Ads::AdWords::v201708::CampaignGroupPerformanceTargetOperation->new(
    {
      operator => "ADD",
      operand  => $campaign_group_performance_target
    });

  my $result =
    $client->CampaignGroupPerformanceTargetService()
    ->mutate({operations => [$operation]});

  $campaign_group_performance_target = $result->get_value()->[0];

  printf(
    "Campaign performance target with ID %d was added for campaign group ID " .
    "%d.\n",
    $campaign_group_performance_target->get_id(),
    $campaign_group_performance_target->get_campaignGroupId());
}

# 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 => "v201708"});

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

# Call the example
add_campaign_groups_and_performance_targets($client, $campaign_ids);

Add a label to multiple campaigns

#!/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 adds a label to multiple campaigns.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201708::Campaign;
use Google::Ads::AdWords::v201708::CampaignLabel;
use Google::Ads::AdWords::v201708::CampaignLabelOperation;

use Cwd qw(abs_path);
use Data::Uniqid qw(uniqid);

# Replace with valid values of your account.
my $campaign_ids = ["INSERT_CAMPAIGN_ID_1_HERE", "INSERT_CAMPAIGN_ID_2_HERE"];
my $label_id = "INSERT_LABEL_ID_HERE";

# Example main subroutine.
sub add_campaign_labels {
  my $client       = shift;
  my $campaign_ids = shift;
  my $label_id     = shift;

  my @operations = ();

  # Create label operations.
  foreach my $campaign_id (@{$campaign_ids}) {
    my $campaign_label = Google::Ads::AdWords::v201708::CampaignLabel->new({
        campaignId => $campaign_id,
        labelId    => $label_id
    });
    my $campaign_label_operation =
      Google::Ads::AdWords::v201708::CampaignLabelOperation->new({
        operator => "ADD",
        operand  => $campaign_label
      });
    push @operations, $campaign_label_operation;
  }

  # Add campaign labels.
  my $result =
    $client->CampaignService()->mutateLabel({operations => \@operations});

  # Display campaign labels.
  foreach my $campaign_label (@{$result->get_value()}) {
    printf "Campaign label for campaign ID %d and label ID %d was added.\n",
      $campaign_label->get_campaignId(), $campaign_label->get_labelId();
  }

  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 => "v201708"});

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

# Call the example
add_campaign_labels($client, $campaign_ids, $label_id);

Add complete campaigns using batch jobs

#!/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 illustrates how to perform multiple requests using the
# BatchJobService.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201708::AdGroup;
use Google::Ads::AdWords::v201708::AdGroupAd;
use Google::Ads::AdWords::v201708::AdGroupAdOperation;
use Google::Ads::AdWords::v201708::AdGroupCriterionOperation;
use Google::Ads::AdWords::v201708::AdGroupOperation;
use Google::Ads::AdWords::v201708::BatchJob;
use Google::Ads::AdWords::v201708::BatchJobOperation;
use Google::Ads::AdWords::v201708::BiddableAdGroupCriterion;
use Google::Ads::AdWords::v201708::Budget;
use Google::Ads::AdWords::v201708::BudgetOperation;
use Google::Ads::AdWords::v201708::CampaignCriterionOperation;
use Google::Ads::AdWords::v201708::CampaignOperation;
use Google::Ads::AdWords::v201708::CpcBid;
use Google::Ads::AdWords::v201708::ExpandedTextAd;
use Google::Ads::AdWords::v201708::Keyword;
use Google::Ads::AdWords::v201708::Money;
use Google::Ads::AdWords::v201708::NegativeCampaignCriterion;
use Google::Ads::AdWords::v201708::Predicate;
use Google::Ads::AdWords::v201708::Paging;
use Google::Ads::AdWords::v201708::Selector;
use Google::Ads::AdWords::Utilities::BatchJobHandler;
use Google::Ads::AdWords::Utilities::BatchJobHandlerError;

use Cwd qw(abs_path);
use Data::Uniqid qw(uniqid);

# Set a timeout to fail if the job does not complete in a specified amount
# of time.
use constant JOB_TIMEOUT_IN_MILLISECONDS => 180000;
# The time to sleep in between polls will start at this time. Then an
# exponential back-off will be instituted.
use constant JOB_BASE_WAITTIME_IN_MILLISECONDS => 30000;
use constant NUMBER_OF_CAMPAIGNS_TO_ADD        => 2;
use constant NUMBER_OF_ADGROUPS_TO_ADD         => 2;
use constant NUMBER_OF_KEYWORDS_TO_ADD         => 5;
# Temporary IDs are negative. Keep decrementing the number in order to always
# have a unique temporary ID.
my $temporary_id = -1;

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

  # Create a batch job, which returns an upload URL to upload the batch
  # operations and a job ID to track the job.
  my $operation = Google::Ads::AdWords::v201708::BatchJobOperation->new({
      operator => 'ADD',
      operand  => Google::Ads::AdWords::v201708::BatchJob->new({})});

  my $batch_job_result =
    $client->BatchJobService()->mutate({operations => [$operation]});

  if (!$batch_job_result->get_value()) {
    print "A batch job could not be created. No operations were uploaded.\n";
    return 1;
  }

  my $batch_job = $batch_job_result->get_value()->[0];

  printf("Batch job with ID %d was created.\n\tInitial upload URL: '%s'\n",
    $batch_job->get_id(), $batch_job->get_uploadUrl()->get_url());

  my @operations = ();
  # Create and add an operation to create a new budget.
  my $budget_operation = _create_budget_operation();
  push @operations, $budget_operation;

  # Create and add operations to create new campaigns.
  my @campaign_operations = _create_campaign_operations($budget_operation);
  push @operations, @campaign_operations;

  # Create and add operations to create new negative keyword criteria
  # for each campaign.
  my @campaign_criterion_operations =
    _create_campaign_criterion_operations(@campaign_operations);
  push @operations, @campaign_criterion_operations;

  # Create and add operations to create new ad groups.
  my @ad_group_operations = _create_ad_group_operations(@campaign_operations);
  push @operations, @ad_group_operations;

  # Create and add operations to create new ad group criteria (keywords).
  my @ad_group_criterion_operations =
    _create_ad_group_criterion_operations(@ad_group_operations);
  push @operations, @ad_group_criterion_operations;

  # Create and add operations to create new ad group ads (text ads).
  my @ad_group_ad_operations =
    _create_ad_group_ad_operations(@ad_group_operations);
  push @operations, @ad_group_ad_operations;

  # Get an instance of a utility that helps with uploading batch operations.
  my $batch_job_handler =
    Google::Ads::AdWords::Utilities::BatchJobHandler->new({client => $client});

  # Convert the list of operations into XML.
  # POST the XML to the upload URL.
  my $upload_result =
    $batch_job_handler->upload_operations(\@operations,
    $batch_job->get_uploadUrl()->get_url());
  if (!$upload_result) {
    printf("%s Error. %s\n",
      $upload_result->get_type(),
      $upload_result->get_description());
    if ($upload_result->get_type() eq "HTTP") {
      printf(
        "Type: %s\nCode: %s\nMessage: %s\nTrigger: %s\nField Path: %s\n",
        $upload_result->get_http_type(),
        $upload_result->get_http_response_code(),
        $upload_result->get_http_response_message(),
        $upload_result->get_http_trigger(),
        $upload_result->get_http_field_path());
    }
    return 1;
  }

  printf("\tOperations uploaded to upload URL: '%s'\n",
    $upload_result->get_resumable_upload_uri());

  # Verify that the operations completed.
  # This will poll until the job has completed or the timeout has expired.
  my $verify_result =
    _verify_operations($client, $batch_job_handler, $batch_job);

  # Display the results.
  my $error             = $verify_result->{error};
  my $job_result        = $verify_result->{batch_job};
  my $operations_result = $verify_result->{result};

  printf("Job with ID %d has completed with a status of '%s'.\n",
    $job_result->get_id(), $job_result->get_status());
  if (defined $error) {
    printf("%s Error. %s\n", $error->get_type(), $error->get_description());
    if ($error->get_type() eq "PROCESSING") {
      printf("%s\n", $error->get_processing_errors());
    }
    if ($error->get_type() eq "HTTP") {
      printf(
        "Type: %s\nCode: %s\nMessage: %s\nTrigger: %s\nField Path: %s\n",
        $error->get_http_type(),             $error->get_http_response_code(),
        $error->get_http_response_message(), $error->get_http_trigger(),
        $error->get_http_field_path());
    }
  }
  if ($operations_result) {
    for my $item (@{$operations_result->get_rval()}) {
      if ($item->get_errorList()) {
        printf("Error on index %d: %s\n",
          $item->get_index(), $item->get_errorList()->get_errors());
      } else {
        # Print the XML output.
        printf("Successful on index %d\n%s\n", $item->get_index(), $item);
      }
    }
  }

  return 1;
}

# Create a BudgetOperation for the Campaign.
sub _create_budget_operation {
  my $budget = Google::Ads::AdWords::v201708::Budget->new({
    # Required attributes.
    budgetId => _next_id(),
    name     => "Interplanetary budget #" . uniqid(),
    amount =>
      Google::Ads::AdWords::v201708::Money->new({microAmount => 5000000}),
    deliveryMethod => "STANDARD"
  });

  my $budget_operation = Google::Ads::AdWords::v201708::BudgetOperation->new({
    operator => "ADD",
    operand  => $budget
  });
  return $budget_operation;
}

# Create a CampaignOperations to add Campaigns.
sub _create_campaign_operations {
  my ($budget_operation) = @_;

  my @campaign_operations = ();

  for (my $i = 1 ; $i < NUMBER_OF_CAMPAIGNS_TO_ADD ; $i++) {
    my $campaign = Google::Ads::AdWords::v201708::Campaign->new({
        id                     => _next_id(),
        name                   => "Batch Campaign #" . uniqid(),
        advertisingChannelType => "SEARCH",
        # Recommendation: Set the campaign to PAUSED when creating it to stop
        # the ads from immediately serving. Set to ENABLED once you've added
        # targeting and the ads are ready to serve.
        status                 => "PAUSED",
        # Bidding strategy (required).
        biddingStrategyConfiguration =>
          Google::Ads::AdWords::v201708::BiddingStrategyConfiguration->new({
            biddingStrategyType => "MANUAL_CPC",
            # You can optionally provide a bidding scheme in place of the type.
          }
          ),
        budget => Google::Ads::AdWords::v201708::Budget->new(
          {budgetId => $budget_operation->get_operand()->get_budgetId()})});
    my $campaign_operation =
      Google::Ads::AdWords::v201708::CampaignOperation->new({
        operator => "ADD",
        operand  => $campaign
      });
    push @campaign_operations, $campaign_operation;
  }
  return @campaign_operations;
}

# Create CampaignCriterionOperations.
sub _create_campaign_criterion_operations() {
  my (@campaign_operations) = @_;

  my @campaign_criterion_operations = ();

  for my $campaign_operation (@campaign_operations) {
    # Create keyword.
    my $keyword = Google::Ads::AdWords::v201708::Keyword->new(
      {matchType => "BROAD", text => "venus"});

    my $negative_criterion =
      Google::Ads::AdWords::v201708::NegativeCampaignCriterion->new({
        campaignId => $campaign_operation->get_operand()->get_id(),
        criterion  => $keyword
      });

    # Create operation.
    my $negative_criterion_operation =
      Google::Ads::AdWords::v201708::CampaignCriterionOperation->new({
        operator => "ADD",
        operand  => $negative_criterion
      });

    push @campaign_criterion_operations, $negative_criterion_operation;
  }
  return @campaign_criterion_operations;
}

# Create AdGroupOperations to add AdGroups.
sub _create_ad_group_operations {
  my (@campaign_operations) = @_;

  my @ad_group_operations = ();
  for my $campaign_operation (@campaign_operations) {
    for (my $i = 1 ; $i < NUMBER_OF_ADGROUPS_TO_ADD ; $i++) {
      my $ad_group = Google::Ads::AdWords::v201708::AdGroup->new({
          id         => _next_id(),
          campaignId => $campaign_operation->get_operand()->get_id(),
          name       => "Batch Ad Group #" . uniqid(),
          biddingStrategyConfiguration =>
            Google::Ads::AdWords::v201708::BiddingStrategyConfiguration->new({
              bids => [
                Google::Ads::AdWords::v201708::CpcBid->new({
                    bid => Google::Ads::AdWords::v201708::Money->new(
                      {microAmount => 10000000})})]})});
      my $ad_group_operation =
        Google::Ads::AdWords::v201708::AdGroupOperation->new({
          operator => "ADD",
          operand  => $ad_group
        });
      push @ad_group_operations, $ad_group_operation;
    }
  }
  return @ad_group_operations;
}

# Create AdGroupCriterionOperations.
sub _create_ad_group_criterion_operations {
  my (@ad_group_operations) = @_;

  my @ad_group_criterion_operations = ();

  for my $ad_group_operation (@ad_group_operations) {
    for (my $i = 1 ; $i < NUMBER_OF_KEYWORDS_TO_ADD ; $i++) {
      # Create keyword.
      my $keyword = Google::Ads::AdWords::v201708::Keyword->new({
          matchType => "BROAD",
          # Make 50% of keywords invalid to demonstrate error handling.
          text => sprintf("mars%d%s", $i, (($i % 2 == 0) ? "!!!" : ""))});

      # Create biddable ad group criterion.
      my $ad_group_criterion =
        Google::Ads::AdWords::v201708::BiddableAdGroupCriterion->new({
          adGroupId => $ad_group_operation->get_operand()->get_id(),
          criterion => $keyword
        });

      # Create operation.
      my $ad_group_criterion_operation =
        Google::Ads::AdWords::v201708::AdGroupCriterionOperation->new({
          operator => "ADD",
          operand  => $ad_group_criterion
        });
      push @ad_group_criterion_operations, $ad_group_criterion_operation;
    }
  }
  return @ad_group_criterion_operations;
}

# Create AdGroupAdOperations.
sub _create_ad_group_ad_operations() {
  my (@ad_group_operations) = @_;

  my @ad_group_ad_operations = ();
  for my $ad_group_operation (@ad_group_operations) {
    my $ad_group_id = $ad_group_operation->get_operand()->get_id();

    my $text_ad = Google::Ads::AdWords::v201708::ExpandedTextAd->new({
        headlinePart1 => "Cruise to Mars",
        headlinePart2 => "Visit the Red Planet in style.",
        description   => "Low-gravity for everyone!",
        finalUrls     => ["http://www.example.com/1"]});

    # Create ad group ad for the text ad.
    my $text_ad_group_ad = Google::Ads::AdWords::v201708::AdGroupAd->new({
      adGroupId => $ad_group_id,
      ad        => $text_ad,
      # Additional properties (non-required).
      status => "PAUSED"
    });

    # Create operation.
    my $text_ad_group_ad_operation =
      Google::Ads::AdWords::v201708::AdGroupAdOperation->new({
        operator => "ADD",
        operand  => $text_ad_group_ad
      });

    push @ad_group_ad_operations, $text_ad_group_ad_operation;
  }
  return @ad_group_ad_operations;
}

# Return the next available temporary ID.
sub _next_id() {
  return $temporary_id--;
}

# Poll for completion of the batch job using an exponential back off
# waiting until the progress of the job is DONE or CANCELED.
# This returns a hash of return values:
#   error => undef if no error and BatchJobHandlerError if an error occurred
#   batch_job => the batch job with the id, status, progressStats,
#                processingErrors, and downloadUrl
#   result => BatchJobOpsService::mutateResponse object with contents from the
#             job's download URL
sub _verify_operations {
  my ($client, $batch_job_handler, $batch_job) = @_;

  my $job_id = sprintf("%d", $batch_job->get_id());
  my $predicate = Google::Ads::AdWords::v201708::Predicate->new({
      field    => "Id",
      operator => "IN",
      values   => [$job_id]});
  my $paging = Google::Ads::AdWords::v201708::Paging->new({
    startIndex    => 0,
    numberResults => 1
  });
  my $selector = Google::Ads::AdWords::v201708::Selector->new({
    fields =>
      ["Id", "Status", "ProgressStats", "ProcessingErrors", "DownloadUrl"],
    predicates => [$predicate],
    paging     => $paging
  });

  # Loop while waiting for the job to complete.
  my $job;
  my $poll_attempts = 0;
  my $end_time      = time + JOB_TIMEOUT_IN_MILLISECONDS;
  do {
    my $batch_job_page = $client->BatchJobService->get({selector => $selector});
    $job = $batch_job_page->get_entries()->[0];

    printf("Job with ID %d has a status of: %s.\n",
      $job->get_id(), $job->get_status());

    my $waittime_in_milliseconds =
      JOB_BASE_WAITTIME_IN_MILLISECONDS * (2**$poll_attempts);
    if (
      (time + $waittime_in_milliseconds) < $end_time
      and ($job->get_status() eq "ACTIVE"
        or $job->get_status() eq "AWAITING_FILE"))
    {
      printf("Sleeping %d milliseconds...\n", $waittime_in_milliseconds);
      sleep($waittime_in_milliseconds / 1000);    # Convert to seconds.
      $poll_attempts++;
    } else {
      # If there isn't enough time to sleep and do another loop, then get out
      # of the loop.
      $end_time = time;
    }
    } while (
    time < $end_time
    and !(
         $job->get_status() eq "DONE"
      or $job->get_status() eq "CANCELED"
    ));

  # If the tiemout was exceeded, then return an error.
  my $error;
  if (!($job->get_status() eq "DONE" or $job->get_status() eq "CANCELED")) {
    $error = Google::Ads::AdWords::Utilities::BatchJobHandlerError->new({
        type        => "UPLOAD",
        description => sprintf(
          "Job with ID %d did not complete" .
            "within a timeout of %d milliseconds.",
          $job->get_id(), JOB_TIMEOUT_IN_MILLISECONDS
        )});
  }

  # Check for processing errors.
  if ($job->get_processingErrors()) {
    $error = Google::Ads::AdWords::Utilities::BatchJobHandlerError->new({
        type => "PROCESSING",
        description =>
          sprintf("Job ID %d had processing errors.", $job->get_id()),
        processing_errors => $job->get_processingErrors()});
  }

  my $download_url = $job->get_downloadUrl()->get_url();
  printf("Batch job with ID %d.\n\tDownload URL: '%s'\n",
    $job->get_id(), $download_url);
  my $download_url_result =
    $batch_job_handler->download_response($download_url);
  if (!$download_url_result) {
    $error               = $download_url_result;
    $download_url_result = undef;
  }
  return {
    error     => $error,
    batch_job => $job,
    result    => $download_url_result
  };
}

# 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 => "v201708"});

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

# Call the example
add_complete_campaign_using_batch_job($client);

Add a draft

#!/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 illustrates how to create a draft and access its associated
# draft campaign.
#
# See the Campaign Drafts and Experiments guide for more information:
# https://developers.google.com/adwords/api/docs/guides/campaign-drafts-experiments

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201708::CampaignCriterion;
use Google::Ads::AdWords::v201708::CampaignCriterionOperation;
use Google::Ads::AdWords::v201708::Draft;
use Google::Ads::AdWords::v201708::DraftOperation;
use Google::Ads::AdWords::v201708::Language;

use Cwd qw(abs_path);
use Data::Uniqid qw(uniqid);

# Replace with a valid value from your account.
my $base_campaign_id = "INSERT_BASE_CAMPAIGN_ID_HERE";

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

  my $draft = Google::Ads::AdWords::v201708::Draft->new({
      baseCampaignId => $base_campaign_id,
      draftName      => sprintf("Test Draft #%s", uniqid())});

  # Create operation.
  my $draft_operation = Google::Ads::AdWords::v201708::DraftOperation->new({
      operator => "ADD",
      operand  => $draft
  });

  # Add draft.
  my $result =
    $client->DraftService()->mutate({operations => [$draft_operation]});

  if ($result) {
    $draft = $result->get_value()->[0];
    my $draft_id          = $draft->get_draftId();
    my $draft_campaign_id = $draft->get_draftCampaignId();

    printf(
      "Draft with ID %d and base campaign ID %d" .
        " and draft campaign ID %d created.\n",
      $draft_id, $draft->get_baseCampaignId(),
      $draft_campaign_id
    );

    # Once the draft is created, you can modify the draft campaign as if it
    # were a real campaign. For example, you may add criteria, adjust bids,
    # or even include additional ads. Adding a criterion is shown here.
    my $criterion = Google::Ads::AdWords::v201708::Language->new({
        id => 1003    # Spanish
    });

    my $operation =
      Google::Ads::AdWords::v201708::CampaignCriterionOperation->new({
        operator => "ADD",
        operand  => Google::Ads::AdWords::v201708::CampaignCriterion->new({
            campaignId => $draft_campaign_id,
            criterion  => $criterion
          })});

    $result =
      $client->CampaignCriterionService()->mutate({operations => [$operation]});

    $criterion = $result->get_value()->[0];

    printf("Draft updated to include criteria in campaign %d.\n",
      $criterion->get_campaignId());
  }

  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 => "v201708"});

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

# Call the example
add_draft($client, $base_campaign_id);

Add keywords using an incremental batch job

#!/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 illustrates how to perform multiple requests using the
# BatchJobService using incremental uploads.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201708::AdGroupCriterion;
use Google::Ads::AdWords::v201708::AdGroupCriterionOperation;
use Google::Ads::AdWords::v201708::BatchJob;
use Google::Ads::AdWords::v201708::BatchJobOperation;
use Google::Ads::AdWords::v201708::BiddableAdGroupCriterion;
use Google::Ads::AdWords::v201708::Keyword;
use Google::Ads::AdWords::Utilities::BatchJobHandler;
use Google::Ads::AdWords::Utilities::BatchJobHandlerError;
use Google::Ads::AdWords::Utilities::BatchJobHandlerStatus;

use Cwd qw(abs_path);

use constant KEYWORD_COUNT => 100;
# Set a timeout to fail if the job does not complete in a specified amount
# of time.
use constant JOB_TIMEOUT_IN_MILLISECONDS => 600000;
# The time to sleep in between polls will start at this time. Then an
# exponential back-off will be instituted.
use constant JOB_BASE_WAITTIME_IN_MILLISECONDS => 30000;

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

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

  # Create a batch job, which returns an upload URL to upload the batch
  # operations and a job ID to track the job.
  my $operation = Google::Ads::AdWords::v201708::BatchJobOperation->new({
      operator => 'ADD',
      operand  => Google::Ads::AdWords::v201708::BatchJob->new({})});

  my $batch_job_result =
    $client->BatchJobService()->mutate({operations => [$operation]});

  if (!$batch_job_result->get_value()) {
    print "A batch job could not be created. No operations were uploaded.\n";
    return 1;
  }

  my $batch_job = $batch_job_result->get_value()->[0];

  printf("Batch job with ID %d was created.\n\tInitial upload URL: '%s'\n",
    $batch_job->get_id(), $batch_job->get_uploadUrl()->get_url());

  # Get an instance of a utility that helps with uploading batch operations.
  my $batch_job_handler =
    Google::Ads::AdWords::Utilities::BatchJobHandler->new({client => $client});

  #
  # Upload the keywords in three batches to the upload URL.
  # The process that adds the keywords to the ad group will not start
  # executing until the last request has been sent.
  #

  # Upload #1: This is the first upload.
  my @operations = _create_keyword_operations($ad_group_id);

  # Create an initial batch job status.
  # Convert the list of operations into XML.
  # POST the XML to the upload URL.
  my $batch_job_status =
    Google::Ads::AdWords::Utilities::BatchJobHandlerStatus->new({
      total_content_length => 0,
      resumable_upload_uri => $batch_job->get_uploadUrl()->get_url()});
  $batch_job_status =
    $batch_job_handler->upload_incremental_operations(\@operations,
    $batch_job_status);
  if (!_check_status($batch_job_status)) {
    return 1;
  }

  printf("\tResumable upload URL: '%s'\n",
    $batch_job_status->get_resumable_upload_uri());

  # Upload #2: Make sure to pass in the status returned in the last call
  # into 'upload_incremental_operations'.
  @operations = _create_keyword_operations($ad_group_id);

  # Convert the list of operations into XML.
  # POST the XML to the upload URL.
  $batch_job_status =
    $batch_job_handler->upload_incremental_operations(\@operations,
    $batch_job_status);
  if (!_check_status($batch_job_status)) {
    return 1;
  }

  # Upload #3: Make sure to pass in the status returned in the last request
  # and a true value for $is_last_request indicating that the uploads have
  # finished into 'upload_incremental_operations'.
  @operations = _create_keyword_operations($ad_group_id);

  # Convert the list of operations into XML.
  # POST the XML to the upload URL.
  $batch_job_status =
    $batch_job_handler->upload_incremental_operations(\@operations,
    $batch_job_status, 1);
  if (!_check_status($batch_job_status)) {
    return 1;
  }

  # Verify that the operations completed.
  # This will poll until the job has completed or the timeout has expired.
  my $verify_result =
    _verify_operations($client, $batch_job_handler, $batch_job);

  # Display the results.
  my $error             = $verify_result->{error};
  my $job_result        = $verify_result->{batch_job};
  my $operations_result = $verify_result->{result};

  printf("Job with ID %d has completed with a status of '%s'.\n",
    $job_result->get_id(), $job_result->get_status());
  if (defined $error) {
    printf("%s Error. %s\n", $error->get_type(), $error->get_description());
    if ($error->get_type() eq "PROCESSING") {
      printf("%s\n", $error->get_processing_errors());
    }
    if ($error->get_type() eq "HTTP") {
      printf(
        "Type: %s\nCode: %s\nMessage: %s\nTrigger: %s\nField Path: %s\n",
        $error->get_http_type(),             $error->get_http_response_code(),
        $error->get_http_response_message(), $error->get_http_trigger(),
        $error->get_http_field_path());
    }
  }
  if ($operations_result and $operations_result->get_rval()) {
    for my $item (@{$operations_result->get_rval()}) {
      if ($item->get_errorList()) {
        printf("Error on index %d: %s\n",
          $item->get_index(), $item->get_errorList()->get_errors());
      } else {
        # Print the XML output.
        printf("Successful on index %d\n%s\n",
          $item->get_index(),
          $item->get_result()->get_AdGroupCriterion()->get_criterion()
            ->get_text());
      }
    }
  }

  return 1;
}

# Create AdGroupCriterion to add keywords.
sub _create_keyword_operations {
  my ($ad_group_id) = @_;

  my @operations = ();

  for (my $i = 1 ; $i < KEYWORD_COUNT ; $i++) {
    # Create keyword.
    my $keyword =
      Google::Ads::AdWords::v201708::Keyword->new({matchType => "BROAD"});
    # Randomly add invalid characters to keyword.
    if (int(rand(10)) == 0) {
      $keyword->set_text(sprintf("keyword %d!!!", $i));
    } else {
      $keyword->set_text(sprintf("keyword %d", $i));
    }

    # Create biddable ad group criterion.
    my $ad_group_criterion =
      Google::Ads::AdWords::v201708::BiddableAdGroupCriterion->new({
        adGroupId => $ad_group_id,
        criterion => $keyword
      });

    # Create operation.
    my $ad_group_criterion_operation =
      Google::Ads::AdWords::v201708::AdGroupCriterionOperation->new({
        operator => "ADD",
        operand  => $ad_group_criterion
      });

    push(@operations, $ad_group_criterion_operation);
  }
  return @operations;
}

# Check the status of uploading incremental operations. Print details if an
# error is found.
sub _check_status {
  my ($batch_job_status) = @_;
  if (!$batch_job_status) {
    # If not given a status back, then this object is an error.
    my $error = $batch_job_status;
    printf("%s Error. %s\n", $error->get_type(), $error->get_description());
    if ($error->get_type() eq "HTTP") {
      printf(
        "Type: %s\nCode: %s\nMessage: %s\nTrigger: %s\nField Path: %s\n",
        $error->get_http_type(),             $error->get_http_response_code(),
        $error->get_http_response_message(), $error->get_http_trigger(),
        $error->get_http_field_path());
    }
  }
  return $batch_job_status;
}

# Poll for completion of the batch job using an exponential back off
# waiting until the progress of the job is DONE or CANCELED.
# If the job does not finish in the alloted time, attempt to cancel it once.
# This returns a hash of return values:
#   error => undef if no error and BatchJobHandlerError if an error occurred
#   batch_job => the batch job with the id, status, progressStats,
#                processingErrors, and downloadUrl
#   result => BatchJobOpsService::mutateResponse object with contents from the
#             job's download URL
sub _verify_operations {
  my ($client, $batch_job_handler, $batch_job) = @_;

  my $job_id = sprintf("%d", $batch_job->get_id());
  my $predicate = Google::Ads::AdWords::v201708::Predicate->new({
      field    => "Id",
      operator => "IN",
      values   => [$job_id]});
  my $paging = Google::Ads::AdWords::v201708::Paging->new({
      startIndex    => 0,
      numberResults => 1
  });
  my $selector = Google::Ads::AdWords::v201708::Selector->new({
      fields =>
        ["Id", "Status", "ProgressStats", "ProcessingErrors", "DownloadUrl"],
      predicates => [$predicate],
      paging     => $paging
  });

  # Loop while waiting for the job to complete.
  my $job;
  my $poll_attempts        = 0;
  my $end_time             = time + JOB_TIMEOUT_IN_MILLISECONDS;
  my $was_cancel_requested = 0;
  do {
    my $batch_job_page = $client->BatchJobService->get({selector => $selector});
    $job = $batch_job_page->get_entries()->[0];

    printf("Job with ID %d has a status of: %s.\n",
      $job->get_id(), $job->get_status());

    my $waittime_in_milliseconds =
      JOB_BASE_WAITTIME_IN_MILLISECONDS * (2**$poll_attempts);
    if (
      (time + $waittime_in_milliseconds) < $end_time
      and ($job->get_status() eq "ACTIVE"
        or $job->get_status() eq "AWAITING_FILE"
        or $job->get_status() eq "CANCELING")
      )
    {
      printf("Sleeping %d milliseconds...\n", $waittime_in_milliseconds);
      sleep($waittime_in_milliseconds / 1000);    # Convert to seconds.
      $poll_attempts++;
    } else {
      # Optional:
      # If there isn't enough time to sleep and do another loop, then cancel.
      # If a cancel was already unsuccessful, get out of the loop.
      $end_time = time;
      if ( !($job->get_status() eq "DONE" or $job->get_status() eq "CANCELED")
        && !$was_cancel_requested)
      {
        $was_cancel_requested = 1;
        $job->set_status("CANCELING");
        my $operation = Google::Ads::AdWords::v201708::BatchJobOperation->new({
            operator => 'SET',
            operand  => $job
        });
        my $job_result =
          $client->BatchJobService()->mutate({operations => [$operation]});
        if (!$job_result->get_value()) {
          sprint("Unable to cancel job with ID %d.", $job->get_id());
        } else {
          $job = $job_result->get_value()->[0];
          # Reset the timer to give the job time to cancel.
          $poll_attempts = 0;
          $end_time      = time + JOB_TIMEOUT_IN_MILLISECONDS;
          printf("Job with ID %d did not complete within a timeout of %d " .
              "milliseconds. Requested cancellation of batch job.\n",
            $job->get_id(), JOB_TIMEOUT_IN_MILLISECONDS);
        }
      }
    }
    } while (
    time < $end_time
    and !(
         $job->get_status() eq "DONE"
      or $job->get_status() eq "CANCELED"
    ));

  # If the timeout was exceeded, then return an error.
  my $error;
  if (!($job->get_status() eq "DONE" or $job->get_status() eq "CANCELED")) {
    $error = Google::Ads::AdWords::Utilities::BatchJobHandlerError->new({
        type        => "UPLOAD",
        description => sprintf(
          "Job with ID %d did not complete" .
            "within a timeout of %d milliseconds.",
          $job->get_id(), JOB_TIMEOUT_IN_MILLISECONDS
        )});
  }

  # Check for processing errors.
  if ($job->get_processingErrors()) {
    $error = Google::Ads::AdWords::Utilities::BatchJobHandlerError->new({
        type => "PROCESSING",
        description =>
          sprintf("Job ID %d had processing errors.", $job->get_id()),
        processing_errors => $job->get_processingErrors()});
  }

  my $download_url_result;
  if ($job->get_downloadUrl()) {
    my $download_url = $job->get_downloadUrl()->get_url();
    printf("Batch job with ID %d.\n\tDownload URL: '%s'\n",
      $job->get_id(), $download_url);
    $download_url_result = $batch_job_handler->download_response($download_url);
    if (!$download_url_result) {
      $error               = $download_url_result;
      $download_url_result = undef;
    }
  }
  return {
    error     => $error,
    batch_job => $job,
    result    => $download_url_result
  };
}

# 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 => "v201708"});

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

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

Add a trial

#!/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 illustrates how to create a trial and wait for it to complete.
#
# See the Campaign Drafts and Experiments guide for more information:
# https://developers.google.com/adwords/api/docs/guides/campaign-drafts-experiments

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201708::Predicate;
use Google::Ads::AdWords::v201708::Selector;
use Google::Ads::AdWords::v201708::Trial;
use Google::Ads::AdWords::v201708::TrialOperation;

use Cwd qw(abs_path);
use Data::Uniqid qw(uniqid);

# Replace with valid values of your account.
my $base_campaign_id = "INSERT_BASE_CAMPAIGN_ID_HERE";
my $draft_id         = "INSERT_DRAFT_ID_HERE";

# Set a timeout to fail if the trial is not created in a specified amount
# of time.
use constant JOB_TIMEOUT_IN_MILLISECONDS => 180000;
# The time to sleep in between polls 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 add_trial {
  my ($client, $base_campaign_id, $draft_id) = @_;

  my $trial = Google::Ads::AdWords::v201708::Trial->new({
      draftId             => $draft_id,
      baseCampaignId      => $base_campaign_id,
      name                => sprintf("Test Trial #%s", uniqid()),
      trafficSplitPercent => 50,
  });

  # Create operation.
  my $trial_operation = Google::Ads::AdWords::v201708::TrialOperation->new({
      operator => "ADD",
      operand  => $trial
  });

  # Add trial.
  my $result =
    $client->TrialService()->mutate({operations => [$trial_operation]});

  if ($result) {
    my $trial_id = $result->get_value()->[0]->get_id()->get_value();

    my $predicate = Google::Ads::AdWords::v201708::Predicate->new({
        field    => "Id",
        operator => "IN",
        values   => [$trial_id]});
    my $paging = Google::Ads::AdWords::v201708::Paging->new({
        startIndex    => 0,
        numberResults => 1
    });
    my $selector = Google::Ads::AdWords::v201708::Selector->new({
        fields => ["Id", "Status", "BaseCampaignId", "TrialCampaignId"],
        predicates => [$predicate],
        paging     => $paging
    });

    # Since creating a trial is asynchronous, we have to poll it to wait for
    # it to finish.
    my $poll_attempts = 0;
    my $is_pending    = 1;
    my $end_time      = time + JOB_TIMEOUT_IN_MILLISECONDS;
    do {
      # Check to see if the trial is still in the process of being created.
      my $result = $client->TrialService()->get({selector => $selector});
      $trial = $result->get_entries()->[0];
      my $waittime_in_milliseconds =
        JOB_BASE_WAITTIME_IN_MILLISECONDS * (2**$poll_attempts);
      if (((time + $waittime_in_milliseconds) < $end_time)
        and $trial->get_status() eq 'CREATING')
      {
        printf("Sleeping %d milliseconds...\n", $waittime_in_milliseconds);
        sleep($waittime_in_milliseconds / 1000);    # Convert to seconds.
        $poll_attempts++;
      }
    } while (time < $end_time
      and $trial->get_status() eq 'CREATING');

    if ($trial->get_status() eq 'ACTIVE') {
      # The trial creation was successful.
      printf("Trial created with ID %d and trial campaign ID %d.\n",
        $trial->get_id(), $trial->get_trialCampaignId());
    } elsif ($trial->get_status() eq 'CREATION_FAILED') {
      # The trial creation failed, and errors can be fetched from the
      # TrialAsyncErrorService.
      my $error_selector = Google::Ads::AdWords::v201708::Selector->new({
          fields     => ["TrialId", "AsyncError"],
          predicates => [
            Google::Ads::AdWords::v201708::Predicate->new({
                field    => "TrialId",
                operator => "IN",
                values   => [$trial_id]})]});

      my $errors =
        $client->TrialAsyncErrorService->get({selector => $error_selector})
        ->get_entries();
      if (!$errors) {
        printf("Could not retrieve errors for trial %d", $trial->get_id());
      } else {
        printf("Could not create trial due to the following errors:");
        my $index = 0;
        for my $error ($errors) {
          printf("Error %d: %s", $index, $error->get_asyncError()
          ->get_errorString());
          $index++;
        }
      }
    } else {
      # Most likely, the trial is still being created. You can continue polling,
      # but we have limited the number of attempts in the example.
      printf("Timed out waiting to create trial from draft %d with base " .
          "campaign %d.\n",
        $draft_id, $base_campaign_id);
    }
  }

  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 => "v201708"});

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

# Call the example
add_trial($client, $base_campaign_id, $draft_id);

Get all disapproved ads in an ad group

#!/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 disapproved ads in an ad group. To add ads, run
# basic_operations/add_text_ads.pl. To get ad groups, run
# basic_operations/get_ad_groups.pl.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201708::OrderBy;
use Google::Ads::AdWords::v201708::Paging;
use Google::Ads::AdWords::v201708::Predicate;
use Google::Ads::AdWords::v201708::Selector;
use Google::Ads::AdWords::Utilities::PageProcessor;

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

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

  # Create predicates (Filters).
  my $ad_group_predicate = Google::Ads::AdWords::v201708::Predicate->new({
      field    => "AdGroupId",
      operator => "IN",
      values   => [$ad_group_id]});

  my $disapproved_predicate = Google::Ads::AdWords::v201708::Predicate->new({
      field    => "CombinedApprovalStatus",
      operator => "EQUALS",
      values   => ["DISAPPROVED"]});

  # Create selector.
  my $paging = Google::Ads::AdWords::v201708::Paging->new({
    startIndex    => 0,
    numberResults => PAGE_SIZE
  });
  my $selector = Google::Ads::AdWords::v201708::Selector->new({
      fields     => ["Id", "PolicySummary"],
      predicates => [$ad_group_predicate, $disapproved_predicate],
      ordering   => [
        Google::Ads::AdWords::v201708::OrderBy->new({
            field     => "Id",
            sortOrder => "ASCENDING"
          })
      ],
      paging => $paging
    });

  # Paginate through results.
  # The contents of the subroutine will be executed for each ad.
  my $disapproved_ad_count = 0;
  Google::Ads::AdWords::Utilities::PageProcessor->new({
      client   => $client,
      service  => $client->AdGroupAdService(),
      selector => $selector
    }
    )->process_entries(
    sub {
      my ($ad_group_ad) = @_;
      $disapproved_ad_count++;
      my $policy_summary = $ad_group_ad->get_policySummary();
      printf "Ad with ID %d and type '%s' was disapproved with the " .
        "following policy topic entries:\n", $ad_group_ad->get_ad()->get_id(),
        $ad_group_ad->get_ad()->get_Ad__Type();
      foreach
        my $policy_topic_entry (@{$policy_summary->get_policyTopicEntries()})
      {
        printf "  topic id: %s, topic name: '%s'\n",
          $policy_topic_entry->get_policyTopicId(),
          $policy_topic_entry->get_policyTopicName();
      }
    });

  if ($disapproved_ad_count == 0) {
    print("No disapproved ads 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 => "v201708"});

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

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

Get all disapproved ads in an ad group using 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 example gets all disapproved ads in an ad group using AWQL.
# To add ads, run basic_operations/add_text_ads.pl. To get ad groups, run
# basic_operations/get_ad_groups.pl.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201708::OrderBy;
use Google::Ads::AdWords::v201708::Paging;
use Google::Ads::AdWords::v201708::Predicate;
use Google::Ads::AdWords::v201708::Selector;
use Google::Ads::AdWords::Utilities::PageProcessor;

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

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

  # Get all the disapproved ads for the given ad group.
  my $query =
    "SELECT Id, PolicySummary WHERE AdGroupId = ${ad_group_id} AND " .
    "CombinedApprovalStatus = DISAPPROVED ORDER BY Id";

  # Paginate through results.
  # The contents of the subroutine will be executed for each disapproved ad.
  my $disapproved_ad_count = 0;
  Google::Ads::AdWords::Utilities::PageProcessor->new({
      client    => $client,
      service   => $client->AdGroupAdService(),
      query     => $query,
      page_size => PAGE_SIZE
    }
    )->process_entries(
    sub {
      my ($ad_group_ad) = @_;
      $disapproved_ad_count++;
      my $policy_summary = $ad_group_ad->get_policySummary();
      printf "Ad with ID %d and type '%s' was disapproved with the " .
        "following policy topic entries:\n", $ad_group_ad->get_ad()->get_id(),
        $ad_group_ad->get_ad()->get_Ad__Type();
      foreach
        my $policy_topic_entry (@{$policy_summary->get_policyTopicEntries()})
      {
        printf "  topic id: %s, topic name: '%s'\n",
          $policy_topic_entry->get_policyTopicId(),
          $policy_topic_entry->get_policyTopicName();
      }
    });

  if ($disapproved_ad_count == 0) {
    print("No disapproved ads 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 => "v201708"});

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

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

Get all campaigns with a specific label

#!/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 campaigns with a specific label. To add a label to
# campaigns, run add_campaign_labels.pl.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201708::OrderBy;
use Google::Ads::AdWords::v201708::Paging;
use Google::Ads::AdWords::v201708::Predicate;
use Google::Ads::AdWords::v201708::Selector;
use Google::Ads::AdWords::Utilities::PageProcessor;

use constant PAGE_SIZE => 500;

use Cwd qw(abs_path);

# Replace with valid values of your account.
my $label_id = "INSERT_LABEL_ID_HERE";

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

  # Create predicate.
  # Labels filtering is performed by ID. You can use CONTAINS_ANY to select
  # campaigns with any of the label IDs, CONTAINS_ALL to select campaigns with
  # all of the label IDs, or CONTAINS_NONE to select campaigns with none of the
  # label IDs.
  my $labels_predicate = Google::Ads::AdWords::v201708::Predicate->new({
      field    => "Labels",
      operator => "CONTAINS_ANY",
      values   => [$label_id]});
  # Create selector.
  my $paging = Google::Ads::AdWords::v201708::Paging->new({
      startIndex    => 0,
      numberResults => PAGE_SIZE
  });
  my $selector = Google::Ads::AdWords::v201708::Selector->new({
      fields     => ["Id", "Name", "Labels"],
      predicates => [$labels_predicate],
      ordering   => [
        Google::Ads::AdWords::v201708::OrderBy->new({
            field     => "Name",
            sortOrder => "ASCENDING"
          })
      ],
      paging => $paging
    });

  # Paginate through results.
  # The contents of the subroutine will be executed for each campaign.
  Google::Ads::AdWords::Utilities::PageProcessor->new({
      client   => $client,
      service  => $client->CampaignService(),
      selector => $selector
    }
    )->process_entries(
    sub {
      my ($campaign) = @_;
      my @label_strings =
        map { $_->get_id() . '/' . $_->get_name() } @{$campaign->get_labels()};
      printf "Campaign found with name \"%s\" and ID %d and labels: %s.\n",
        $campaign->get_name(), $campaign->get_id(),
        join(', ', @label_strings);
    });

  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 => "v201708"});

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

# Call the example
get_campaigns_by_label($client, $label_id);

Graduate a trial

#!/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 illustrates how to graduate a trial.
#
# See the Campaign Drafts and Experiments guide for more information:
# https://developers.google.com/adwords/api/docs/guides/campaign-drafts-experiments

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201708::Budget;
use Google::Ads::AdWords::v201708::BudgetOperation;
use Google::Ads::AdWords::v201708::Trial;
use Google::Ads::AdWords::v201708::TrialOperation;

use Cwd qw(abs_path);
use Data::Uniqid qw(uniqid);

# Replace with a valid value from your account.
my $trial_id = "INSERT_TRIAL_ID_HERE";

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

  # To graduate a trial, you must specify a different budget from the base
  # campaign. The base campaign (in order to have had a trial based on it)
  # must have a non-shared budget, so it cannot be shared with the new
  # independent campaign created by graduation.
  my $budget = Google::Ads::AdWords::v201708::Budget->new({
      name => sprintf("Budget #%s", uniqid()),
      amount =>
        Google::Ads::AdWords::v201708::Money->new({microAmount => 5000000}),
      deliveryMethod => "STANDARD"
  });

  my $budget_operation = Google::Ads::AdWords::v201708::BudgetOperation->new({
      operator => "ADD",
      operand  => $budget
  });

  # Add budget.
  my $budget_id =
    $client->BudgetService()->mutate({operations => ($budget_operation)})
    ->get_value()->get_budgetId()->get_value();

  my $trial = Google::Ads::AdWords::v201708::Trial->new({
      id       => $trial_id,
      budgetId => $budget_id,
      status   => "GRADUATED"
  });

  # Create operation.
  my $trial_operation = Google::Ads::AdWords::v201708::TrialOperation->new({
      operator => "SET",
      operand  => $trial
  });

  # Graduate trial.
  my $result =
    $client->TrialService()->mutate({operations => [$trial_operation]});

  # Update the trial.
  $trial = $result->get_value()->[0];

  # Graduation is a synchronous operation, so the campaign is already ready.
  # If you promote instead, make sure to see the polling scheme demonstrated
  # in add_trial.pl to wait for the asynchronous operation to finish.
  printf("Trial ID %d graduated. Campaign %d was given a new budget ID %d " .
      "and is no longer dependent on this trial.\n",
    $trial->get_id(), $trial->get_trialCampaignId(), $budget_id);

  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 => "v201708"});

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

# Call the example
graduate_trial($client, $trial_id);

Set ad parameters

#!/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 sets ad parameters for a keyword in an ad group. 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::v201708::AdParam;
use Google::Ads::AdWords::v201708::AdParamOperation;

use Cwd qw(abs_path);

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

# Example main subroutine.
sub set_ad_parameters {
  my $client      = shift;
  my $ad_group_id = shift;
  my $keyword_id  = shift;

  # Create ad parameters.
  my $ad_param1 = Google::Ads::AdWords::v201708::AdParam->new({
      adGroupId     => $ad_group_id,
      criterionId   => $keyword_id,
      insertionText => "100",
      paramIndex    => "1",
  });

  my $ad_param2 = Google::Ads::AdWords::v201708::AdParam->new({
      adGroupId     => $ad_group_id,
      criterionId   => $keyword_id,
      insertionText => "\$40",
      paramIndex    => "2",
  });

  # Create operations.
  my $ad_param_operation1 =
    Google::Ads::AdWords::v201708::AdParamOperation->new({
      operator => "SET",
      operand  => $ad_param1
    });

  my $ad_param_operation2 =
    Google::Ads::AdWords::v201708::AdParamOperation->new({
      operator => "SET",
      operand  => $ad_param2
    });

  # Set ad parameters.
  my $ad_params =
    $client->AdParamService()
    ->mutate({operations => [$ad_param_operation1, $ad_param_operation2]});

  # Display ad parameters.
  if ($ad_params) {
    foreach my $ad_param (@{$ad_params}) {
      printf "Ad parameter with ad group id \"%d\", criterion id \"%d\", " .
        "insertion text \"%s\", and parameter index \"%d\" was set.\n",
        $ad_param->get_adGroupId(),     $ad_param->get_criterionId(),
        $ad_param->get_insertionText(), $ad_param->get_paramIndex();
    }
  } else {
    print "No ad parameters were set.\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 => "v201708"});

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

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

Set bid modifier

#!/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 sets a bid modifier for the mobile platform on 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::v201708::CampaignCriterionOperation;
use Google::Ads::AdWords::v201708::Platform;

use Cwd qw(abs_path);

use constant BID_MODIFIER => 1.5;

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

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

  # Create mobile platform. The ID can be found in the documentation.
  # https://developers.google.com/adwords/api/docs/appendix/platforms
  my $mobile = Google::Ads::AdWords::v201708::Platform->new({id => 30001});

  # Create criterion with modified bid.
  my $criterion = Google::Ads::AdWords::v201708::CampaignCriterion->new({
      campaignId  => $campaign_id,
      criterion   => $mobile,
      bidModifier => BID_MODIFIER
  });

  # Create SET operation.
  my $operation =
    Google::Ads::AdWords::v201708::CampaignCriterionOperation->new({
      operator => "SET",
      operand  => $criterion
    });

  # Update campaign criteria.
  my $result =
    $client->CampaignCriterionService()->mutate({operations => [$operation]});

  # Display campaign criteria.
  if ($result->get_value()) {
    foreach my $campaign_criterion (@{$result->get_value()}) {
      printf "Campaign criterion with campaign id '%s', criterion id '%s', " .
        "and type '%s' was modified with bid %.2f.\n",
        $campaign_criterion->get_campaignId(),
        $campaign_criterion->get_criterion()->get_id(),
        $campaign_criterion->get_criterion()->get_type(),
        $campaign_criterion->get_bidModifier();
    }
  } else {
    print "No campaign criteria were modified.\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 => "v201708"});

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

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

Validate text ad

#!/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 shows how to use the validate only header to check for errors.
# No objects will be created, but exceptions will still be returned.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201708::AdGroupAd;
use Google::Ads::AdWords::v201708::AdGroupAdOperation;
use Google::Ads::AdWords::v201708::ExpandedTextAd;

use Cwd qw(abs_path);

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

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

  # Don't die on fault it will be handled in code.
  $client->set_die_on_faults(0);

  # Set validate only.
  $client->set_validate_only(1);

  # Create invalid expanded text ad
  my $text_ad = Google::Ads::AdWords::v201708::ExpandedTextAd->new({
      headlinePart1 => "Luxury Cruise to Mars",
      headlinePart2 => "Visit the Red Planet in style.",
      description   => "Low-gravity fun for all astronauts in orbit.",
      finalUrls     => ["http://www.example.com"]});
  my $text_ad_group_ad = Google::Ads::AdWords::v201708::AdGroupAd->new({
    adGroupId => $ad_group_id,
    ad        => $text_ad
  });

  # Create operations.
  my $operation = Google::Ads::AdWords::v201708::AdGroupAdOperation->new({
    operand  => $text_ad_group_ad,
    operator => "ADD"
  });

  # Validate text ad operation.
  my $result =
    $client->AdGroupAdService()->mutate({operations => [$operation]});
  if (defined($result) and $result->isa("SOAP::WSDL::SOAP::Typelib::Fault11")) {
    printf "Validation failed for reason: %s\n", $result->get_faultstring();
  } else {
    print "The ad is valid!\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 => "v201708"});

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

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

Send feedback about...

AdWords API
AdWords API
Need help? Visit our support page.