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

Advanced Operations Samples

The code samples below provide examples of common advanced operations using the AdWords API. Client Library.

Add an ad customizer feed

#!/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 an ad customizer feed, and then adds an ad in two different
# ad groups that uses the feed to populate dynamic data.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201809::AdCustomizerFeed;
use Google::Ads::AdWords::v201809::AdCustomizerFeedAttribute;
use Google::Ads::AdWords::v201809::AdCustomizerFeedOperation;
use Google::Ads::AdWords::v201809::AdGroupAd;
use Google::Ads::AdWords::v201809::AdGroupAdOperation;
use Google::Ads::AdWords::v201809::ConstantOperand;
use Google::Ads::AdWords::v201809::ExpandedTextAd;
use Google::Ads::AdWords::v201809::Feed;
use Google::Ads::AdWords::v201809::FeedAttribute;
use Google::Ads::AdWords::v201809::FeedItem;
use Google::Ads::AdWords::v201809::FeedItemAdGroupTarget;
use Google::Ads::AdWords::v201809::FeedItemTargetOperation;
use Google::Ads::AdWords::v201809::FeedItemAdGroupTargeting;
use Google::Ads::AdWords::v201809::FeedItemAttributeValue;
use Google::Ads::AdWords::v201809::FeedItemOperation;
use Google::Ads::AdWords::v201809::Function;
use Google::Ads::AdWords::v201809::FunctionOperand;
use Google::Ads::AdWords::v201809::RequestContextOperand;

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

# Replace with valid values of your account.
my $ad_group_ids = ["INSERT_ADGROUP_ID_HERE", "INSERT_ADGROUP_ID_HERE"];
my $feed_name = "INSERT_FEED_NAME_HERE";

# Example main subroutine.
sub add_ad_customizers {
  my ($client, $ad_group_ids, $feed_name) = @_;

  # Create a customizer feed. One feed per account can be used for all ads.
  my $ad_customizer_feed = create_customizer_feed($client, $feed_name);

  # Add feed items containing the values we'd like to place in ads.
  create_customizer_feed_items($client, $ad_customizer_feed, $ad_group_ids);

  # All set! We can now create ads with customizations.
  create_ads_with_customizations($client, $ad_group_ids, $feed_name);

  return 1;
}

sub create_customizer_feed {
  my ($client, $feed_name) = @_;

  my $name_attribute =
    Google::Ads::AdWords::v201809::AdCustomizerFeedAttribute->new({
      type => "STRING",
      name => "Name"
    });
  my $price_attribute =
    Google::Ads::AdWords::v201809::AdCustomizerFeedAttribute->new({
      type => "STRING",
      name => "Price"
    });
  my $date_attribute =
    Google::Ads::AdWords::v201809::AdCustomizerFeedAttribute->new({
      type => "DATE_TIME",
      name => "Date"
    });
  my $ad_customizer_feed = Google::Ads::AdWords::v201809::AdCustomizerFeed->new(
    {
      feedName       => $feed_name,
      feedAttributes => [$name_attribute, $price_attribute, $date_attribute]});

  my $operation = Google::Ads::AdWords::v201809::AdCustomizerFeedOperation->new(
    {
      operator => "ADD",
      operand  => $ad_customizer_feed
    });

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

  my $added_feed = $feed_result->get_value(0);

  printf(
    "Created ad customizer feed with ID %d, and name '%s' and attributes:\n",
    $added_feed->get_feedId(),
    $added_feed->get_feedName());
  foreach my $feed_attribute (@{$added_feed->get_feedAttributes()}) {
    printf "  ID: %d, name: '%s', type: '%s'\n",
      $feed_attribute->get_id(), $feed_attribute->get_name(),
      $feed_attribute->get_type();
  }

  return $added_feed;
}

sub restrict_feed_item_to_ad_group {
  my($client, $feed_item, $ad_group_id) = @_;

  # Optional: Restrict the first feed item to only serve with ads for the
  # specified ad group ID.
  my $ad_group_target =
      Google::Ads::AdWords::v201809::FeedItemAdGroupTarget->new({
          feedId     => $feed_item->get_feedId(),
          feedItemId => $feed_item->get_feedItemId(),
          adGroupId  => $ad_group_id
      });

  my $operation =
      Google::Ads::AdWords::v201809::FeedItemTargetOperation->new({
          operator => "ADD",
          operand  => $ad_group_target
      });

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

  my $new_ad_group_target = $result->get_value(0);

  printf(
      "Feed item target for feed ID %d and feed item ID %d" .
          " was created to restrict serving to ad group ID %d",
      $new_ad_group_target->get_feedId(),
      $new_ad_group_target->get_feedItemId(),
      $new_ad_group_target->get_adGroupId());
}

sub create_customizer_feed_items {
  my ($client, $ad_customizer_feed, $ad_group_ids) = @_;

  my @operations = ();

  push @operations,
    create_feed_item_add_operation($ad_customizer_feed,
    "Mars", "\$1234.56", "20140601 000000");
  push @operations,
    create_feed_item_add_operation($ad_customizer_feed,
    "Venus", "\$1450.00", "20140615 120000");

  my $result = $client->FeedItemService()->mutate({operations => \@operations});

  foreach my $feed_item (@{$result->get_value()}) {
    printf "FeedItem with feedItemId %d was added.\n",
      $feed_item->get_feedItemId();
  }

  # Add feed item targeting to restrict the feeditem to specific ad groups.
  restrict_feed_item_to_ad_group($client, $result->get_value()->[0],
      $ad_group_ids->[0]);
  restrict_feed_item_to_ad_group($client, $result->get_value()->[1],
      $ad_group_ids->[1]);
}

sub create_feed_item_add_operation {
  my ($ad_customizer_feed, $name, $price, $date) = @_;

  my $name_attribute_value =
    Google::Ads::AdWords::v201809::FeedItemAttributeValue->new({
      feedAttributeId =>
        $ad_customizer_feed->get_feedAttributes()->[0]->get_id(),
      stringValue => $name
    });
  my $price_attribute_value =
    Google::Ads::AdWords::v201809::FeedItemAttributeValue->new({
      feedAttributeId =>
        $ad_customizer_feed->get_feedAttributes()->[1]->get_id(),
      stringValue => $price
    });
  my $date_attribute_value =
    Google::Ads::AdWords::v201809::FeedItemAttributeValue->new({
      feedAttributeId =>
        $ad_customizer_feed->get_feedAttributes()->[2]->get_id(),
      stringValue => $date
    });

  my $feed_item = Google::Ads::AdWords::v201809::FeedItem->new({
      feedId => $ad_customizer_feed->get_feedId(),
      attributeValues =>
        [$name_attribute_value, $price_attribute_value, $date_attribute_value]
  });

  my $operation = Google::Ads::AdWords::v201809::FeedItemOperation->new({
    operand  => $feed_item,
    operator => "ADD"
  });

  return $operation;
}

sub create_ads_with_customizations {
  my ($client, $ad_group_ids, $feed_name) = @_;

  my $text_ad = Google::Ads::AdWords::v201809::ExpandedTextAd->new({
      headlinePart1 => sprintf("Luxury Cruise to {=%s.Name}", $feed_name),
      headlinePart2 => sprintf("Only {=%s.Price}",            $feed_name),
      description =>
        sprintf("Offer ends in {=countdown(%s.Date)}!", $feed_name),
      finalUrls => ['http://www.example.com']});

  # We add the same ad to both ad groups. When they serve, they will show
  # different values, since they match different feed items.
  my @operations = ();

  foreach my $ad_group_id (@{$ad_group_ids}) {
    push @operations,
      Google::Ads::AdWords::v201809::AdGroupAdOperation->new({
        operator => "ADD",
        operand  => Google::Ads::AdWords::v201809::AdGroupAd->new({
            adGroupId => $ad_group_id,
            ad        => $text_ad
          })});
  }

  my $result =
    $client->AdGroupAdService()->mutate({operations => \@operations});

  foreach my $ad_group_ad (@{$result->get_value()}) {
    printf "Created an ad with ID %d, type '%s', and status '%s'.\n",
      $ad_group_ad->get_ad()->get_id(), $ad_group_ad->get_ad()->get_Ad__Type(),
      $ad_group_ad->get_status();
  }
}

# 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
add_ad_customizers($client, $ad_group_ids, $feed_name);

Add an ad group level 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 adds multiple keywords to an ad group. To get ad groups run
# basic_operations/get_ad_groups.pl.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201809::AdGroupBidModifierOperation;
use Google::Ads::AdWords::v201809::AdGroupBidModifier;
use Google::Ads::AdWords::v201809::Platform;

use Cwd qw(abs_path);

use constant BID_MODIFIER => 1.5;

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

