Remarketing Samples

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

Create a remarketing user list (audience)

#!/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 remarketing user list (a.k.a. Audience) and shows its
# associated conversion tracker code snippet.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201806::Predicate;
use Google::Ads::AdWords::v201806::BasicUserList;
use Google::Ads::AdWords::v201806::Selector;
use Google::Ads::AdWords::v201806::UserListConversionType;
use Google::Ads::AdWords::v201806::UserListOperation;

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

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

  # Create conversion type (tag).
  my $name = "Mars cruise customers #" . uniqid();

  my $conversion_type =
    Google::Ads::AdWords::v201806::UserListConversionType->new({name => $name});

  # Create remarketing user list.
  my $user_list = Google::Ads::AdWords::v201806::BasicUserList->new({
      name            => $name,
      conversionTypes => [$conversion_type],
      # Additional properties (non-required).
      description        => "A list of mars cruise customers in the last year",
      membershipLifeSpan => 365,
      status             => "OPEN"
  });

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

  # Add user list.
  my $result =
    $client->AdwordsUserListService()->mutate({operations => [$operation]});

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

    # Due to a bug in the service we need to retrieve the conversion trackers
    # info in a separate request after a few seconds.
    sleep(5);
    my $predicate = Google::Ads::AdWords::v201806::Predicate->new({
        field    => "Id",
        operator => "IN",
        values   => [$user_list->get_id()->get_value()]});
    my $selector = Google::Ads::AdWords::v201806::Selector->new({
        fields     => ["ConversionTypes"],
        predicates => [$predicate]});
    my $conversion_trackers_page =
      $client->AdwordsUserListService()->get({serviceSelector => $selector});

    # Get associated conversion snippets.
    my $conversion_id =
      $conversion_trackers_page->get_entries()->[0]->get_conversionTypes()->[0]
      ->get_id()->get_value();

    # Create selector.
    my $conversion_type_predicate =
      Google::Ads::AdWords::v201806::Predicate->new({
        field    => "Id",
        operator => "IN",
        values   => [$conversion_id]});
    $selector = Google::Ads::AdWords::v201806::Selector->new({
        fields     => ["Id", "GoogleGlobalSiteTag", "GoogleEventSnippet"],
        predicates => [$conversion_type_predicate]});

    # Get all conversion trackers.
    my $page =
      $client->ConversionTrackerService()->get({serviceSelector => $selector});

    my $conversion_tracker = $page->get_entries()->[0];

    # Display results.
    printf "User list with name \"%s\" and id \"%d\" was added.\n",
      $user_list->get_name(), $user_list->get_id();
    printf("Google global site tag:\n%s\n\n",
      $conversion_tracker->get_googleGlobalSiteTag());
    printf("Google event snippet:\n%s\n\n",
      $conversion_tracker->get_googleEventSnippet());
  } else {
    print "No user list was added.";
  }

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

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

# Call the example
add_audience($client);

Create an AdWords conversion tracker and add to it upload 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 adds an AdWords conversion tracker and an upload conversion
# tracker.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201806::AdWordsConversionTracker;
use Google::Ads::AdWords::v201806::ConversionTrackerOperation;
use Google::Ads::AdWords::v201806::UploadConversion;

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

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

  my @conversion_trackers = ();

  # Create AdWords conversion tracker.
  my $adwords_conversion_tracker =
    Google::Ads::AdWords::v201806::AdWordsConversionTracker->new({
      name => "Earth to Mars Cruises Conversion #" . uniqid(),
      # Additional properties (non-required).
      status                               => "ENABLED",
      category                             => "DEFAULT",
      viewthroughLookbackWindow            => 15,
      defaultRevenueValue                  => 23.41,
      alwaysUseDefaultRevenueValue         => 1
    });
  push @conversion_trackers, $adwords_conversion_tracker;

  # Create an upload conversion for offline conversion imports.
  my $upload_conversion_tracker =
    Google::Ads::AdWords::v201806::UploadConversion->new({
      # Set an appropriate category. This field is optional, and will be set to
      # DEFAULT if not mentioned.
      category                             => "LEAD",
      name                                 => "Upload Conversion #" . uniqid(),
      viewthroughLookbackWindow            => 30,
      ctcLookbackWindow                    => 90,
      # Optional: Set the default currency code to use for conversions
      # that do not specify a conversion currency. This must be an ISO 4217
      # 3-character currency code such as "EUR" or "USD".
      # If this field is not set on this UploadConversion, AdWords will use
      # the account's currency.
      defaultRevenueCurrencyCode => "EUR",
      # Optional: Set the default revenue value to use for conversions
      # that do not specify a conversion value. Note that this value
      # should NOT be in micros.
      defaultRevenueValue => 2.50,
      # Optional: To upload fractional conversion credits, mark the upload conversion
      # 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.
      # isExternallyAttributed => true
    });
  push @conversion_trackers, $upload_conversion_tracker;

  my @operations = ();
  for my $conversion_tracker (@conversion_trackers) {
    # Create operation.
    my $conversion_operation =
      Google::Ads::AdWords::v201806::ConversionTrackerOperation->new({
        operator => "ADD",
        operand  => $conversion_tracker
      });
    push @operations, $conversion_operation;
  }

  # Add conversion trackers.
  my $result =
    $client->ConversionTrackerService()
    ->mutate({operations => \@operations});

  # Display conversion tracker.
  if ($result->get_value()) {
    foreach my $conversion_tracker (@{$result->get_value()}) {
      printf "Conversion tracker with ID %d, name \"%s\", status \"%s\" " .
        "and category \"%s\" was added.\n", $conversion_tracker->get_id(),
        $conversion_tracker->get_name(), $conversion_tracker->get_status(),
        $conversion_tracker->get_category();
      if ($conversion_tracker
        ->isa("Google::Ads::AdWords::v201806::AdWordsConversionTracker")) {
        printf("Google global site tag:\n%s\n\n",
          $conversion_tracker->get_googleGlobalSiteTag());
        printf("Google event snippet:\n%s\n\n",
          $conversion_tracker->get_googleEventSnippet());
      }
    }
  } else {
    print "No conversion tracker was added.";
  }

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

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

