—#!/usr/bin/perl -w
#
# Copyright 2021, 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
#
#
# 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.
#
# Uploads an enhanced conversion for leads by uploading a ClickConversion
# with hashed, first-party user-provided data from your website lead forms.
# This includes user identifiers, and optionally a click ID and order ID.
# With this information, Google can tie the conversion to the ad that drove
# the lead.
use
strict;
use
warnings;
use
utf8;
qw(FIRST_PARTY)
;
use
Google::Ads::GoogleAds::V19::Services::ConversionUploadService::ClickConversion;
use
Pod::Usage;
# The following parameter(s) should be provided to run the example. You can
# either specify these by changing the INSERT_XXX_ID_HERE values below, or on
# the command line.
#
# Parameters passed on the command line will override any parameters set in
# code.
#
# Running the example with -h will print the command line usage.
my
$customer_id
=
"INSERT_CUSTOMER_ID_HERE"
;
my
$conversion_action_id
=
"INSERT_CONVERSION_ACTION_ID_HERE"
;
my
$conversion_date_time
=
"INSERT_CONVERSION_DATE_TIME_HERE"
;
my
$conversion_value
=
"INSERT_CONVERSION_VALUE_HERE"
;
# Optional: Specify the unique order ID for the click conversion.
my
$order_id
=
undef
;
# Optional: Specify the Google click ID (gclid) for the click conversion.
my
$gclid
=
undef
;
# Optional: Specify the ad user data consent for the click.
my
$ad_user_data_consent
=
undef
;
sub
upload_enhanced_conversions_for_leads {
my
(
$api_client
,
$customer_id
,
$conversion_action_id
,
$conversion_date_time
,
$conversion_value
,
$order_id
,
$gclid
,
$ad_user_data_consent
)
=
@_
;
# [START add_user_identifiers]
# Create an empty click conversion.
my
$click_conversion
=
Google::Ads::GoogleAds::V19::Services::ConversionUploadService::ClickConversion
->new({});
# Extract user email and phone from the raw data, normalize and hash it,
# then wrap it in UserIdentifier objects. Create a separate UserIdentifier
# object for each.
# The data in this example is hardcoded, but in your application
# you might read the raw data from an input file.
#
# IMPORTANT: Since the identifier attribute of UserIdentifier
# is a oneof
# (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must set
# only ONE of hashed_email, hashed_phone_number, mobile_id, third_party_user_id,
# or address-info. Setting more than one of these attributes on the same UserIdentifier
# will clear all the other members of the oneof. For example, the following code is
# INCORRECT and will result in a UserIdentifier with ONLY a hashed_phone_number:
#
# my $incorrect_user_identifier = Google::Ads::GoogleAds::V19::Common::UserIdentifier->new({
# hashedEmail => '...',
# hashedPhoneNumber => '...',
# });
my
$raw_record
= {
# Email address that includes a period (.) before the Gmail domain.
=>
'alex.2@example.com'
,
# Phone number to be converted to E.164 format, with a leading '+' as
# required.
phone
=>
'+1 800 5550102'
,
# This example lets you input conversion details as arguments,
# but in reality you might store this data alongside other user data,
# so we include it in this sample user record.
orderId
=>
$order_id
,
gclid
=>
$gclid
,
conversionActionId
=>
$conversion_action_id
,
conversionDateTime
=>
$conversion_date_time
,
conversionValue
=>
$conversion_value
,
currencyCode
=>
"USD"
,
adUserDataConsent
=>
$ad_user_data_consent
};
my
$user_identifiers
= [];
# Create a user identifier using the hashed email address, using the normalize
# and hash method specifically for email addresses.
my
$hashed_email
= normalize_and_hash_email_address(
$raw_record
->{email});
push
(
@$user_identifiers
,
Google::Ads::GoogleAds::V19::Common::UserIdentifier->new({
hashedEmail
=>
$hashed_email
,
# Optional: Specify the user identifier source.
userIdentifierSource
=> FIRST_PARTY
}));
# Create a user identifier using normalized and hashed phone info.
my
$hashed_phone
= normalize_and_hash(
$raw_record
->{phone});
push
(
@$user_identifiers
,
Google::Ads::GoogleAds::V19::Common::UserIdentifier->new({
hashedPhone
=>
$hashed_phone
,
# Optional: Specify the user identifier source.
userIdentifierSource
=> FIRST_PARTY
}));
# Add the user identifiers to the conversion.
$click_conversion
->{userIdentifiers} =
$user_identifiers
;
# [END add_user_identifiers]
# [START add_conversion_details]
# Add details of the conversion.
$click_conversion
->{conversionAction} =
Google::Ads::GoogleAds::V19::Utils::ResourceNames::conversion_action(
$customer_id
,
$raw_record
->{conversionActionId});
$click_conversion
->{conversionDateTime} =
$raw_record
->{conversionDateTime};
$click_conversion
->{conversionValue} =
$raw_record
->{conversionValue};
$click_conversion
->{currencyCode} =
$raw_record
->{currencyCode};
# Set the order ID if provided.
if
(
defined
$raw_record
->{orderId}) {
$click_conversion
->{orderId} =
$raw_record
->{orderId};
}
# Set the Google click ID (gclid) if provided.
if
(
defined
$raw_record
->{gclid}) {
$click_conversion
->{gclid} =
$raw_record
->{gclid};
}
# Set the consent information, if provided.
if
(
defined
$raw_record
->{adUserDataConsent}) {
$click_conversion
->{consent} =
Google::Ads::GoogleAds::V19::Common::Consent->new({
adUserData
=>
$raw_record
->{adUserDataConsent}});
}
# [END add_conversion_details]
# [START upload_conversion]
# Upload the click conversion. Partial failure should always be set to true.
#
# NOTE: This request contains a single conversion as a demonstration.
# However, if you have multiple conversions to upload, it's best to
# upload multiple conversions per request instead of sending a separate
# request per conversion. See the following for per-request limits:
my
$response
=
$api_client
->ConversionUploadService()->upload_click_conversions({
customerId
=>
$customer_id
,
conversions
=> [
$click_conversion
],
# Enable partial failure (must be true).
partialFailure
=>
"true"
});
# [END upload_conversion]
# Print any partial errors returned.
# To review the overall health of your recent uploads, see:
if
(
$response
->{partialFailureError}) {
printf
"Partial error encountered: '%s'.\n"
,
$response
->{partialFailureError}{message};
}
# Print the result.
my
$result
=
$response
->{results}[0];
# Only print valid results.
if
(
defined
$result
->{conversionDateTime}) {
printf
"Uploaded conversion that occurred at '%s' to '%s'.\n"
,
$result
->{conversionDateTime},
$result
->{conversionAction};
}
return
1;
}
# Normalizes and hashes a string value.
# Private customer data must be hashed during upload, as described at
# [START normalize_and_hash]
sub
normalize_and_hash {
my
$value
=
shift
;
# Removes leading, trailing, and intermediate spaces.
$value
=~ s/\s+//g;
return
sha256_hex(
lc
$value
);
}
# Returns the result of normalizing and hashing an email address. For this use
# case, Google Ads requires removal of any '.' characters preceding 'gmail.com'
# or 'googlemail.com'.
sub
normalize_and_hash_email_address {
my
$email_address
=
shift
;
my
$normalized_email
=
lc
$email_address
;
my
@email_parts
=
split
(
'@'
,
$normalized_email
);
if
(
scalar
@email_parts
> 1
&&
$email_parts
[1] =~ /^(gmail|googlemail)\.com\s*/)
{
# Remove any '.' characters from the portion of the email address before the
# domain if the domain is 'gmail.com' or 'googlemail.com'.
$email_parts
[0] =~ s/\.//g;
$normalized_email
=
sprintf
'%s@%s'
,
$email_parts
[0],
$email_parts
[1];
}
return
normalize_and_hash(
$normalized_email
);
}
# [END normalize_and_hash]
# Don't run the example if the file is being included.
if
(abs_path($0) ne abs_path(__FILE__)) {
return
1;
}
# Get Google Ads Client, credentials will be read from ~/googleads.properties.
my
$api_client
= Google::Ads::GoogleAds::Client->new();
# By default examples are set to die on any server returned fault.
$api_client
->set_die_on_faults(1);
# Parameters passed on the command line will override any parameters set in code.
GetOptions(
"customer_id=s"
=> \
$customer_id
,
"conversion_action_id=i"
=> \
$conversion_action_id
,
"conversion_date_time=s"
=> \
$conversion_date_time
,
"conversion_value=f"
=> \
$conversion_value
,
"order_id=s"
=> \
$order_id
,
"gclid=s"
=> \
$gclid
,
"ad_user_data_consent=s"
=> \
$ad_user_data_consent
,
);
# Print the help message if the parameters are not initialized in the code nor
# in the command line.
pod2usage(2)
if
not check_params(
$customer_id
,
$conversion_action_id
,
$conversion_date_time
,
$conversion_value
);
# Call the example.
upload_enhanced_conversions_for_leads(
$api_client
,
$customer_id
=~ s/-//gr,
$conversion_action_id
,
$conversion_date_time
,
$conversion_value
,
$order_id
,
$gclid
,
$ad_user_data_consent
);
=pod
=head1 NAME
upload_enhanced_conversions_for_leads
=head1 DESCRIPTION
Uploads an enhanced conversion for leads by uploading a ClickConversion
with hashed, first-party user-provided data from your website lead forms.
=head1 SYNOPSIS
upload_enhanced_conversions_for_leads.pl [options]
-help Show the help message.
-customer_id The Google Ads customer ID.
-conversion_action_id The conversion action ID associated with this conversion.
-conversion_date_time The date time at which the conversion occurred.
Must be after the click time, and must include the time zone offset.
The format is 'yyyy-mm-dd hh:mm:ss+|-hh:mm', e.g. '2019-01-01 12:32:45-08:00'.
-conversion_value The value of the conversion.
-order_id [optional] The unique ID (transaction ID) of the conversion. We recommend including if available.
-gclid [optional] The Google click ID associated with the conversion. We recommend including if available.
-ad_user_data_consent [optional] The ad user data consent for the click.
=cut