# Example main subroutine.
sub add_ad_group_bid_modifier {
  my $client      = shift;
  my $ad_group_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::v201809::Platform->new({id => 30001});

  # Create the bid modifier.
  my $modifier = Google::Ads::AdWords::v201809::AdGroupBidModifier->new({
      adGroupId   => $ad_group_id,
      criterion   => $mobile,
      bidModifier => BID_MODIFIER
  });

  # Create ADD operation.
  my $operation =
    Google::Ads::AdWords::v201809::AdGroupBidModifierOperation->new({
      operator => "ADD",
      operand  => $modifier
    });

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

  # Display campaign criteria.
  if ($result->get_value()) {
    foreach my $modifier (@{$result->get_value()}) {
      printf "Ad Group ID '%s', criterion ID '%s', " .
        "and type '%s' was modified with bid %.2f.\n",
        $modifier->get_adGroupId(),
        $modifier->get_criterion()->get_id(),
        $modifier->get_criterion()->get_type(),
        $modifier->get_bidModifier();
    }
  } else {
    print "No ad group bid modifier was added.\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
add_ad_group_bid_modifier($client, $ad_group_id);

Add a page feed specifying URLs for a DSA campaign

#!/usr/bin/perl -w
#
# Copyright 2017, Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This code example adds a page feed to specify precisely which URLs to use
# with your Dynamic Search Ads campaign. To create a Dynamic Search Ads
# campaign, run add_dynamic_search_ads_campaign.pl. To get campaigns, run
# get_campaigns.pl.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::Utilities::PageProcessor;
use Google::Ads::AdWords::v201809::AdGroupCriterionOperation;
use Google::Ads::AdWords::v201809::AttributeFieldMapping;
use Google::Ads::AdWords::v201809::BiddableAdGroupCriterion;
use Google::Ads::AdWords::v201809::Campaign;
use Google::Ads::AdWords::v201809::CampaignFeed;
use Google::Ads::AdWords::v201809::CampaignFeedOperation;
use Google::Ads::AdWords::v201809::CampaignOperation;
use Google::Ads::AdWords::v201809::Feed;
use Google::Ads::AdWords::v201809::FeedAttribute;
use Google::Ads::AdWords::v201809::FeedItem;
use Google::Ads::AdWords::v201809::FeedItemAttributeValue;
use Google::Ads::AdWords::v201809::FeedItemGeoRestriction;
use Google::Ads::AdWords::v201809::FeedItemOperation;
use Google::Ads::AdWords::v201809::FeedMapping;
use Google::Ads::AdWords::v201809::FeedMappingOperation;
use Google::Ads::AdWords::v201809::FeedOperation;
use Google::Ads::AdWords::v201809::Function;
use Google::Ads::AdWords::v201809::Location;
use Google::Ads::AdWords::v201809::PageFeed;
use Google::Ads::AdWords::v201809::Paging;
use Google::Ads::AdWords::v201809::Predicate;
use Google::Ads::AdWords::v201809::Selector;
use Google::Ads::AdWords::v201809::Webpage;
use Google::Ads::AdWords::v201809::WebpageCondition;
use Google::Ads::AdWords::v201809::WebpageParameter;

use Cwd qw(abs_path);
use Data::Uniqid qw(uniqid);
use constant PAGE_SIZE => 500;
# The criterion type to be used for DSA page feeds. DSA page feeds use the
# criterionType field instead of the placeholderType field unlike most other
# feed types.
use constant DSA_PAGE_FEED_CRITERION_TYPE => 61;
# ID that corresponds to the page URLs.
use constant DSA_PAGE_URLS_FIELD_ID => 1;
# ID that corresponds to the labels.
use constant DSA_LABEL_FIELD_ID => 2;

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

# Example main subroutine.
sub add_dynamic_page_feed {
  my ($client, $campaign_id, $ad_group_id) = @_;
  my $dsa_page_url_label = "discounts";

  # Get the page feed details. This code example creates a new feed, but you can
  # fetch and re-use an existing feed.
  my $feed_details = _create_feed($client);
  _create_feed_mapping($client, $feed_details);
  _create_feed_items($client, $feed_details, $dsa_page_url_label);

  # Associate the page feed with the campaign.
  _update_campaign_dsa_setting($client, $campaign_id, $feed_details);

  # Optional: Target web pages matching the feed's label in the ad group.
  _add_dsa_targeting($client, $ad_group_id, $dsa_page_url_label);

  printf("Dynamic page feed setup is complete for campaign ID %s.\n",
    $campaign_id);

  return 1;
}

sub _create_feed {
  my ($client) = @_;

  #  Create attributes.
  my $url_attribute = Google::Ads::AdWords::v201809::FeedAttribute->new({
    type => "URL_LIST",
    name => "Page URL"
  });

  my $label_attribute = Google::Ads::AdWords::v201809::FeedAttribute->new({
    type => "STRING_LIST",
    name => "Label"
  });

  # Create the feed.
  my $dsa_page_feed = Google::Ads::AdWords::v201809::Feed->new({
    name       => sprintf("DSA Feed #%s", uniqid()),
    attributes => [$url_attribute,        $label_attribute],
    origin     => "USER"
  });

  # Create operation.
  my $operation = Google::Ads::AdWords::v201809::FeedOperation->new({
    operator => "ADD",
    operand  => $dsa_page_feed
  });

  # Add the feed.
  my $feed_result =
    $client->FeedService()->mutate({operations => [$operation]});
  my $new_feed = $feed_result->get_value(0);

  my $feed_details = {
    "feedId"           => $new_feed->get_id(),
    "urlAttributeId"   => $new_feed->get_attributes()->[0]->get_id(),
    "labelAttributeId" => $new_feed->get_attributes()->[1]->get_id()};

  printf(
    "Feed with name '%s' and ID %d with urlAttributeId %d " .
      " and labelAttributeId %d was created.\n",
    $new_feed->get_name(),             $feed_details->{"feedId"},
    $feed_details->{"urlAttributeId"}, $feed_details->{"labelAttributeId"});

  return $feed_details;
}

# Creates the feed mapping for the DSA page feeds.
sub _create_feed_mapping {
  my ($client, $feed_details) = @_;

  # Map the FeedAttributeIds to the fieldId constants.
  my $url_field_mapping =
    Google::Ads::AdWords::v201809::AttributeFieldMapping->new({
      feedAttributeId => $feed_details->{"urlAttributeId"},
      fieldId         => DSA_PAGE_URLS_FIELD_ID
    });

  my $label_field_mapping =
    Google::Ads::AdWords::v201809::AttributeFieldMapping->new({
      feedAttributeId => $feed_details->{"labelAttributeId"},
      fieldId         => DSA_LABEL_FIELD_ID
    });

  # Create the FeedMapping and operation.
  my $feed_mapping = Google::Ads::AdWords::v201809::FeedMapping->new({
      criterionType          => DSA_PAGE_FEED_CRITERION_TYPE,
      feedId                 => $feed_details->{"feedId"},
      attributeFieldMappings => [$url_field_mapping, $label_field_mapping]});

  my $operation = Google::Ads::AdWords::v201809::FeedMappingOperation->new({
    operand  => $feed_mapping,
    operator => "ADD"
  });

  # Save the feed mapping.
  my $result =
    $client->FeedMappingService()->mutate({operations => [$operation]});
  my $new_feed_mapping = $result->get_value()->[0];
  printf "Feed mapping with ID %d and criterionType %d was saved for " .
    "feed with ID %d.\n", $new_feed_mapping->get_feedMappingId(),
    $new_feed_mapping->get_criterionType(),
    $new_feed_mapping->get_feedId();
}

sub _create_feed_items {
  my ($client, $feed_details, $label_name) = @_;

  # Create operations to add FeedItems.
  my @operations = ();
  push @operations,
    _create_dsa_url_add_operation($feed_details,
    "http://www.example.com/discounts/rental-cars", $label_name);
  push @operations,
    _create_dsa_url_add_operation($feed_details,
    "http://www.example.com/discounts/hotel-deals", $label_name);
  push @operations,
    _create_dsa_url_add_operation($feed_details,
    "http://www.example.com/discounts/flight-deals", $label_name);

  my $result = $client->FeedItemService()->mutate({operations => \@operations});

  foreach my $feed_item (@{$result->get_value()}) {
    printf "Feed item with feed item ID %d was added.\n",
      $feed_item->get_feedItemId();
  }
}

# Creates a {@link FeedItemOperation} to add the DSA URL.
sub _create_dsa_url_add_operation {
  my ($feed_details, $url, $label_name) = @_;

  # Create the FeedItemAttributeValues for the URL and label.
  my $url_attribute_value =
    Google::Ads::AdWords::v201809::FeedItemAttributeValue->new({
      feedAttributeId => $feed_details->{"urlAttributeId"},
      # See https://support.google.com/adwords/answer/7166527 for
      # page feed URL recommendations and rules.
      stringValues => sprintf("%s", $url)});

  my $label_attribute_value =
    Google::Ads::AdWords::v201809::FeedItemAttributeValue->new({
      feedAttributeId => $feed_details->{"labelAttributeId"},
      stringValues    => $label_name
    });

  # Create the feed item and operation.
  my $feed_item = Google::Ads::AdWords::v201809::FeedItem->new({
      feedId          => $feed_details->{"feedId"},
      attributeValues => [$url_attribute_value, $label_attribute_value]});

  my $operation = Google::Ads::AdWords::v201809::FeedItemOperation->new({
    operand  => $feed_item,
    operator => "ADD"
  });

  return $operation;
}

# Update the campaign DSA setting to add DSA pagefeeds.
sub _update_campaign_dsa_setting {
  my ($client, $campaign_id, $feed_details) = @_;

  my $paging = Google::Ads::AdWords::v201809::Paging->new({
    startIndex    => 0,
    numberResults => PAGE_SIZE
  });
  my $selector = Google::Ads::AdWords::v201809::Selector->new({
      fields     => ["Id", "Settings"],
      predicates => [
        Google::Ads::AdWords::v201809::Predicate->new({
            field    => "CampaignId",
            operator => "EQUALS",
            values   => [$campaign_id]})
      ],
      paging => $paging
    });

  my $dsa_setting = undef;
  Google::Ads::AdWords::Utilities::PageProcessor->new({
      client   => $client,
      service  => $client->CampaignService(),
      selector => $selector
    }
    )->process_entries(
    sub {
      my ($campaign) = @_;
      if ($campaign->get_settings()) {
        foreach my $setting (@{$campaign->get_settings()}) {
          if (
            $setting->isa(
              "Google::Ads::AdWords::v201809::DynamicSearchAdsSetting"))
          {
            $dsa_setting = $setting;
            last;
          }
        }
      }
    });

  if (!$dsa_setting) {
    die sprintf("Campaign with ID %s is not a DSA campaign.", $campaign_id);
  }

  # Use a page feed to specify precisely which URLs to use with your
  # Dynamic Search Ads.
  my $page_feed = Google::Ads::AdWords::v201809::PageFeed->new({
      feedIds => [$feed_details->{"feedId"}]});
  $dsa_setting->set_pageFeed($page_feed);

  # Optional: Specify whether only the supplied URLs should be used with your
  # Dynamic Search Ads.
  $dsa_setting->set_useSuppliedUrlsOnly(1);

  my $updated_campaign = Google::Ads::AdWords::v201809::Campaign->new({
      id       => $campaign_id,
      settings => [$dsa_setting]});

  my $operation = Google::Ads::AdWords::v201809::CampaignOperation->new({
    operand  => $updated_campaign,
    operator => "SET"
  });

  $client->CampaignService()->mutate({operations => [$operation]});
  printf(
    "DSA page feed for campaign ID %d was updated with feed ID %d.\n",
    $updated_campaign->get_id(),
    $feed_details->{"feedId"});
}

# Sets custom targeting for the page feed URLs based on a list of labels.
sub _add_dsa_targeting {
  my ($client, $ad_group_id, $dsa_page_url_label) = @_;

  # Create a webpage criterion.
  # Add a condition for label=specified_label_name.
  my $condition = Google::Ads::AdWords::v201809::WebpageCondition->new({
    operand  => "CUSTOM_LABEL",
    argument => $dsa_page_url_label
  });

  # Create a webpage criterion for special offers.
  my $parameter = Google::Ads::AdWords::v201809::WebpageParameter->new({
      criterionName => "Test criterion",
      conditions    => [$condition]});

  my $webpage = Google::Ads::AdWords::v201809::Webpage->new({
    parameter => $parameter
  });

  # Create biddable ad group criterion.
  my $biddable_ad_group_criterion =
    Google::Ads::AdWords::v201809::BiddableAdGroupCriterion->new({
      adGroupId => $ad_group_id,
      criterion => $webpage,
      # Set a custom bid for this criterion.
      biddingStrategyConfiguration =>
        Google::Ads::AdWords::v201809::BiddingStrategyConfiguration->new({
          bids => [
            Google::Ads::AdWords::v201809::CpcBid->new({
                bid => Google::Ads::AdWords::v201809::Money->new(
                  {microAmount => 1500000}
                ),
              }
            ),
          ]})});

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

  # Create the criterion.
  my $result =
    $client->AdGroupCriterionService()->mutate({operations => [$operation]});
  my $new_ad_group_criterion = $result->get_value()->[0];
  printf "Web page criterion with ID %d and status '%s' was created.\n",
    $new_ad_group_criterion->get_criterion()->get_id(),
    $new_ad_group_criterion->get_userStatus();
}

# 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
add_dynamic_page_feed($client, $campaign_id, $ad_group_id);

Add a DSA campaign

#!/usr/bin/perl -w
#
# Copyright 2017, Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This code example adds a Dynamic Search Ads campaign. To get campaigns, run
# get_campaigns.pl.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201809::AdGroup;
use Google::Ads::AdWords::v201809::AdGroupOperation;
use Google::Ads::AdWords::v201809::AdGroupAd;
use Google::Ads::AdWords::v201809::AdGroupAdOperation;
use Google::Ads::AdWords::v201809::AdGroupCriterionOperation;
use Google::Ads::AdWords::v201809::BiddableAdGroupCriterion;
use Google::Ads::AdWords::v201809::BiddingStrategyConfiguration;
use Google::Ads::AdWords::v201809::Budget;
use Google::Ads::AdWords::v201809::BudgetOperation;
use Google::Ads::AdWords::v201809::Campaign;
use Google::Ads::AdWords::v201809::CampaignCriterion;
use Google::Ads::AdWords::v201809::CampaignCriterionOperation;
use Google::Ads::AdWords::v201809::CampaignOperation;
use Google::Ads::AdWords::v201809::CpcBid;
use Google::Ads::AdWords::v201809::DynamicSearchAdsSetting;
use Google::Ads::AdWords::v201809::ExpandedDynamicSearchAd;
use Google::Ads::AdWords::v201809::Money;
use Google::Ads::AdWords::v201809::Webpage;
use Google::Ads::AdWords::v201809::WebpageCondition;
use Google::Ads::AdWords::v201809::WebpageParameter;

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

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

  my $budget   = _create_budget($client);
  my $campaign = _create_campaign($client, $budget);
  my $ad_group = _create_ad_group($client, $campaign);
  _create_expanded_DSA($client, $ad_group);
  _add_web_page_criteria($client, $ad_group);

  return 1;
}

# Create the budget.
sub _create_budget() {
  my ($client) = @_;

  # Create a budget, which can be shared by multiple campaigns.
  my $shared_budget = Google::Ads::AdWords::v201809::Budget->new({
    name => sprintf("Interplanetary Cruise #%s", uniqid()),
    amount =>
      Google::Ads::AdWords::v201809::Money->new({microAmount => 5000000}),
    deliveryMethod => "STANDARD"
  });

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

  # Add budget.
  my $budget =
    $client->BudgetService()->mutate({operations => ($budget_operation)})
    ->get_value()->[0];
  return $budget;
}

# Creates the campaign.
sub _create_campaign {
  my ($client, $budget) = @_;

  # Required: Set the campaign's Dynamic Search Ads settings.
  my $dynamic_search_ads_setting =
    Google::Ads::AdWords::v201809::DynamicSearchAdsSetting->new({
      # Required: Set the domain name and language.
      domainName   => "example.com",
      languageCode => "en"
    });

  # Calculating a start date of today and an end date 1 year from now.
  my (undef, undef, undef, $mday, $mon, $year) = localtime(time + 60 * 60 * 24);
  my $start_date = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);
  (undef, undef, undef, $mday, $mon, $year) =
    localtime(time + 60 * 60 * 24 * 365);
  my $end_date = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);

  my $campaign = Google::Ads::AdWords::v201809::Campaign->new({
      name => sprintf("Interplanetary Cruise #%s", uniqid()),
      biddingStrategyConfiguration =>
        Google::Ads::AdWords::v201809::BiddingStrategyConfiguration->new({
          biddingStrategyType => "MANUAL_CPC"
        }
        ),
      # Only the budgetId should be sent, all other fields will be ignored by
      # CampaignService.
      budget => Google::Ads::AdWords::v201809::Budget->new(
        {budgetId => $budget->get_budgetId()}
      ),
      advertisingChannelType => "SEARCH",
      settings               => [$dynamic_search_ads_setting],
      # Additional properties (non-required).
      startDate => $start_date,
      endDate   => $end_date,
      # 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"
    });

  # Create operation.
  my $campaign_operation =
    Google::Ads::AdWords::v201809::CampaignOperation->new({
      operator => "ADD",
      operand  => $campaign
    });

  # Add campaigns.
  my $result =
    $client->CampaignService()->mutate({operations => [$campaign_operation]});

  # Display campaigns.
  my $new_campaign = $result->get_value()->[0];
  printf "Campaign with name '%s' and ID %d was added.\n",
    $new_campaign->get_name(),
    $new_campaign->get_id();
  return $new_campaign;
}