# Call the example
add_conversion_trackers($client);

Create and populate a user list

#!/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 user list (a.k.a. audience) and uploads members
# to populate the list.
#
# Note: It may take up to several hours for the list to be populated
# with members. Email addresses must be associated with a Google account.
# For privacy purposes, the user list size will show as zero until the list
# has at least 1000 members. After that, the size will be rounded to the
# two most significant digits.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201806::AddressInfo;
use Google::Ads::AdWords::v201806::CrmBasedUserList;
use Google::Ads::AdWords::v201806::Member;
use Google::Ads::AdWords::v201806::MutateMembersOperand;
use Google::Ads::AdWords::v201806::MutateMembersOperation;
use Google::Ads::AdWords::v201806::UserListOperation;

use Cwd qw(abs_path);
use Data::Uniqid qw(uniqid);
use Digest::SHA qw(sha256_hex);

sub add_crm_based_user_list {
  my $client = shift;

  # Create a user list.
  my $user_list = Google::Ads::AdWords::v201806::CrmBasedUserList->new({
    name        => "Customer relationship management list #" . uniqid(),
    description => "A list of customers that originated from email addresses",
    # CRM-based user lists can use a membershipLifeSpan of 10000 to indicate
    # unlimited; otherwise normal values apply.
    membershipLifeSpan => "30",
    uploadKeyType => "CONTACT_INFO"
  });

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

  # Add user list.
  my $result =
    $client->AdwordsUserListService()->mutate({operations => [$operation]});

  # Display user list.
  if ($result->get_value()) {
    my $user_list_added = $result->get_value()->[0];
    printf(
      "User list with name '%s' and ID '%d' was added.\n",
      $user_list_added->get_name(),
      $user_list_added->get_id());
  }

  my @members = ();
  # Add e-mails to the user list.
  if ($result->get_value()) {
    # Use SHA256 to encode the e-mails.
    # All e-mails MUST be trimmed and lower-cased before encoding.
    my @email_list = (
      'customer1@example.com', 'customer2@example.com',
      ' Customer3@example.com '
    );
    foreach my $email (@email_list) {
      $email = sha256_hex(_to_normalized_string($email));
      my $member = Google::Ads::AdWords::v201806::Member->new({
        hashedEmail => $email
      });
      push @members, $member;
    }

    my $first_name   = "John";
    my $last_name    = "Doe";
    my $country_code = "US";
    my $zip_code     = "10011";

    my $address_info = Google::Ads::AdWords::v201806::AddressInfo->new({
      # First and last name must be normalized and hashed.
      hashedFirstName => sha256_hex(_to_normalized_string($first_name)),
      hashedLastName  => sha256_hex(_to_normalized_string($last_name)),
      # Country code and zip code are sent in plaintext.
      countryCode => $country_code,
      zipCode     => $zip_code
    });

    my $member_by_address = Google::Ads::AdWords::v201806::Member->new({
      addressInfo => $address_info
    });
    push @members, $member_by_address;

    my $userlist_id = $result->get_value()->[0]->get_id();
    my $operand     = Google::Ads::AdWords::v201806::MutateMembersOperand->new({
      userListId => $userlist_id,
      membersList => \@members
    });

    my $member_operation =
      Google::Ads::AdWords::v201806::MutateMembersOperation->new({
        operator => "ADD",
        operand  => $operand
      });

    # Add members to the user list based on email addresses.
    my $result =
      $client->AdwordsUserListService()
      ->mutateMembers({operations => [$member_operation]});

    # Display results.
    # Reminder: it may take up to 9 hours for the list to be populated
    # with members.
    for $user_list ($result->get_userLists()) {
      printf(
        "%d email addresses were uploaded to user list with name '%s' " .
          "and ID '%d' and are scheduled for review.\n",
        scalar(@email_list), $user_list->get_name(),
        $user_list->get_id());
    }

  } else {
    print "No user list was added.";
  }

  return 1;
}