# Creates the ad group.
sub _create_ad_group {
  my ($client, $campaign) = @_;

  my $ad_group = Google::Ads::AdWords::v201809::AdGroup->new({
      name       => sprintf("Earth to Mars Cruises #%s", uniqid()),
      campaignId => $campaign->get_id(),
      # Required: Set the ad group's type to Dynamic Search Ads.
      adGroupType => "SEARCH_DYNAMIC_ADS",
      status      => "PAUSED",
      # Recommended: Set a tracking URL template for your ad group if you want
      # to use URL tracking software.
      trackingUrlTemplate =>
        "http://tracker.example.com/traveltracker/{escapedlpurl}",
      biddingStrategyConfiguration =>
        Google::Ads::AdWords::v201809::BiddingStrategyConfiguration->new({
          bids => [
            Google::Ads::AdWords::v201809::CpcBid->new({
                bid => Google::Ads::AdWords::v201809::Money->new(
                  {microAmount => 3000000}
                ),
              }
            ),
          ]})});

  # Create operation.
  my $ad_group_operation =
    Google::Ads::AdWords::v201809::AdGroupOperation->new({
      operator => "ADD",
      operand  => $ad_group
    });

  my $result =
    $client->AdGroupService()->mutate({operations => [$ad_group_operation]});
  my $new_ad_group = $result->get_value()->[0];
  printf "Ad group with name '%s' and ID %d was added.\n",
    $new_ad_group->get_name(), $new_ad_group->get_id();
  return $new_ad_group;
}

# Creates the expanded Dynamic Search Ad.
sub _create_expanded_DSA {
  my ($client, $ad_group) = @_;
  # Create the expanded Dynamic Search Ad. This ad will have its headline and
  # final URL auto-generated at serving time according to domain name specific
  # information provided by DynamicSearchAdsSetting at the campaign level.
  my $expanded_DSA =
    Google::Ads::AdWords::v201809::ExpandedDynamicSearchAd->new({
      # Set the ad description.
      description  => "Buy your tickets now!",
      description2 => "Discount ends soon"
    });

  # Create the ad group ad.
  my $ad_group_ad = Google::Ads::AdWords::v201809::AdGroupAd->new({
    adGroupId => $ad_group->get_id(),
    ad        => $expanded_DSA,
    # Optional: Set the status.
    status => "PAUSED"
  });

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

  my $result =
    $client->AdGroupAdService()->mutate({operations => [$operation]});
  my $new_ad_group_ad = $result->get_value()->[0];
  my $new_expanded_dsa = $new_ad_group_ad->get_ad();
  printf
    "Expanded Dynamic Search Ad with ID %d, description '%s', and " .
    "description 2 '%s' was added.\n",
    $new_expanded_dsa->get_id(), $new_expanded_dsa->get_description(),
    $new_expanded_dsa->get_description2();
}

# Adds a web page criteria to target Dynamic Search Ads.
sub _add_web_page_criteria {
  my ($client, $ad_group) = @_;

  my $url_condition = Google::Ads::AdWords::v201809::WebpageCondition->new({
    operand  => "URL",
    argument => "/specialoffers"
  });

  my $title_condition = Google::Ads::AdWords::v201809::WebpageCondition->new({
    operand  => "PAGE_TITLE",
    argument => "Special Offer"
  });

  # Create a webpage criterion for special offers.
  my $param = Google::Ads::AdWords::v201809::WebpageParameter->new({
      criterionName => "Special offers",
      conditions    => [$url_condition, $title_condition]});

  my $webpage = Google::Ads::AdWords::v201809::Webpage->new({
    parameter => $param
  });

  # Create biddable ad group criterion.
  my $biddable_ad_group_criterion =
    Google::Ads::AdWords::v201809::BiddableAdGroupCriterion->new({
      adGroupId  => $ad_group->get_id(),
      criterion  => $webpage,
      userStatus => "PAUSED",
      # Optional: set a custom bid.
      biddingStrategyConfiguration =>
        Google::Ads::AdWords::v201809::BiddingStrategyConfiguration->new({
          bids => [
            Google::Ads::AdWords::v201809::CpcBid->new({
                bid => Google::Ads::AdWords::v201809::Money->new(
                  {microAmount => 1000000}
                ),
              }
            ),
          ]})});

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

  # Create the criterion.
  my $result =
    $client->AdGroupCriterionService()->mutate({operations => [$operation]});
  my $new_ad_group_criterion = $result->get_value()->[0];
  printf "Webpage criterion with ID %d was added to ad group ID %d.\n",
    $new_ad_group_criterion->get_criterion()->get_id(),
    $new_ad_group_criterion->get_adGroupId();
}

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

Add an expanded text ad with Upgraded URLs

#!/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 text ad that uses advanced features of upgraded URLs.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201809::AdGroupAd;
use Google::Ads::AdWords::v201809::AdGroupAdOperation;
use Google::Ads::AdWords::v201809::CustomParameter;
use Google::Ads::AdWords::v201809::CustomParameters;
use Google::Ads::AdWords::v201809::ExpandedTextAd;
use Google::Ads::AdWords::v201809::Image;
use Google::Ads::AdWords::v201809::ImageAd;
use Google::Ads::AdWords::v201809::TemplateAd;
use Google::Ads::AdWords::v201809::Video;
use Google::Ads::Common::MediaUtils;

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

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

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

  # Create text ad.
  my $text_ad = Google::Ads::AdWords::v201809::ExpandedTextAd->new({
      headlinePart1 => "Cruise to Mars #" . substr(uniqid(), 0, 8),
      headlinePart2 => "Visit the Red Planet in style.",
      description   => "Buy your tickets now!"
  });

  # Specify a tracking url for 3rd party tracking provider. You may
  # specify one at customer, campaign, ad group, ad, criterion or
  # feed item levels.
  $text_ad->set_trackingUrlTemplate(
    "http://tracker.example.com/?season={_season}&promocode={_promocode}&" .
      "u={lpurl}");

  # Since your tracking url has two custom parameters, provide their
  # values too. This can be provided at campaign, ad group, ad, criterion
  # or feed item levels.
  my $season_parameter = Google::Ads::AdWords::v201809::CustomParameter->new({
      key   => "season",
      value => "christmas"
  });
  my $promo_code_parameter =
    Google::Ads::AdWords::v201809::CustomParameter->new({
      key   => "promocode",
      value => "NYC123"
    });
  my $tracking_url_parameters =
    Google::Ads::AdWords::v201809::CustomParameters->new(
    {parameters => [$season_parameter, $promo_code_parameter]});

  $text_ad->set_urlCustomParameters($tracking_url_parameters);

  # Specify a list of final urls. This field cannot be set if url field is
  # set. This may be specified at ad, criterion, and feed item levels.
  $text_ad->set_finalUrls([
      "http://www.example.com/cruise/space/",
      "http://www.example.com/locations/mars/"
  ]);
  # Specify a list of final mobile urls. This field cannot be set if url field
  # is set or finalUrls is not set. This may be specified at ad, criterion, and
  # feed item levels.
  $text_ad->set_finalMobileUrls([
      "http://mobile.example.com/cruise/space/",
      "http://mobile.example.com/locations/mars/"
  ]);

  # Create ad group ad for the expanded text ad.
  my $text_ad_group_ad = Google::Ads::AdWords::v201809::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::v201809::AdGroupAdOperation->new({
      operator => "ADD",
      operand  => $text_ad_group_ad
    });

  # Add expanded text ads.
  my $result =
    $client->AdGroupAdService()
    ->mutate({operations => [$text_ad_group_ad_operation]});

  # Display results.
  if ($result->get_value()) {
    foreach my $ad_group_ad (@{$result->get_value()}) {
      printf "New expanded text ad with id \"%d\" was added.\n",
        $ad_group_ad->get_ad()->get_id();
    }
  } else {
    print "No expanded text ads were added.\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
add_text_ad_with_upgraded_urls($client, $ad_group_id);


Add a Gmail ad to an ad group

#!/usr/bin/perl -w
#
# Copyright 2018, 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 Gmail ad to a given ad group. The ad group's campaign
# needs to have an AdvertisingChannelType of DISPLAY and
# AdvertisingChannelSubType of DISPLAY_GMAIL_AD.
# To get ad groups, run basic_operations/get_ad_groups.pl.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::Common::MediaUtils;
use Google::Ads::AdWords::v201809::AdGroupAd;
use Google::Ads::AdWords::v201809::AdGroupAdOperation;
use Google::Ads::AdWords::v201809::GmailAd;
use Google::Ads::AdWords::v201809::GmailTeaser;

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

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

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

  # This ad format does not allow the creation of an image using the
  # Image.data field. An image must first be created using the MediaService,
  # and Image.mediaId must be populated when creating the ad.
  my $logo_image = _upload_image($client, 'https://goo.gl/mtt54n');
  my $logo = Google::Ads::AdWords::v201809::Image->new({
    mediaId => $logo_image->get_mediaId(),
  });

  my $ad_image = _upload_image($client, "http://goo.gl/3b9Wfh");
  my $marketing_image = Google::Ads::AdWords::v201809::Image->new(
    {mediaId => $ad_image->get_mediaId()});

  my $teaser = Google::Ads::AdWords::v201809::GmailTeaser->new({
    headline     => "Dream",
    description  => "Create your own adventure",
    businessName => "Interplanetary Ships",
    logoImage    => $logo_image
  });

  # Create the Gmail ad.
  my $gmail_ad = Google::Ads::AdWords::v201809::GmailAd->new({
      teaser => $teaser,
      marketingImage            => $marketing_image,
      marketingImageHeadline    => "Travel",
      marketingImageDescription => "Take to the skies!",
      finalUrls                 => ["http://www.example.com/"]
  });

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

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

  # Add Gmail ad.
  my $result =
    $client->AdGroupAdService()
    ->mutate({operations => [$gmail_ad_group_ad_operation]});

  # Display results.
  if ($result->get_value()) {
    foreach my $ad_group_ad (@{$result->get_value()}) {
      printf "New Gmail ad with ID %d and headline \"%s\" was added.\n",
        $ad_group_ad->get_ad()->get_id(),
        $ad_group_ad->get_ad()->get_teaser()->get_headline();
    }
  } else {
    print "No Gmail ads were added.\n";
    return 0;
  }

  return 1;
}

sub _upload_image {
  my ($client, $url) = @_;

  # Creates an image and upload it to the server.
  my $image_data =
    Google::Ads::Common::MediaUtils::get_base64_data_from_url($url);
  my $image = Google::Ads::AdWords::v201809::Image->new({
    data => $image_data,
    type => "IMAGE"
  });

  return $client->MediaService()->upload({media => [$image]});
}

# 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(1);

# 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
add_gmail_ad($client, $ad_group_id);


Add an HTML 5 ad to 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 code example adds an HTML5 ad to a given ad group.
# To get ad groups, run basic_operations/get_ad_groups.pl.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201809::AdGroupAd;
use Google::Ads::AdWords::v201809::AdGroupAdOperation;
use Google::Ads::AdWords::v201809::Dimensions;
use Google::Ads::AdWords::v201809::MediaBundle;
use Google::Ads::AdWords::v201809::TemplateAd;
use Google::Ads::AdWords::v201809::TemplateElementField;
use Google::Ads::Common::MediaUtils;