sub _to_normalized_string {
  my ($input_string) = @_;
  $input_string =~ s/^\s+|\s+$//g;
  $input_string = lc $input_string;
  return $input_string;
}

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

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

# Call the example
add_crm_based_user_list($client);

Create rule-based user lists

#!/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 two rule-based remarketing user lists: one with no site
# visit date restrictions, and another that will only include users who visit
# your site in the next six months.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201806::BasicUserList;
use Google::Ads::AdWords::v201806::CombinedRuleUserList;
use Google::Ads::AdWords::v201806::DateKey;
use Google::Ads::AdWords::v201806::DateRuleItem;
use Google::Ads::AdWords::v201806::DateSpecificRuleUserList;
use Google::Ads::AdWords::v201806::ExpressionRuleUserList;
use Google::Ads::AdWords::v201806::NumberKey;
use Google::Ads::AdWords::v201806::NumberRuleItem;
use Google::Ads::AdWords::v201806::Operator;
use Google::Ads::AdWords::v201806::Rule;
use Google::Ads::AdWords::v201806::RuleItem;
use Google::Ads::AdWords::v201806::RuleItemGroup;
use Google::Ads::AdWords::v201806::StringKey;
use Google::Ads::AdWords::v201806::StringRuleItem;
use Google::Ads::AdWords::v201806::UserListOperation;

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

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

  # First rule item group - users who visited the checkout page and had more
  # than one item in their shopping cart.
  my $checkout_string_rule_item =
    Google::Ads::AdWords::v201806::StringRuleItem->new({
      key => Google::Ads::AdWords::v201806::StringKey->new(
        {name => "ecomm_pagetype"}
      ),
      op    => "EQUALS",
      value => "checkout"
    });
  my $checkout_rule_item = Google::Ads::AdWords::v201806::RuleItem->new(
    {StringRuleItem => $checkout_string_rule_item});

  my $cart_size_number_rule_item =
    Google::Ads::AdWords::v201806::NumberRuleItem->new({
      key =>
        Google::Ads::AdWords::v201806::NumberKey->new({name => "cartsize"}),
      op    => "GREATER_THAN",
      value => "1"
    });
  my $cart_size_rule_item = Google::Ads::AdWords::v201806::RuleItem->new(
    {NumberRuleItem => $cart_size_number_rule_item});

  # Combine the two rule items into a RuleItemGroup so AdWords will AND their
  # rules together.
  my $checkout_multiple_item_group =
    Google::Ads::AdWords::v201806::RuleItemGroup->new(
    {items => [$checkout_rule_item, $cart_size_rule_item]});

  # Second rule item group - users who check out during the next three months.
  my ($sec, $min, $hour, $mday, $mon, $year) = localtime();
  my $rule_start_date =
    sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);
  ($sec, $min, $hour, $mday, $mon, $year) =
    localtime(time + 60 * 60 * 24 * 30 * 3);
  my $rule_end_date = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);

  my $start_date_date_rule_item =
    Google::Ads::AdWords::v201806::DateRuleItem->new({
      key =>
        Google::Ads::AdWords::v201806::DateKey->new({name => "checkoutdate"}),
      op    => "AFTER",
      value => $rule_start_date
    });

  my $start_date_rule_item = Google::Ads::AdWords::v201806::RuleItem->new(
    {DateRuleItem => $start_date_date_rule_item});

  my $end_date_date_rule_item =
    Google::Ads::AdWords::v201806::DateRuleItem->new({
      key =>
        Google::Ads::AdWords::v201806::DateKey->new({name => "checkoutdate"}),
      op    => "BEFORE",
      value => $rule_end_date
    });

  my $end_date_rule_item = Google::Ads::AdWords::v201806::RuleItem->new(
    {DateRuleItem => $end_date_date_rule_item});

  # Combine the date rule items into a RuleItemGroup.
  my $checked_out_next_three_months_item_group =
    Google::Ads::AdWords::v201806::RuleItemGroup->new(
    {items => [$start_date_rule_item, $end_date_rule_item]});

  # Combine the rule item groups into a Rule so AdWords knows how to apply the
  # rules.
  my $rule = Google::Ads::AdWords::v201806::Rule->new({
      groups => [
        $checkout_multiple_item_group, $checked_out_next_three_months_item_group
      ],
      # ExpressionRuleUserLists can use either CNF or DNF for matching. CNF
      # means 'at least one item in each rule item group must match', and DNF
      # means 'at least one entire rule item group must match'.
      # DateSpecificRuleUserList only supports DNF. You can also omit the rule
      # type altogether to default to DNF.
      ruleType => 'DNF'
    });

  # Third and fourth rule item groups
  # Visitors of a page who visited another page.
  my $site1_string_rule_item =
    Google::Ads::AdWords::v201806::StringRuleItem->new({
      key => Google::Ads::AdWords::v201806::StringKey->new(
        {name => "url__"}
      ),
      op    => "EQUALS",
      value => "example.com/example1"
    });
  my $site1_rule_item = Google::Ads::AdWords::v201806::RuleItem->new(
    {StringRuleItem => $site1_string_rule_item});
  my $site2_string_rule_item =
    Google::Ads::AdWords::v201806::StringRuleItem->new({
      key => Google::Ads::AdWords::v201806::StringKey->new(
        {name => "url__"}
      ),
      op    => "EQUALS",
      value => "example.com/example2"
    });
  my $site2_rule_item = Google::Ads::AdWords::v201806::RuleItem->new(
    {StringRuleItem => $site2_string_rule_item});

  # Create two RuleItemGroups to show that a visitor browsed two sites.
  my $site1_item_group = Google::Ads::AdWords::v201806::RuleItemGroup->new(
    {items => [$site1_rule_item]});
  my $site2_item_group = Google::Ads::AdWords::v201806::RuleItemGroup->new(
    {items => [$site2_rule_item]});

  # Create two rules to show that a visitor browsed two sites.
  my $user_visited_site1_rule = Google::Ads::AdWords::v201806::Rule->new({
      groups => [$site1_item_group]
    });
  my $user_visited_site2_rule = Google::Ads::AdWords::v201806::Rule->new({
      groups => [$site2_item_group]
    });

  # Create the user list with no restrictions on site visit date.
  ($sec, $min, $hour, $mday, $mon, $year) = localtime();
  my $creation_time = sprintf(
    "%d%02d%02d_%02d%02d%02d",
    ($year + 1900),
    ($mon + 1),
    $mday, $hour, $min, $sec
  );
  my $expression_user_list =
    Google::Ads::AdWords::v201806::ExpressionRuleUserList->new({
      name        => "Expression based user list created at ${creation_time}",
      description => "Users who checked out in six month window OR " .
        "visited the checkout page with more than one item in their cart",
      rule => $rule,
      # Optional: Set the prepopulationStatus to REQUESTED to include past
      # users in the user list.
      prepopulationStatus => "REQUESTED"
    });

  # Create the user list restricted to users who visit your site within the
  # next six months.
  ($sec, $min, $hour, $mday, $mon, $year) = localtime();
  my $list_start_date =
    sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);
  ($sec, $min, $hour, $mday, $mon, $year) =
    localtime(time + 60 * 60 * 24 * 30 * 6);
  my $list_end_date = sprintf("%d%02d%02d", ($year + 1900), ($mon + 1), $mday);

  my $date_user_list =
    Google::Ads::AdWords::v201806::DateSpecificRuleUserList->new({
      name        => "Date rule user list created at ${creation_time}",
      description => "Users who visited the site between " .
        "${list_start_date} and ${list_end_date} and checked out " .
        "in three month window OR visited the checkout page with " .
        "more than one item in their cart.",
      rule      => $rule,
      startDate => $list_start_date,
      endDate   => $list_end_date
    });

  # Create the user list where "Visitors of a page who did visit another page".
  # To create a user list where "Visitors of a page who did not visit another
  # page", change the ruleOperator from AND to AND_NOT.
  my $combined_user_list =
    Google::Ads::AdWords::v201806::CombinedRuleUserList->new({
      name         => "Combined rule user list created at ${creation_time}",
      description  => "Users who visited two sites.",
      leftOperand  => $user_visited_site1_rule,
      rightOperand => $user_visited_site2_rule,
      ruleOperator => "AND"
    });

  # Create operations to add the user lists.
  my $operations = [
    Google::Ads::AdWords::v201806::UserListOperation->new({
        operator => "ADD",
        operand  => $expression_user_list
      }
    ),
    Google::Ads::AdWords::v201806::UserListOperation->new({
        operator => "ADD",
        operand  => $date_user_list
      }
    ),
    Google::Ads::AdWords::v201806::UserListOperation->new({
        operator => "ADD",
        operand  => $combined_user_list
      })];

  # Submit the operations.
  my $result =
    $client->AdwordsUserListService()->mutate({operations => $operations});

  if ($result->get_value()) {
    foreach my $user_list (@{$result->get_value}) {
      printf "User list added with ID %d, name '%s', status '%s', list " .
        "type '%s', accountUserListStatus '%s', description '%s'.\n",
        $user_list->get_id(),     $user_list->get_name(),
        $user_list->get_status(), $user_list->get_listType(),
        $user_list->get_accountUserListStatus(),
        $user_list->get_description();
    }
  } else {
    print "No user list was added.";
  }

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

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