use Cwd qw(abs_path);

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

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

  my @operations = ();

  # Create the template ad.
  my $html5_ad = Google::Ads::AdWords::v201809::TemplateAd->new({
      name       => "Ad for HTML5",
      templateId => 419,
      finalUrls  => ["http://example.com/html5"],
      displayUrl => "www.example.com/html5",
      dimensions => Google::Ads::AdWords::v201809::Dimensions->new({
          width  => 300,
          height => 250
        })});

  # The HTML5 zip file contains all the HTML, CSS, and images needed for the
  # HTML5 ad. For help on creating an HTML5 zip file, check out Google Web
  # Designer (https://www.google.com/webdesigner/).
  my $html5_zip = Google::Ads::Common::MediaUtils::get_base64_data_from_url(
    "https://goo.gl/9Y7qI2");

  # Create a media bundle containing the zip file with all the HTML5 components.
  # NOTE: You may also upload an HTML5 zip using MediaService.upload()
  # and simply set the mediaId field below. See upload_media_bundle.pl
  # for an example.
  my $media_bundle = Google::Ads::AdWords::v201809::MediaBundle->new({
      data       => $html5_zip,
      entryPoint => "carousel/index.html",
      type       => "MEDIA_BUNDLE"
  });

  # Create the template elements for the ad. You can refer to
  # https://developers.google.com/adwords/api/docs/appendix/templateads
  # for the list of available template fields.
  my $media = Google::Ads::AdWords::v201809::TemplateElementField->new({
      name       => "Custom_layout",
      fieldMedia => $media_bundle,
      type       => "MEDIA_BUNDLE"
  });
  my $layout = Google::Ads::AdWords::v201809::TemplateElementField->new({
      name      => "layout",
      fieldText => "Custom",
      type      => "ENUM"
  });

  my $adData = Google::Ads::AdWords::v201809::TemplateElement->new({
      uniqueName => "adData",
      fields     => [$media, $layout]});

  $html5_ad->set_templateElements([$adData]);

  # Create the AdGroupAd.
  my $html5_ad_group_ad = Google::Ads::AdWords::v201809::AdGroupAd->new({
      adGroupId => $ad_group_id,
      ad        => $html5_ad,
      # Additional properties (non-required).
      status => "PAUSED"
  });
  my $ad_group_ad_operation =
    Google::Ads::AdWords::v201809::AdGroupAdOperation->new({
      operator => "ADD",
      operand  => $html5_ad_group_ad
    });

  push @operations, $ad_group_ad_operation;

  # Add HTML5 ad.
  my $result =
    $client->AdGroupAdService()->mutate({operations => \@operations});

  # Display results.
  if ($result->get_value()) {
    foreach my $ad_group_ad (@{$result->get_value()}) {
      printf "New HTML5 ad with id \"%d\" and display url " .
        "\"%s\" was added.\n",
        $ad_group_ad->get_ad()->get_id(),
        $ad_group_ad->get_ad()->get_displayUrl();
    }
  } else {
    print "No HTML5 ads were added.\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
add_html5_ad($client, $ad_group_id);

Add a responsive display 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 code example adds an image representing the ad using the MediaService and
# then adds a responsive display ad to a given ad group.
# To get ad groups, run basic_operations/get_ad_groups.pl.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::Common::MediaUtils;
use Google::Ads::AdWords::v201809::AdGroupAd;
use Google::Ads::AdWords::v201809::AdGroupAdOperation;
use Google::Ads::AdWords::v201809::DisplayAdFormatSetting;
use Google::Ads::AdWords::v201809::DynamicSettings;
use Google::Ads::AdWords::v201809::ResponsiveDisplayAd;

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

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

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

  # This ad format does not allow the creation of an image using the
  # Image.data field. An image must first be created using the MediaService,
  # and Image.mediaId must be populated when creating the ad.
  my $ad_image = _upload_image($client, "http://goo.gl/3b9Wfh");
  my $marketing_image = Google::Ads::AdWords::v201809::Image->new(
    {mediaId => $ad_image->get_mediaId()});

  # Create the responsive display ad.
  my $responsive_display_ad =
    Google::Ads::AdWords::v201809::ResponsiveDisplayAd->new({
      marketingImage => $marketing_image,
      shortHeadline  => "Travel",
      longHeadline   => "Travel the World",
      description    => "Take to the air!",
      businessName   => "Interplanetary Cruises",
      finalUrls      => ["http://www.example.com/"],
    });

  # Optional: Create a square marketing image using MediaService, and set it
  # to the ad.
  my $square_image = _upload_image($client, "https://goo.gl/mtt54n");
  my $square_marketing_image = Google::Ads::AdWords::v201809::Image->new(
    {mediaId => $square_image->get_mediaId()});
  $responsive_display_ad->set_squareMarketingImage($square_marketing_image);

  # Optional: Set call to action text.
  $responsive_display_ad->set_callToActionText("Shop Now");

  # Optional: Set dynamic display ad settings, composed of landscape logo
  # image, promotion text, and price prefix.
  my $dynamic_settings = _create_dynamic_display_ad_settings($client);
  $responsive_display_ad->set_dynamicDisplayAdSettings($dynamic_settings);

  # Whitelisted accounts only: Set color settings using hexadecimal values.
  # Set allowFlexibleColor to false if you want your ads to render by always
  # using your colors strictly.
  # $responsiveDisplayAd->set_mainColor("#0000ff");
  # $responsiveDisplayAd->set_accentColor("#ffff00");
  # $responsiveDisplayAd->set_allowFlexibleColor(0);

  # Whitelisted accounts only: Set the format setting that the ad will be
  # served in.
  # $responsiveDisplayAd->set_formatSetting("NON_NATIVE");

  # Create ad group ad for the responsive display ad.
  my $responsive_display_ad_group_ad =
    Google::Ads::AdWords::v201809::AdGroupAd->new({
      adGroupId => $ad_group_id,
      ad        => $responsive_display_ad,
      # Additional properties (non-required).
      status => "PAUSED"
    });

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

  # Add responsive display ad.
  my $result =
    $client->AdGroupAdService()
    ->mutate({operations => [$responsive_display_ad_group_ad_operation]});

  # Display results.
  if ($result->get_value()) {
    foreach my $ad_group_ad (@{$result->get_value()}) {
      printf "New responsive display ad with id \"%d\" and " .
        "short headline \"%s\" was added.\n",
        $ad_group_ad->get_ad()->get_id(),
        $ad_group_ad->get_ad()->get_shortHeadline();
    }
  } else {
    print "No responsive display ads were added.\n";
  }

  return 1;
}

sub _upload_image {
  my ($client, $url) = @_;

  # Creates an image and upload it to the server.
  my $image_data = Google::Ads::Common::MediaUtils::get_base64_data_from_url(
    $url);
  my $image = Google::Ads::AdWords::v201809::Image->new({
      data => $image_data,
      type => "IMAGE"
  });

  return $client->MediaService()->upload({media => [$image]});
}

sub _create_dynamic_display_ad_settings {
  my ($client) = @_;

  my $logo_image = _upload_image($client, 'https://goo.gl/dEvQeF');
  my $logo = Google::Ads::AdWords::v201809::Image->new({
      mediaId => $logo_image->get_mediaId(),
  });

  my $dynamic_settings = Google::Ads::AdWords::v201809::DynamicSettings->new({
    landscapeLogoImage => $logo,
    pricePrefix => "as low as",
    promoText => "Free shipping!"
  });

  return $dynamic_settings;
}

# 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
add_responsive_display_ad($client, $ad_group_id);


Add a Shopping dynamic remarketing campaign

#!/usr/bin/perl -w
#
# Copyright 2018, 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 Shopping dynamic remarketing campaign for the Display
# Network via the following steps:
# * Creates a new Display Network campaign.
# * Links the campaign with Merchant Center.
# * Links the user list to the ad group.
# * Creates a responsive display ad to render the dynamic text.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201809::AdGroup;
use Google::Ads::AdWords::v201809::AdGroupOperation;
use Google::Ads::AdWords::v201809::AdGroupAd;
use Google::Ads::AdWords::v201809::AdGroupAdOperation;
use Google::Ads::AdWords::v201809::AdGroupCriterionOperation;
use Google::Ads::AdWords::v201809::BiddableAdGroupCriterion;
use Google::Ads::AdWords::v201809::BiddingStrategyConfiguration;
use Google::Ads::AdWords::v201809::Budget;
use Google::Ads::AdWords::v201809::Campaign;
use Google::Ads::AdWords::v201809::CampaignOperation;
use Google::Ads::AdWords::v201809::CriterionUserList;
use Google::Ads::AdWords::v201809::DynamicSettings;
use Google::Ads::AdWords::v201809::Image;
use Google::Ads::AdWords::v201809::ResponsiveDisplayAd;
use Google::Ads::AdWords::v201809::ShoppingSetting;
use Google::Ads::Common::MediaUtils;

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

# Replace with valid values of your account.
my $budget_id    = "INSERT_BUDGET_ID_HERE";
my $merchant_id  = "INSERT_MERCHANT_ID_HERE";
my $user_list_id = "INSERT_USER_LIST_ID_HERE";

# Example main subroutine.
sub add_shopping_dynamic_remarketing_campaign {
  my ($client, $merchant_id, $budget_id, $user_list_id) = @_;

  my $campaign = _create_campaign($client, $merchant_id, $budget_id);
  printf("Campaign with name '%s' and ID %d was added.\n",
    $campaign->get_name(), $campaign->get_id());

  my $ad_group = _create_ad_group($client, $campaign);
  printf("Ad group with name '%s' and ID %d was added.\n",
    $ad_group->get_name(), $ad_group->get_id());

  my $ad_group_ad = _create_ad($client, $ad_group);
  printf("Responsive display ad with ID %d was added.\n",
    $ad_group_ad->get_ad()->get_id());

  _attach_user_list($client, $ad_group, $user_list_id);
  printf("User list with ID %d was attached to ad group with ID %d.\n",
    $user_list_id, $ad_group->get_id());

  return 1;
}

# Creates a Shopping dynamic remarketing campaign object (not including ad
# group level and below). This creates a Display campaign with the merchant
# center feed attached. Merchant Center is used for the product information in
# combination with a user list which contains hits with ecomm_prodid specified.
# See https://developers.google.com/adwords-remarketing-tag/parameters#retail"
# for more detail.
sub _create_campaign {
  my ($client, $merchant_id, $budget_id) = @_;

  my $campaign = Google::Ads::AdWords::v201809::Campaign->new({
      name => sprintf("Shopping campaign #%s", uniqid()),
      # Dynamic remarketing campaigns are only available on the Google Display
      # Network.
      advertisingChannelType => "DISPLAY",
      status                 => "PAUSED",
      budget =>
        Google::Ads::AdWords::v201809::Budget->new({budgetId => $budget_id}),
      # This example uses a Manual CPC bidding strategy, but you should select
      # the strategy that best aligns with your sales goals. More details here:
      # https://support.google.com/adwords/answer/2472725
      biddingStrategyConfiguration =>
        Google::Ads::AdWords::v201809::BiddingStrategyConfiguration->new({
          biddingStrategyType => "MANUAL_CPC"
        }
        ),
      settings => [
        Google::Ads::AdWords::v201809::ShoppingSetting->new({
            # Campaigns with numerically higher priorities take precedence over
            # those with lower priorities.
            campaignPriority => 0,
            # Set the Merchant Center account ID from which to source products.
            merchantId => $merchant_id,
            # Display Network campaigns do not support partition by country.
            # The only supported value is "ZZ". This signals that products
            # from all countries are available in the campaign. The actual
            # products which serve are based on the products tagged in the user
            # list entry.
            salesCountry => "ZZ",
            # Optional: Enable local inventory ads (items for sale in physical
            # stores.)
            enableLocal => 1
          })
      ],
    });

  # Create operation.
  my $campaign_operation =
    Google::Ads::AdWords::v201809::CampaignOperation->new({
      operator => "ADD",
      operand  => $campaign
    });

  my $result =
    $client->CampaignService()->mutate({operations => [$campaign_operation]});
  return $result->get_value()->[0];
}

# Creates an ad group in the specified campaign.
sub _create_ad_group {
  my ($client, $campaign) = @_;

  my $ad_group = Google::Ads::AdWords::v201809::AdGroup->new({
    name       => sprintf("Dynamic remarketing ad group"),
    campaignId => $campaign->get_id(),
    status     => "ENABLED"
  });

  my $ad_group_operation =
    Google::Ads::AdWords::v201809::AdGroupOperation->new({
      operator => "ADD",
      operand  => $ad_group
    });

  my $result =
    $client->AdGroupService()->mutate({operations => [$ad_group_operation]});
  return $result->get_value()->[0];
}

# Attach a user list to an ad group. The user list provides positive targeting
# and feed information to drive the dynamic content of the ad.
# Note: User lists must be attached at the ad group level for positive
# targeting in Shopping dynamic remarketing campaigns.
sub _attach_user_list {
  my ($client, $ad_group, $user_list_id) = @_;

  my $user_list = Google::Ads::AdWords::v201809::CriterionUserList->new({
    userListId => $user_list_id
  });

  my $ad_group_criterion =
    Google::Ads::AdWords::v201809::BiddableAdGroupCriterion->new({
      adGroupId => $ad_group->get_id(),
      criterion => $user_list
    });

  my $operation = Google::Ads::AdWords::v201809::AdGroupCriterionOperation->new(
    {
      operand  => $ad_group_criterion,
      operator => "ADD"
    });
  $client->AdGroupCriterionService()->mutate({operations => [$operation]});
}

# Creates an ad for serving dynamic content in a remarketing campaign.
sub _create_ad {
  my ($client, $ad_group) = @_;

  # This ad format does not allow the creation of an image using the
  # Image.data field. An image must first be created using the MediaService,
  # and Image.mediaId must be populated when creating the ad.
  my $ad_image = _upload_image($client, "https://goo.gl/3b9Wfh");
  my $marketing_image = Google::Ads::AdWords::v201809::Image->new(
    {mediaId => $ad_image->get_mediaId()});

  # Create the responsive display ad.
  my $responsive_display_ad =
    Google::Ads::AdWords::v201809::ResponsiveDisplayAd->new({
      marketingImage => $marketing_image,
      shortHeadline  => "Travel",
      longHeadline   => "Travel the World",
      description    => "Take to the air!",
      businessName   => "Interplanetary Cruises",
      finalUrls      => ["http://www.example.com/"]});

  # Optional: Call to action text.
  # Valid texts: https://support.google.com/adwords/answer/7005917
  $responsive_display_ad->set_callToActionText("Apply Now");

  # Optional: Set dynamic display ad settings, composed of landscape logo
  # image, promotion text, and price prefix.
  my $dynamic_settings = _create_dynamic_display_ad_settings($client);
  $responsive_display_ad->set_dynamicDisplayAdSettings($dynamic_settings);

  # Optional: Create a logo image and set it to the ad.
  my $logo_image = _upload_image($client, "https://goo.gl/mtt54n");
  my $logo_marketing_image = Google::Ads::AdWords::v201809::Image->new(
    {mediaId => $logo_image->get_mediaId()});
  $responsive_display_ad->set_logoImage($logo_marketing_image);

  # Optional: Create a square marketing image and set it to the ad.
  my $square_image = _upload_image($client, "https://goo.gl/mtt54n");
  my $square_marketing_image = Google::Ads::AdWords::v201809::Image->new(
    {mediaId => $square_image->get_mediaId()});
  $responsive_display_ad->set_squareMarketingImage($square_marketing_image);

  # Whitelisted accounts only: Set color settings using hexadecimal values.
  # Set allowFlexibleColor to false if you want your ads to render by always
  # using your colors strictly.
  # $responsiveDisplayAd->set_mainColor("#0000ff");
  # $responsiveDisplayAd->set_accentColor("#ffff00");
  # $responsiveDisplayAd->set_allowFlexibleColor(0);

  # Whitelisted accounts only: Set the format setting that the ad will be
  # served in.
  # $responsiveDisplayAd->set_formatSetting("NON_NATIVE");

  # Create ad group ad for the responsive display ad.
  my $responsive_display_ad_group_ad =
    Google::Ads::AdWords::v201809::AdGroupAd->new({
      adGroupId => $ad_group->get_id(),
      ad        => $responsive_display_ad
    });

  my $responsive_display_ad_group_ad_operation =
    Google::Ads::AdWords::v201809::AdGroupAdOperation->new({
      operator => "ADD",
      operand  => $responsive_display_ad_group_ad
    });

  my $result =
    $client->AdGroupAdService()
    ->mutate({operations => [$responsive_display_ad_group_ad_operation]});
  return $result->get_value()->[0];
}

# Creates the additional content (images, promo text, etc.) supported by
# dynamic ads.
sub _create_dynamic_display_ad_settings {
  my ($client) = @_;

  my $logo_image = _upload_image($client, 'https://goo.gl/dEvQeF');
  my $logo = Google::Ads::AdWords::v201809::Image->new({
    mediaId => $logo_image->get_mediaId(),
  });

  my $dynamic_settings = Google::Ads::AdWords::v201809::DynamicSettings->new({
    landscapeLogoImage => $logo,
    pricePrefix        => "as low as",
    promoText          => "Free shipping!"
  });

  return $dynamic_settings;
}

# Uploads the image from the specified URL.
sub _upload_image {
  my ($client, $url) = @_;

  # Creates an image and upload it to the server.
  my $image_data =
    Google::Ads::Common::MediaUtils::get_base64_data_from_url($url);
  my $image = Google::Ads::AdWords::v201809::Image->new({
    data => $image_data,
    type => "IMAGE"
  });

  return $client->MediaService()->upload({media => [$image]});
}

# 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
add_shopping_dynamic_remarketing_campaign($client, $merchant_id, $budget_id,
  $user_list_id);

Add a universal app campaign

#!/usr/bin/perl -w
#
# Copyright 2017, Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This example adds a universal app campaign. To get campaigns, run
# get_campaigns.pl. To upload image assets for this campaign, run
# upload_image.pl.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201809::BiddingStrategyConfiguration;
use Google::Ads::AdWords::v201809::Budget;
use Google::Ads::AdWords::v201809::BudgetOperation;
use Google::Ads::AdWords::v201809::Campaign;
use Google::Ads::AdWords::v201809::CampaignCriterion;
use Google::Ads::AdWords::v201809::CampaignCriterionOperation;
use Google::Ads::AdWords::v201809::CampaignOperation;
use Google::Ads::AdWords::v201809::GeoTargetTypeSetting;
use Google::Ads::AdWords::v201809::Language;
use Google::Ads::AdWords::v201809::Location;
use Google::Ads::AdWords::v201809::Money;
use Google::Ads::AdWords::v201809::NetworkSetting;
use Google::Ads::AdWords::v201809::TargetCpaBiddingScheme;
use Google::Ads::AdWords::v201809::UniversalAppCampaignSetting;

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

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

  # Set the campaign's assets and ad text ideas. These values will be used to
  # generate ads.
  my $universalAppSetting =
    Google::Ads::AdWords::v201809::UniversalAppCampaignSetting->new({
      appId        => "com.labpixies.colordrips",
      appVendor    => "VENDOR_GOOGLE_MARKET",
      description1 => "A cool puzzle game",
      description2 => "Remove connected blocks",
      description3 => "3 difficulty levels",
      description4 => "4 colorful fun skins"
    });

  # Optional: You can set up to 20 image assets for your campaign.
  # See upload_image.pl for an example on how to upload images.
  # universalAppSetting->set_imageMediaIds([INSERT_IMAGE_MEDIA_ID_HERE]);

  # Optimize this campaign for getting new users for your app.
  $universalAppSetting->set_universalAppBiddingStrategyGoalType(
    "OPTIMIZE_FOR_INSTALL_CONVERSION_VOLUME");

  # If you select the OPTIMIZE_FOR_IN_APP_CONVERSION_VOLUME goal type, then also
  # specify your in-app conversion types so AdWords can focus your campaign on
  # people who are most likely to complete the corresponding in-app actions.
  # Conversion type IDs can be retrieved using ConversionTrackerService.get.

  # my $selectiveOptimization =
  # Google::Ads::AdWords::v201809::SelectiveOptimization->new({
  #  conversionTypeIds =>
  #    [INSERT_CONVERSION_TYPE_ID_1_HERE, INSERT_CONVERSION_TYPE_ID_2_HERE]
  # });
  # $campaign->set_selectiveOptimization($selectiveOptimization);

  # Optional: Set the campaign settings for advanced location options.
  my $geoSetting = Google::Ads::AdWords::v201809::GeoTargetTypeSetting->new({
    positiveGeoTargetType => "LOCATION_OF_PRESENCE",
    negativeGeoTargetType => "DONT_CARE"
  });

  my (undef, undef, undef, $mday, $mon, $year) = localtime(time + 60 * 60 * 24);
  my $start_date = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);
  (undef, undef, undef, $mday, $mon, $year) =
    localtime(time + 60 * 60 * 24 * 365);
  my $end_date = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);

  my $budgetId = create_budget($client);

  my $campaign = Google::Ads::AdWords::v201809::Campaign->new({
      name => "Interplanetary Cruise App #" . uniqid(),
      # Bidding strategy (required).
      # Set the campaign's bidding strategy. Universal app campaigns
      # only support TARGET_CPA bidding strategy.
      biddingStrategyConfiguration =>
        Google::Ads::AdWords::v201809::BiddingStrategyConfiguration->new({
          biddingStrategyType => "TARGET_CPA",
          # Set the target CPA to $1 / app install.
          biddingScheme =>
            Google::Ads::AdWords::v201809::TargetCpaBiddingScheme->new({
              targetCpa => Google::Ads::AdWords::v201809::Money->new(
                {microAmount => 1000000})})}
        ),
      # Budget (required) - note only the budgetId is required.
      budget =>
        Google::Ads::AdWords::v201809::Budget->new({budgetId => $budgetId}),
      # Advertising channel type (required).
      # Set the advertising channel and subchannel types for universal
      # app campaigns.
      advertisingChannelType    => "MULTI_CHANNEL",
      advertisingChannelSubType => "UNIVERSAL_APP_CAMPAIGN",
      settings                  => [$universalAppSetting, $geoSetting],
      # Additional properties (non-required).
      startDate => $start_date,
      endDate   => $end_date,
      # 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"
    });

  # Create operation.
  my $campaign_operation =
    Google::Ads::AdWords::v201809::CampaignOperation->new({
      operator => "ADD",
      operand  => $campaign
    });

  # Add campaigns.
  my $result =
    $client->CampaignService()->mutate({operations => [$campaign_operation]});

  # Display campaigns.
  foreach my $new_campaign (@{$result->get_value()}) {
    printf "Universal app campaign with name \"%s\" and ID %s was added.\n",
      $new_campaign->get_name(), $new_campaign->get_id();
    # Optional: Set the campaign's location and language targeting. No other
    # targeting criteria can be used for universal app campaigns.
    set_campaign_targeting_criteria($client, $new_campaign->get_id());
  }

  return 1;
}

# Create the budget.
sub create_budget() {
  my ($client) = @_;

  # Create the campaign budget.
  my $budget = Google::Ads::AdWords::v201809::Budget->new({
    # Required attributes.
    name => "Interplanetary Cruise App Budget #" . uniqid(),
    amount =>
      Google::Ads::AdWords::v201809::Money->new({microAmount => 5000000}),
    deliveryMethod => "STANDARD",
    # Universal app campaigns don't support shared budgets.
    isExplicitlyShared => 0
  });

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

  # Add budget.
  my $addedBudget =
    $client->BudgetService()->mutate({operations => ($budget_operation)})
    ->get_value();
  printf
    "Budget with name '%s' and ID %d was created.\n",
    $addedBudget->get_name(), $addedBudget->get_budgetId()->get_value();
  my $budget_id = $addedBudget->get_budgetId()->get_value();
  return $budget_id;
}