# Call the example
add_rule_based_user_lists($client);

Import conversion adjustments for existing conversions

#!/usr/bin/perl -w
#
# Copyright 2018 Google LLC
#
# 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
#
#        https://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 conversion adjustments for conversions that already
# exist. To set up a conversion tracker, run the add_conversion_tracker.pl
# example.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201806::GclidOfflineConversionAdjustmentFeed;
use Google::Ads::AdWords::v201806::OfflineConversionAdjustmentFeedOperation;

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 $adjustment_type     = "INSERT_ADJUSTMENT_TYPE_HERE";
my $conversion_time     = "INSERT_CONVERSION_TIME_HERE";
my $adjustment_time     = "INSERT_ADJUSTMENT_TIME_HERE";
my $adjusted_value      = "INSERT_ADJUST_VALUE_HERE";

# Example main subroutine.
sub upload_conversion_adjustment {
  my ($client, $conversion_name, $gclid, $adjustment_type,
      $conversion_time, $adjustment_time, $adjusted_value) = @_;
  # This example demonstrates adjusting one conversion, but you can add more
  # than one operation to adjust more in a single mutate request.
  my @conversion_adjustment_operations = ();

  # Associate conversion adjustments with the existing named conversion
  # tracker. The GCLID should have been uploaded before with a conversion.
  my $feed =
      Google::Ads::AdWords::v201806::GclidOfflineConversionAdjustmentFeed->new({
      conversionName  => $conversion_name,
      adjustmentType  => $adjustment_type,
      conversionTime  => $conversion_time,
      adjustmentTime  => $adjustment_time,
      adjustedValue   => $adjusted_value,
      googleClickId   => $gclid,
  });

  my $conversion_adjustment_operation =
    Google::Ads::AdWords::v201806::OfflineConversionAdjustmentFeedOperation->new({
      operator => "ADD",
      operand  => $feed
    });

  push @conversion_adjustment_operations, $conversion_adjustment_operation;

  # Add the conversion adjustment.
  my $result =
    $client->OfflineConversionAdjustmentFeedService()
    ->mutate({operations => \@conversion_adjustment_operations});

  # Display results.
  if ($result->get_value()) {
    foreach my $adjustment_feed (@{$result->get_value()}) {
      printf "Uploaded conversion adjusted value of \"%s\" for Google Click " .
        "ID \"%s\"\n",
        $adjustment_feed->get_adjustedValue(),
        $adjustment_feed->get_googleClickId();
    }
  } else {
    print "No conversion adjustments 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 => "v201806"});

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

# Call the example
upload_conversion_adjustment($client, $conversion_name, $gclid,
    $adjustment_type, $conversion_time, $adjustment_time, $adjusted_value);

Import offline call 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 call conversion values for calls
# related to the ads in your account. To set up a conversion tracker, run the
# add_conversion_tracker.pl example using UploadCallConversion as the
# conversion tracker.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201806::OfflineCallConversionFeed;
use Google::Ads::AdWords::v201806::OfflineCallConversionFeedOperation;

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

# Replace with valid values of your account.
my $caller_id        = "INSERT_CALLER_ID_HERE";
# For times use the format yyyyMMdd HHmmss tz. For more details on formats,
# see: https://developers.google.com/adwords/api/docs/appendix/codes-formats#date-and-time-formats
# For time zones, see: https://developers.google.com/adwords/api/docs/appendix/codes-formats#timezone-ids
my $call_start_time  = "INSERT_CALL_START_TIME_HERE";
my $conversion_name  = "INSERT_CONVERSION_NAME_HERE";
my $conversion_time  = "INSERT_CONVERSION_TIME_HERE";
my $conversion_value = "INSERT_CONVERSION_VALUE_HERE";

# Example main subroutine.
sub upload_offline_call_conversions {
  my $client                             = shift;
  my $caller_id                          = shift;
  my $call_start_time                    = shift;
  my $conversion_name                    = shift;
  my $conversion_time                    = shift;
  my $conversion_value                   = shift;
  my @offline_call_conversion_operations = ();

  # Associate offline call conversions with the existing named
  # conversion tracker. If this tracker was newly created, it may be a
  # few hours before it can accept conversions.
  my $feed = Google::Ads::AdWords::v201806::OfflineCallConversionFeed->new({
    callerId        => $caller_id,
    callStartTime   => $call_start_time,
    conversionName  => $conversion_name,
    conversionTime  => $conversion_time,
    conversionValue => $conversion_value
  });

  my $offline_call_conversion_operation =
    Google::Ads::AdWords::v201806::OfflineCallConversionFeedOperation->new({
      operator => "ADD",
      operand  => $feed
    });

  push @offline_call_conversion_operations, $offline_call_conversion_operation;

  # This example uploads only one call conversion, but you can upload multiple
  # call conversions by passing additional operations.
  my $result =
    $client->OfflineCallConversionFeedService()
    ->mutate({operations => \@offline_call_conversion_operations});

  # Display results.
  if ($result->get_value()) {
    foreach my $feed_result (@{$result->get_value()}) {
      printf "Uploaded offline call conversion value of \"%s\" for caller ID " .
        "\"%s\".\n",
        $feed_result->get_conversionValue(),
        $feed_result->get_callerId();
    }
  } else {
    print "No offline call conversions 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 => "v201806"});

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

# Call the example
upload_offline_call_conversions($client, $caller_id, $call_start_time,
  $conversion_name, $conversion_time, $conversion_value);

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 call conversion values for calls 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_tracker.pl example.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201806::UploadConversion;
use Google::Ads::AdWords::v201806::ConversionTrackerOperation;
use Google::Ads::AdWords::v201806::OfflineCallConversionFeed;
use Google::Ads::AdWords::v201806::OfflineCallConversionFeedOperation;

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 @offline_conversion_operations = ();

  # Associate offline conversions with the existing named conversion tracker. If
  # this tracker was newly created, it may be a few hours before it can accept
  # conversions.
  my $feed = Google::Ads::AdWords::v201806::OfflineCallConversionFeed->new({
      conversionName  => $conversion_name,
      conversionTime  => $conversion_time,
      conversionValue => $conversion_value,
      googleClickId   => $gclid
  });

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

  push @offline_conversion_operations, $offline_conversion_operation;

  # Add the upload conversion.
  my $feed_result =
    $client->OfflineCallConversionFeedService()
    ->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 => "v201806"});

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

Upload offline data for store sales transactions

#!/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 shows how to upload offline data for store sales
# transactions.

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

use Google::Ads::AdWords::Client;
use Google::Ads::AdWords::Logging;
use Google::Ads::AdWords::v201806::ConversionTrackerOperation;
use Google::Ads::AdWords::v201806::FirstPartyUploadMetadata;
use Google::Ads::AdWords::v201806::Money;
use Google::Ads::AdWords::v201806::MoneyWithCurrency;
use Google::Ads::AdWords::v201806::OfflineCallConversionFeed;
use Google::Ads::AdWords::v201806::OfflineCallConversionFeedOperation;
use Google::Ads::AdWords::v201806::OfflineData;
use Google::Ads::AdWords::v201806::OfflineDataUploadOperation;
use Google::Ads::AdWords::v201806::StoreSalesTransaction;
use Google::Ads::AdWords::v201806::ThirdPartyUploadMetadata;
use Google::Ads::AdWords::v201806::UploadConversion;
use Google::Ads::AdWords::v201806::UploadMetadata;
use Google::Ads::AdWords::v201806::UserIdentifier;

use Cwd qw(abs_path);
use Data::Uniqid qw(uniqid);
use Digest::SHA qw(sha256_hex);

# Replace with valid values of your account.
# The external upload ID can be any number that you use to keep track of your
# uploads.
my $external_upload_id = 'INSERT_EXTERNAL_UPLOAD_ID';
# Insert the conversion type name that you'd like to attribute this upload to.
my $conversion_name = 'INSERT_CONVERSION_NAME';

# Change the below constant to ThirdPartyUploadMetadata if uploading third
# party data.
my $store_sales_upload_common_metadata_type = "FirstPartyUploadMetadata";
# Insert email addresses below for creating user identifiers.
my @email_addresses = ("EMAIL_ADDRESS_1", "EMAIL_ADDRESS_2");
# The three constants below are needed when uploading third party data.
# You can safely ignore them if you are uploading first party data.
# For times, use the format yyyyMMdd HHmmss tz. For more details on formats,
# see:
# https://developers.google.com/adwords/api/docs/appendix/codes-formats#date-and-time-formats
# For time zones, see:
# https://developers.google.com/adwords/api/docs/appendix/codes-formats#timezone-ids
my $advertiser_upload_time = "INSERT_ADVERTISER_UPLOAD_TIME";
my $bridge_map_version_id  = "INSERT_BRIDGE_MAP_VERSION_ID";
my $partner_id             = "INSERT_PARTNER_ID";

# Example main subroutine.
sub upload_offline_data {
  my (
    $client,                $external_upload_id,
    $conversion_name,       $store_sales_upload_common_metadata_type,
    $email_addresses,       $advertiser_upload_time,
    $bridge_map_version_id, $partner_id
  ) = @_;

  # Create the first offline data for upload.
  # This transaction occurred 7 days ago with amount of 200 USD.
  my ($second, $minute, $hour, $mday, $mon, $year) =
    localtime(time - 60 * 60 * 24 * 7);
  my $transaction_time_1 = sprintf(
    "%d%02d%02d %02d%02d%02d",
    ($year + 1900),
    ($mon + 1),
    $mday, $hour, $minute, $second
  );
  my $transaction_amount_1        = 200000000;
  my $transaction_currency_code_1 = 'USD';
  my $user_identifier_list_1      = [
    _create_user_identifier('HASHED_EMAIL', $email_addresses->[0]),
    _create_user_identifier('STATE',        'New York')];

  my $offline_data_1 = _create_offline_data(
    $transaction_time_1,          $transaction_amount_1,
    $transaction_currency_code_1, $conversion_name,
    $user_identifier_list_1
  );

  # Create the second offline data for upload.
  # This transaction occurred 14 days ago with amount of 450 EUR.
  ($second, $minute, $hour, $mday, $mon, $year) =
    localtime(time - 60 * 60 * 24 * 14);
  my $transaction_time_2 = sprintf(
    "%d%02d%02d %02d%02d%02d",
    ($year + 1900),
    ($mon + 1),
    $mday, $hour, $minute, $second
  );
  my $transaction_amount_2        = 450000000;
  my $transaction_currency_code_2 = 'EUR';
  my $user_identifier_list_2      = [
    _create_user_identifier('HASHED_EMAIL', $email_addresses->[1]),
    _create_user_identifier('STATE',        'California')];

  my $offline_data_2 = _create_offline_data(
    $transaction_time_2,          $transaction_amount_2,
    $transaction_currency_code_2, $conversion_name,
    $user_identifier_list_2
  );

  # Create offline data upload object.
  my $offline_data_upload = undef;
  if ($store_sales_upload_common_metadata_type eq 'FirstPartyUploadMetadata') {
    $offline_data_upload =
      Google::Ads::AdWords::v201806::OfflineDataUpload->new({
        externalUploadId => $external_upload_id,
        offlineDataList  => [$offline_data_1, $offline_data_2],
        uploadType       => 'STORE_SALES_UPLOAD_FIRST_PARTY',
        uploadMetadata   => Google::Ads::AdWords::v201806::UploadMetadata->new({
            StoreSalesUploadCommonMetadata =>
              Google::Ads::AdWords::v201806::FirstPartyUploadMetadata->new({
                loyaltyRate           => "1.0",
                transactionUploadRate => "1.0",
              })
        })
      });
  } elsif (
    $store_sales_upload_common_metadata_type eq 'ThirdPartyUploadMetadata')
  {
    $offline_data_upload =
      Google::Ads::AdWords::v201806::OfflineDataUpload->new({
        externalUploadId => $external_upload_id,
        offlineDataList  => [$offline_data_1, $offline_data_2],
        # Set the type and metadata of this upload.
        uploadType     => 'STORE_SALES_UPLOAD_THIRD_PARTY',
        uploadMetadata => Google::Ads::AdWords::v201806::UploadMetadata->new({
            StoreSalesUploadCommonMetadata =>
              Google::Ads::AdWords::v201806::ThirdPartyUploadMetadata->new({
                loyaltyRate           => "1.0",
                transactionUploadRate => "1.0",
                advertiserUploadTime  => $advertiser_upload_time,
                validTransactionRate  => "1.0",
                partnerMatchRate      => "1.0",
                partnerUploadRate     => "1.0",
                bridgeMapVersionId    => $bridge_map_version_id,
                partnerId             => $partner_id
              })
        })
      });
  }

  # Create an offline data upload operation.
  my @operations = ();
  my $offline_data_upload_operation =
    Google::Ads::AdWords::v201806::OfflineDataUploadOperation->new({
      operator => 'ADD',
      operand  => $offline_data_upload
    });
  push @operations, $offline_data_upload_operation;

  # Upload offline data on the server and print some information.
  my $result =
    $client->OfflineDataUploadService()->mutate({operations => \@operations});
  $offline_data_upload = $result->get_value()->[0];

  printf(
    "Uploaded offline data with external upload ID %d and upload status" .
      " %s\n",
    $offline_data_upload->get_externalUploadId(),
    $offline_data_upload->get_uploadStatus());

  # Print any partial failure errors from the response.
  if ($result->get_partialFailureErrors()) {
    foreach my $api_error (@{$result->get_partialFailureErrors()}) {
      # Get the index of the failed operation from the error's field path
      # elements.
      my $operation_index =
        _get_field_path_element_index($api_error, "operations");
      if (defined($operation_index)) {
        my $failed_offline_data_upload =
          $operations[$operation_index]->get_operand();
        # Get the index of the entry in the offline data list from the error's
        # field path elements.
        my $offline_data_list_index =
          _get_field_path_element_index($api_error, "offlineDataList");
        printf("Offline data list entry %d in operation %d with external"
          . " upload ID %d and type \"%s\" has triggered a failure for the "
          . " following reason: \"%s\".\n",
          $offline_data_list_index,
          $operation_index,
          $offline_data_upload->get_externalUploadId(),
          $offline_data_upload->get_uploadType(),
          $api_error->get_errorString());
      } else {
        printf "A failure for the following reason: \"%s\" has occurred.\n",
          $api_error->get_errorString();
      }
    }
  }
  return 1;
}

# Returns the FieldPathElement#getIndex() for the specified field name, if
# present in the error's field path elements.
sub _get_field_path_element_index {
  my ($api_error, $field) = @_;

  my $field_path_elements = $api_error->get_fieldPathElements();
  if (!$field_path_elements) {
    return;
  }
  for (my $i = 0 ; $i < scalar $field_path_elements; $i++) {
    my $field_path_element = $field_path_elements->[$i];
    if ($field eq $field_path_element->get_field()) {
      return $field_path_element->get_index();
    }
  }
  return;
}

# Creates the offline data from the specified transaction time, transaction
# micro amount, transaction currency, conversion name and user identifier
# list.
sub _create_offline_data {
  my (
    $transaction_time,     $transaction_micro_amount,
    $transaction_currency, $conversion_name,
    $user_identifier_list
  ) = @_;
  my $store_sales_transaction =
    Google::Ads::AdWords::v201806::StoreSalesTransaction->new({
      conversionName => $conversion_name,
      # For times use the format yyyyMMdd HHmmss [tz].
      # For details, see
      # https://developers.google.com/adwords/api/docs/appendix/codes-formats#date-and-time-formats
      transactionTime => $transaction_time,
      userIdentifiers => $user_identifier_list,
      transactionAmount =>
        Google::Ads::AdWords::v201806::MoneyWithCurrency->new({
          currencyCode => $transaction_currency,
          money        => Google::Ads::AdWords::v201806::Money->new(
            {microAmount => $transaction_micro_amount})})});
  # There is a temporary issue with the WSDL in which there is a
  # namespace conflict. As a workaround, the namespace is explicitly set here.
  $Google::Ads::AdWords::v201806::MoneyWithCurrency::OBJECT_NAMESPACE =
    "https://adwords.google.com/api/adwords/rm/v201806";

  my $offline_data = Google::Ads::AdWords::v201806::OfflineData->new({
    StoreSalesTransaction => $store_sales_transaction
  });
  return $offline_data;
}

# Creates a user identifier from the specified type and value.
sub _create_user_identifier {
  my ($type, $value) = @_;
  # If the user identifier type is a hashed type, also call hash function
  # on the value.
  if ($type =~ /^HASHED_/) {
    $value = sha256_hex($value);
  }

  my $user_identifier = Google::Ads::AdWords::v201806::UserIdentifier->new({
    userIdentifierType => $type,
    value              => $value
  });

  return $user_identifier;
}

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

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

# Setting partial failures to true as this example show how to handle them.
$client->set_partial_failure(1);

# Call the example
upload_offline_data(
  $client,                $external_upload_id,
  $conversion_name,       $store_sales_upload_common_metadata_type,
  \@email_addresses,      $advertiser_upload_time,
  $bridge_map_version_id, $partner_id
);

Send feedback about...

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