# Set the campaign targeting criteria.
sub set_campaign_targeting_criteria() {
  my ($client, $campaign_id) = @_;
  my @criteria = ();

  # Create locations. The IDs can be found in the documentation or retrieved
  # with the LocationCriterionService.
  my $california = Google::Ads::AdWords::v201809::Location->new({id => 21137});
  push @criteria, $california;
  my $mexico = Google::Ads::AdWords::v201809::Location->new({id => 2484});
  push @criteria, $mexico;

  # Create languages. The IDs can be found in the documentation or retrieved
  # with the ConstantDataService.
  my $english = Google::Ads::AdWords::v201809::Language->new({id => 1000});
  push @criteria, $english;
  my $spanish = Google::Ads::AdWords::v201809::Language->new({id => 1003});
  push @criteria, $spanish;

  # Create operations.
  my @operations = ();
  foreach my $criterion (@criteria) {
    my $operation =
      Google::Ads::AdWords::v201809::CampaignCriterionOperation->new({
        operator => "ADD",
        operand  => Google::Ads::AdWords::v201809::CampaignCriterion->new({
            campaignId => $campaign_id,
            criterion  => $criterion
          })});
    push @operations, $operation;
  }

  # Set campaign criteria.
  my $result =
    $client->CampaignCriterionService()->mutate({operations => \@operations});

  # Display campaign criteria.
  if ($result->get_value()) {
    foreach my $campaign_criterion (@{$result->get_value()}) {
      printf "Campaign criterion of type '%s' and ID %s was added.\n",
        $campaign_criterion->get_criterion()->get_type(),
        $campaign_criterion->get_criterion()->get_id();
    }
  }
}

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

Create a negative broad match keywords list and attach it to a campaign

#!/usr/bin/perl -w
#
# Copyright 2017, Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This example creates a shared list of negative broad match keywords, then
# attaches them to a campaign.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201809::CampaignSharedSet;
use Google::Ads::AdWords::v201809::CampaignSharedSetOperation;
use Google::Ads::AdWords::v201809::Keyword;
use Google::Ads::AdWords::v201809::SharedCriterion;
use Google::Ads::AdWords::v201809::SharedCriterionOperation;
use Google::Ads::AdWords::v201809::SharedSet;
use Google::Ads::AdWords::v201809::SharedSetOperation;

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

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

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

  # Keywords to include in the shared set.
  my @keywords = ('mars cruise', 'mars hotels');

  # Create the shared negative keyword set.
  my $shared_set = Google::Ads::AdWords::v201809::SharedSet->new({
      name => 'Negative keyword list #' . uniqid(),
      type => 'NEGATIVE_KEYWORDS'
  });

  # Add the shared set.
  my $shared_set_result = $client->SharedSetService()->mutate({
      operations => [
        Google::Ads::AdWords::v201809::SharedSetOperation->new({
            operator => 'ADD',
            operand  => $shared_set
          })]});

  $shared_set = $shared_set_result->get_value(0);

  printf "Shared set with ID %d and name '%s' was successfully added.\n",
    $shared_set->get_sharedSetId(),
    $shared_set->get_name();

  # Add negative keywords to the shared set.
  my @shared_criterion_operations = ();
  foreach my $keyword (@keywords) {
    my $keyword_criterion = Google::Ads::AdWords::v201809::Keyword->new({
        text      => $keyword,
        matchType => 'BROAD'
    });

    my $shared_criterion = Google::Ads::AdWords::v201809::SharedCriterion->new({
        criterion   => $keyword_criterion,
        negative    => 1,
        sharedSetId => $shared_set->get_sharedSetId()});

    my $shared_criterion_operation =
      Google::Ads::AdWords::v201809::SharedCriterionOperation->new({
        operator => 'ADD',
        operand  => $shared_criterion
      });

    push @shared_criterion_operations, $shared_criterion_operation;
  }

  my $shared_criterion_result =
    $client->SharedCriterionService()
    ->mutate({operations => \@shared_criterion_operations});

  foreach my $shared_criterion (@{$shared_criterion_result->get_value()}) {
    printf "Added shared criterion ID %d '%s' to shared set with ID %d.\n",
      $shared_criterion->get_criterion()->get_id(),
      $shared_criterion->get_criterion()->get_text(),
      $shared_criterion->get_sharedSetId();
  }

  # Attach the negative keyword shared set to the campaign.
  my $campaign_shared_set =
    Google::Ads::AdWords::v201809::CampaignSharedSet->new({
      campaignId  => $campaign_id,
      sharedSetId => $shared_set->get_sharedSetId()});

  my $campaign_shared_set_result = $client->CampaignSharedSetService->mutate({
      operations => [
        Google::Ads::AdWords::v201809::CampaignSharedSetOperation->new({
            operator => 'ADD',
            operand  => $campaign_shared_set
          })]});

  $campaign_shared_set = $campaign_shared_set_result->get_value(0);

  printf "Shared set ID %d was attached to campaign ID %d.\n",
    $campaign_shared_set->get_sharedSetId(),
    $campaign_shared_set->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 => "v201809"});

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

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

Find and remove shared sets and shared set criteria

#!/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 demonstrates how to find and remove shared sets and shared set
# criteria.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201809::CampaignSharedSet;
use Google::Ads::AdWords::v201809::CampaignSharedSetOperation;
use Google::Ads::AdWords::v201809::Criterion;
use Google::Ads::AdWords::v201809::Keyword;
use Google::Ads::AdWords::v201809::OrderBy;
use Google::Ads::AdWords::v201809::Paging;
use Google::Ads::AdWords::v201809::Placement;
use Google::Ads::AdWords::v201809::Predicate;
use Google::Ads::AdWords::v201809::Selector;
use Google::Ads::AdWords::v201809::SharedCriterion;
use Google::Ads::AdWords::v201809::SharedCriterionOperation;
use Google::Ads::AdWords::v201809::SharedSet;
use Google::Ads::AdWords::v201809::SharedSetOperation;
use Google::Ads::AdWords::Utilities::PageProcessor;

use constant PAGE_SIZE => 500;

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

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

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

  # First, retrieve all shared sets associated with the campaign.
  my $paging = Google::Ads::AdWords::v201809::Paging->new({
      startIndex    => 0,
      numberResults => PAGE_SIZE
  });
  my $selector = Google::Ads::AdWords::v201809::Selector->new({
      fields => ["SharedSetId", "CampaignId", "SharedSetName", "SharedSetType"],
      predicates => [
        Google::Ads::AdWords::v201809::Predicate->new({
            field    => "CampaignId",
            operator => "EQUALS",
            values   => [$campaign_id]})
      ],
      paging => $paging
    });

  # Paginate through results and collect the shared set IDs.
  # The subroutine will be executed for each shared set.
  my @shared_set_ids = Google::Ads::AdWords::Utilities::PageProcessor->new({
      client   => $client,
      service  => $client->CampaignSharedSetService(),
      selector => $selector
    }
    )->process_entries(
    sub {
      my ($campaign_shared_set) = @_;
      printf "Campaign shared set ID %d and name '%s' found for " .
        " campaign ID %d.\n",
        $campaign_shared_set->get_sharedSetId(),
        $campaign_shared_set->get_sharedSetName(),
        $campaign_shared_set->get_campaignId();
      return $campaign_shared_set->get_sharedSetId()->get_value();
    });

  if (!@shared_set_ids) {
    printf "No shared sets found for campaign ID %d.\n", $campaign_id;
    return 1;
  }

  # Next, retrieve criterion IDs for all found shared sets.
  $paging = Google::Ads::AdWords::v201809::Paging->new({
      startIndex    => 0,
      numberResults => PAGE_SIZE
  });
  $selector = Google::Ads::AdWords::v201809::Selector->new({
      fields => [
        "SharedSetId", "Id", "KeywordText", "KeywordMatchType", "PlacementUrl"
      ],
      predicates => [
        Google::Ads::AdWords::v201809::Predicate->new({
            field    => "SharedSetId",
            operator => "IN",
            values   => \@shared_set_ids
          })
      ],
      paging => $paging
    });

  my @remove_criterion_operations =
    Google::Ads::AdWords::Utilities::PageProcessor->new({
      client   => $client,
      service  => $client->SharedCriterionService(),
      selector => $selector
    }
    )->process_entries(
    sub {
      my ($shared_criterion) = @_;
      my $criterion = $shared_criterion->get_criterion();
      if ($criterion->isa("Google::Ads::AdWords::v201809::Keyword")) {
        printf "Shared negative keyword with ID %d and text '%s' was " .
          "found.\n",
          $criterion->get_id(),
          $criterion->get_text();
      } elsif ($criterion->isa("Google::Ads::AdWords::v201809::Placement")) {
        printf "Shared negative placement with ID %d and URL '%s' was " .
          "found.\n",
          $criterion->get_id(),
          $criterion->get_url();
      } else {
        printf "Shared criterion with ID %d was found.\n", $criterion->get_id();
      }

      # Create an operation to remove this criterion.
      my $shared_criterion_operation =
        Google::Ads::AdWords::v201809::SharedCriterionOperation->new({
          operator => 'REMOVE',
          operand  => Google::Ads::AdWords::v201809::SharedCriterion->new({
              criterion => Google::Ads::AdWords::v201809::Criterion->new(
                {id => $criterion->get_id()}
              ),
              sharedSetId => $shared_criterion->get_sharedSetId()})});
      return $shared_criterion_operation;
    });

  # Finally, remove the criteria.
  if (@remove_criterion_operations) {
    my $remove_criteria_result =
      $client->SharedCriterionService()
      ->mutate({operations => \@remove_criterion_operations});
    foreach my $removed_criterion (@{$remove_criteria_result->get_value()}) {
      printf "Shared criterion ID %d was successfully removed from shared " .
        "set ID %d.\n",
        $removed_criterion->get_criterion()->get_id(),
        $removed_criterion->get_sharedSetId();
    }
  } else {
    printf "No shared criteria to remove.\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
find_and_remove_criteria_from_shared_set($client, $campaign_id);

Get ad group level bid modifiers

#!/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.
#
# Retrieves all the ad group level bid modifiers of the account.

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

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

use Cwd qw(abs_path);

use constant PAGE_SIZE => 500;

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

  # Create selector.
  my $paging = Google::Ads::AdWords::v201809::Paging->new({
      startIndex    => 0,
      numberResults => PAGE_SIZE
  });
  my $selector = Google::Ads::AdWords::v201809::Selector->new({
      fields => ["CampaignId", "AdGroupId", "BidModifier", "Id"],
      paging => $paging
  });

  # Paginate through results.
  Google::Ads::AdWords::Utilities::PageProcessor->new({
      client   => $client,
      service  => $client->AdGroupBidModifierService(),
      selector => $selector
    }
    )->process_entries(
    sub {
      my ($modifier) = @_;
      my $modifier_value = $modifier->get_bidModifier() || "unset";
      printf "Campaign ID %s, AdGroup ID %s, Criterion ID %s has ad group " .
        "level modifier: %s\n", $modifier->get_campaignId(),
        $modifier->get_adGroupId(), $modifier->get_criterion()->get_id(),
        $modifier_value;
    });

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

Import offline click conversions

#!/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 imports offline conversion values for specific clicks to
# your account. To get Google Click ID for a click, run
# CLICK_PERFORMANCE_REPORT. To set up a conversion tracker, run the
# add_conversion_trackers.pl example.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201809::UploadConversion;
use Google::Ads::AdWords::v201809::ConversionTrackerOperation;
use Google::Ads::AdWords::v201809::OfflineConversionFeed;
use Google::Ads::AdWords::v201809::OfflineConversionFeedOperation;

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

# Replace with valid values of your account.
my $conversion_name             = "INSERT_CONVERSION_NAME_HERE";
my $gclid                       = "INSERT_GCLID_HERE";
my $conversion_time             = "INSERT_CONVERSION_TIME_HERE";
my $conversion_value            = "INSERT_CONVERSION_VALUE_HERE";

# Example main subroutine.
sub upload_offline_conversions {
  my $client                      = shift;
  my $conversion_name             = shift;
  my $gclid                       = shift;
  my $conversion_time             = shift;
  my $conversion_value            = shift;

  my @conversion_tracker_operations = ();
  my @offline_conversion_operations = ();

  # Create an upload conversion. Once created, this entry will be visible
  # under Tools and Analysis->Conversion and will have Source = Import.
  my $upload_conversion = Google::Ads::AdWords::v201809::UploadConversion->new({
    category                  => 'PAGE_VIEW',
    name                      => $conversion_name,
    viewthroughLookbackWindow => 30,
    ctcLookbackWindow         => 90
  });

  my $upload_operation =
    Google::Ads::AdWords::v201809::ConversionTrackerOperation->new({
      operator => "ADD",
      operand  => $upload_conversion
    });

  push @conversion_tracker_operations, $upload_operation;

  # Add the upload conversion.
  my $tracker_result =
    $client->ConversionTrackerService()
    ->mutate({operations => \@conversion_tracker_operations});

  # Display results.
  if ($tracker_result->get_value()) {
    foreach my $conversion_tracker (@{$tracker_result->get_value()}) {
      printf "New upload conversion type with name \"%s\" and ID \"%d\" " .
        "was created.\n",
        $conversion_tracker->get_name(),
        $conversion_tracker->get_id();
    }
  } else {
    print "No upload conversions were added.\n";
    return;
  }

  # Associate offline conversions with the upload conversion we created.
  my $feed = Google::Ads::AdWords::v201809::OfflineConversionFeed->new({
    conversionName            => $conversion_name,
    conversionTime            => $conversion_time,
    conversionValue           => $conversion_value,
    googleClickId             => $gclid,
    # Optional: To upload fractional conversion credits, set the external
    # attribution model and credit. To use this feature, your conversion tracker
    # should be marked as externally attributed. See
    # https://developers.google.com/adwords/api/docs/guides/conversion-tracking#importing_externally_attributed_conversions
    # to learn more about importing externally attributed conversions.
    # externalAttributionModel => "Linear";
    # externalAttributionCredit => 0.3;
  });

  my $offline_conversion_operation =
    Google::Ads::AdWords::v201809::OfflineConversionFeedOperation->new({
      operator => "ADD",
      operand  => $feed
    });

  push @offline_conversion_operations, $offline_conversion_operation;

  # Add the upload conversion.
  my $feed_result =
    $client->OfflineConversionFeedService()
    ->mutate({operations => \@offline_conversion_operations});

  # Display results.
  if ($feed_result->get_value()) {
    foreach my $oc_feed (@{$feed_result->get_value()}) {
      printf "Uploaded offline conversion value of \"%s\" for Google Click " .
        "ID \"%s\" was created.\n",
        $oc_feed->get_conversionName(),
        $oc_feed->get_googleClickId();
    }
  } else {
    print "No offline conversion were added.\n";
    return;
  }

  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
upload_offline_conversions($client, $conversion_name, $gclid, $conversion_time,
  $conversion_value);

Add a portfolio bidding strategy to a campaign

#!/usr/bin/perl -w
#
# Copyright 2017, Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# This example adds a portfolio bidding strategy and uses it to
# construct a campaign.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201809::SharedBiddingStrategy;
use Google::Ads::AdWords::v201809::TargetSpendBiddingScheme;
use Google::Ads::AdWords::v201809::Money;
use Google::Ads::AdWords::v201809::BiddingStrategyOperation;
use Google::Ads::AdWords::v201809::BudgetOperation;
use Google::Ads::AdWords::v201809::NetworkSetting;
use Google::Ads::AdWords::v201809::CampaignOperation;

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

# Replace with valid values of your account.
my $budget_id = 0;

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

  my $biddingStrategy = create_bidding_strategy($client);
  if (!$biddingStrategy) {
    return 0;
  }

  if (!$budget_id) {
    my $budget = create_shared_budget($client);
    if (!$budget) {
      return 0;
    }
    $budget_id = $budget->get_budgetId();
  }

  create_campaign_with_bidding_strategy($client, $biddingStrategy->get_id(),
    $budget_id);

  return 1;
}

# Creates the bidding strategy object.
sub create_bidding_strategy {
  my $client = shift;

  my @operations = ();

  # Create a portfolio bidding strategy.
  my $bidding_strategy =
    Google::Ads::AdWords::v201809::SharedBiddingStrategy->new({
      name => "Maximize Clicks " . uniqid(),
      type => "TARGET_SPEND",

      # Create the bidding scheme.
      biddingScheme =>
        Google::Ads::AdWords::v201809::TargetSpendBiddingScheme->new({
          # Optionally set additional bidding scheme parameters.
          bidCeiling => Google::Ads::AdWords::v201809::Money->new(
            {microAmount => 2000000,}
          ),
          spendTarget => Google::Ads::AdWords::v201809::Money->new(
            {microAmount => 20000000,})})});

  # Create operation.
  my $operation = Google::Ads::AdWords::v201809::BiddingStrategyOperation->new({
      operator => "ADD",
      operand  => $bidding_strategy
  });

  push @operations, $operation;

  my $result =
    $client->BiddingStrategyService()->mutate({operations => \@operations});

  if ($result->get_value()) {
    my $strategy = $result->get_value()->[0];
    printf "Portfolio bidding strategy with name \"%s\" and ID %d of type %s " .
      "was created.\n", $strategy->get_name(), $strategy->get_id(),
      $strategy->get_biddingScheme()->get_BiddingScheme__Type();
    return $strategy;
  } else {
    print "No portfolio bidding strategies were added.\n";
    return 0;
  }
}

# Creates an explicit budget to be used only to create the campaign.
sub create_shared_budget {
  my $client = shift;

  my @operations = ();

  # Create a shared budget operation.
  my $operation = Google::Ads::AdWords::v201809::BudgetOperation->new({
      operator => 'ADD',
      operand  => Google::Ads::AdWords::v201809::Budget->new({
          amount => Google::Ads::AdWords::v201809::Money->new(
            {microAmount => 50000000}
          ),
          deliveryMethod     => 'STANDARD',
          isExplicitlyShared => 0
        })});

  push @operations, $operation;

  # Make the mutate request.
  my $result = $client->BudgetService()->mutate({operations => \@operations});

  if ($result->get_value()) {
    return $result->get_value()->[0];
  } else {
    print "No budgets were added.\n";
    return 0;
  }
}

# Create a campaign with a portfolio bidding strategy.
sub create_campaign_with_bidding_strategy {
  my $client              = shift;
  my $bidding_strategy_id = shift;
  my $budget_id           = shift;

  my @operations = ();

  # Create campaign.
  my $campaign = Google::Ads::AdWords::v201809::Campaign->new({
      name => 'Interplanetary Cruise #' . uniqid(),
      budget =>
        Google::Ads::AdWords::v201809::Budget->new({budgetId => $budget_id}),
      # Set bidding strategy (required).
      biddingStrategyConfiguration =>
        Google::Ads::AdWords::v201809::BiddingStrategyConfiguration->new(
        {biddingStrategyId => $bidding_strategy_id}
        ),
      # Set advertising channel type (required).
      advertisingChannelType => 'SEARCH',
      # Network targeting (recommended).
      networkSetting => Google::Ads::AdWords::v201809::NetworkSetting->new({
          targetGoogleSearch   => 1,
          targetSearchNetwork  => 1,
          targetContentNetwork => 1
        }),
      # 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"
  });

  # Create operation.
  my $operation = Google::Ads::AdWords::v201809::CampaignOperation->new({
      operator => 'ADD',
      operand  => $campaign
  });

  push @operations, $operation;

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

  if ($result->get_value()) {
    my $new_campaign = $result->get_value()->[0];
    printf "Campaign with name \"%s\", ID %d and bidding strategy ID %d was " .
      "created.\n", $new_campaign->get_name(), $new_campaign->get_id(),
      $new_campaign->get_biddingStrategyConfiguration()
      ->get_biddingStrategyId();
    return $new_campaign;
  } else {
    print "No campaigns were added.\n";
    return 0;
  }
}

# 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
use_portfolio_bidding_strategy($client, $budget_id);