Skip to content

Commit

Permalink
V15: Rename and update enhanced conversions examples
Browse files Browse the repository at this point in the history
  • Loading branch information
danielfrg committed Oct 20, 2023
1 parent 8028a89 commit 59556e8
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 40 deletions.
5 changes: 5 additions & 0 deletions examples/remarketing/upload_call_conversion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ def upload_call_conversion(
# Issues a request to upload the call conversion.
response = client.service.conversion_upload.upload_call_conversions(
customer_id: customer_id,
# 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:
# https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
conversions: [call_conversion],
partial_failure: true
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,66 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Uploads a conversion using hashed email address instead of GCLID.
# Uploads an enhanced conversion for leads by uploading a ClickConversion.
# The click conversion has 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.

require 'optparse'
require 'google/ads/google_ads'

# [START upload_conversion_with_identifiers]
def upload_conversion_with_identifiers(
customer_id,
conversion_action_id,
email_address,
conversion_date_time,
conversion_value,
order_id)
order_id,
gclid,
ad_user_data_consent)
# GoogleAdsClient will read a config file from
# ENV['HOME']/google_ads_config.rb when called without parameters
client = Google::Ads::GoogleAds::GoogleAdsClient.new

# [START create_conversion]
# [START add_user_identifiers]
# 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
# (https://developers.google.com/google-ads/api/reference/rpc/latest/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:
#
# incorrectly_populated_user_identifier.hashed_email = "...""
# incorrectly_populated_user_identifier.hashed_phone_number = "...""

raw_record = {
# Email address that includes a period (.) before the Gmail domain.
"email" => "[email protected]",
# 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.
"order_id" => order_id,
"gclid" => gclid,
"conversion_action_id" => conversion_action_id,
"conversion_date_time" => conversion_date_time,
"conversion_value" => conversion_value,
"currency_code" => "USD",
"ad_user_data_consent" => ad_user_data_consent,
}

click_conversion = client.resource.click_conversion do |cc|
# [START add_conversion_details]
cc.conversion_action = client.path.conversion_action(customer_id, conversion_action_id)
cc.conversion_date_time = conversion_date_time
cc.conversion_value = conversion_value.to_f
Expand All @@ -43,16 +84,38 @@ def upload_conversion_with_identifiers(
cc.order_id = order_id
end

unless raw_record[:gclid].nil?
cc.gclid = gclid
end

# Specifies whether user consent was obtained for the data you are
# uploading. For more details, see:
# https://www.google.com/about/company/user-consent-policy
unless raw_record[:ad_user_data_consent].nil?
# cc.consent.ad_user_data = client.enums.ConsentStatusEnum[
# raw_record["ad_user_data_consent"]
# ]
end
# [END add_conversion_details]

# Creates a user identifier using the hashed email address, using the
# normalize and hash method specifically for email addresses.
# If using a phone number, use the normalize_and_hash method instead.
cc.user_identifiers << client.resource.user_identifier do |id|
id.hashed_email = normalize_and_hash_email(email_address)
cc.user_identifiers << client.resource.user_identifier do |ui|
ui.hashed_phone_number = normalize_and_hash_email(raw_record["email"])
# Optional: Specifies the user identifier source.
id.user_identifier_source = :FIRST_PARTY
ui.user_identifier_source = :FIRST_PARTY
end

# Checks if the record has a phone number, and if so, adds a UserIdentifier
# for it.
unless raw_record["phone"].nil?
cc.user_identifiers << client.resource.user_identifier do |ui|
ui.hashed_phone_number = normalize_and_hash_email(raw_record["phone"])
end
end
end
# [END create_conversion]
# [END add_user_identifiers]

response = client.service.conversion_upload.upload_click_conversions(
customer_id: customer_id,
Expand All @@ -69,7 +132,6 @@ def upload_conversion_with_identifiers(
"to #{result.conversion_action}."
end
end
# [END upload_conversion_with_identifiers]

# [START normalize_and_hash]
# Returns the result of normalizing and then hashing the string using the
Expand Down Expand Up @@ -111,6 +173,8 @@ def normalize_and_hash_email(email)
options[:conversion_date_time] = 'INSERT_CONVERSION_DATE_TIME_HERE'
options[:conversion_value] = 'INSERT_CONVERSION_VALUE_HERE'
options[:order_id] = nil
options[:gclid] = 'INSERT_GCLID_HERE'
options[:ad_user_data_consent] = 'INSERT_AD_USER_DATA_CONSENT_ENUM_HERE'

OptionParser.new do |opts|
opts.banner = sprintf('Usage: %s [options]', File.basename(__FILE__))
Expand All @@ -126,10 +190,6 @@ def normalize_and_hash_email(email)
options[:conversion_action_id] = v
end

opts.on('-e', '--email-address EMAIL-ADDRESS', String, 'Email address') do |v|
options[:email_address] = v
end

opts.on('-t', '--conversion-date-time CONVERSION-DATE-TIME', String,
'The date and time of the conversion (should be after click time). ' \
'The format is "yyyy-mm-dd hh:mm:ss+|-hh:mm", ' \
Expand All @@ -145,6 +205,16 @@ def normalize_and_hash_email(email)
options[:order_id] = v
end

opts.on('-g', '--gclid GCLID', String, 'The Google click ID (gclid) for the click') do |v|
options[:gclid] = v
end

opts.on('-d', '--ad-user-data-dconsent GCLID', String,
'The data consent status for ad user data for all members in' \
'the job.') do |v|
options[:ad_user_data_consent] = v
end

opts.separator ''
opts.separator 'Help:'

Expand All @@ -158,10 +228,11 @@ def normalize_and_hash_email(email)
upload_conversion_with_identifiers(
options.fetch(:customer_id).tr("-", ""),
options.fetch(:conversion_action_id),
options.fetch(:email_address),
options.fetch(:conversion_date_time),
options.fetch(:conversion_value),
options[:order_id],
options[:gclid],
options[:ad_user_data_consent],
)
rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e
e.failure.errors.each do |error|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Adjusts an existing conversion by supplying user identifiers so Google can
# enhance the conversion value.
# Enhances a web conversion by uploading a ConversionAdjustment.
# The conversion adjustment contains hashed user identifiers and an order ID.

require 'optparse'
require 'google/ads/google_ads'
require 'digest'

# [START upload_conversion_enhancement]
def upload_conversion_enhancement(
customer_id,
conversion_action_id,
Expand All @@ -33,8 +32,49 @@ def upload_conversion_enhancement(
# ENV['HOME']/google_ads_config.rb when called without parameters
client = Google::Ads::GoogleAds::GoogleAdsClient.new

# [START create_adjustment]
# [START add_user_identifiers]
# Extracts user email, phone, and address info from the raw data, normalizes
# and hashes it, then wraps it in UserIdentifier objects. Creates 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
# (https://developers.google.com/google-ads/api/reference/rpc/latest/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:
#
# incorrectly_populated_user_identifier.hashed_email = "...""
# incorrectly_populated_user_identifier.hashed_phone_number = "...""

raw_record = {
# Email address that includes a period (.) before the Gmail domain.
"email" => "[email protected]",
# Address that includes all four required elements: first name, last
# name, country code, and postal code.
"first_name" => "Alex",
"last_name" => "Quinn",
"country_code" => "US",
"postal_code" => "94045",
# 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.
"order_id" => order_id,
"conversion_action_id" => conversion_action_id,
"conversion_date_time" => conversion_date_time,
"currency_code" => "USD",
"user_agent" => user_agent,
}

enhancement = client.resource.conversion_adjustment do |ca|
# [START add_conversion_details]
ca.conversion_action = client.path.conversion_action(customer_id, conversion_action_id)
ca.adjustment_type = :ENHANCEMENT
ca.order_id = order_id
Expand All @@ -47,30 +87,52 @@ def upload_conversion_enhancement(
end
end

# Creates a user identifier using sample values for the user address.
# Creates a user identifier using the hashed email address, using the
# normalize and hash method specifically for email addresses.
ca.user_identifiers << client.resource.user_identifier do |ui|
ui.address_info = client.resource.offline_user_address_info do |info|
# Certain fields must be hashed using SHA256 in order to handle
# identifiers in a privacy-safe way, as described at
# https://support.google.com/google-ads/answer/9888656.
info.hashed_first_name = normalize_and_hash("Joanna")
info.hashed_last_name = normalize_and_hash("Smith")
info.hashed_street_address = normalize_and_hash("1600 Amphitheatre Pkwy")
info.city = "Mountain View"
info.state = "CA"
info.postal_code = "94043"
info.country_code = "US"
end
# Uses the normalize and hash method specifically for email addresses.
ui.hashed_email = normalize_and_hash_email(raw_record["email"])
# Optional: Specifies the user identifier source.
ui.user_identifier_source = :FIRST_PARTY
end

# Creates a user identifier using the hashed email address.
ca.user_identifiers << client.resource.user_identifier do |ui|
# Uses the normalize and hash method specifically for email addresses.
ui.hashed_email = normalize_and_hash_email("[email protected]")
ui.user_identifier_source = :FIRST_PARTY
# Checks if the record has a phone number, and if so, adds a UserIdentifier
# for it.
unless raw_record["phone"].nil?
ca.user_identifiers << client.resource.user_identifier do |ui|
ui.hashed_phone_number = normalize_and_hash_email(raw_record["phone"])
end
end

# Checks if the record has all the required mailing address elements, and if
# so, adds a UserIdentifier for the mailing address.
unless raw_record["first_name"].nil?
# Checks if the record contains all the other required elements of a
# mailing address.
required_keys = ["last_name", "country_code", "postal_code"]
# Builds a new list of the required keys that are missing from
# raw_record.
missing_keys = required_keys - raw_record.keys
if missing_keys
puts(
"Skipping addition of mailing address information because the" \
"following required keys are missing: #{missing_keys}"
)
else
ca.user_identifiers << client.resource.user_identifier do |ui|
ui.address_info = client.resource.offline_user_address_info do |info|
# Certain fields must be hashed using SHA256 in order to handle
# identifiers in a privacy-safe way, as described at
# https://support.google.com/google-ads/answer/9888656.
info.hashed_first_name = normalize_and_hash( raw_record["first_name"])
info.hashed_last_name = normalize_and_hash( raw_record["last_name"])
info.postal_code = normalize_and_hash(raw_record["country_code"])
info.country_code = normalize_and_hash(raw_record["postal_code"])
end
end
end
end
# [END add_user_identifiers]

# Sets optional fields where a value was provided.
unless user_agent.nil?
Expand All @@ -80,16 +142,25 @@ def upload_conversion_enhancement(
# cross-device.
ca.user_agent = user_agent
end
# [END add_conversion_details]
end
# [END create_adjustment]

# [START upload_enhancement]
response = client.service.conversion_adjustment_upload.upload_conversion_adjustments(
customer_id: customer_id,
# NOTE: This request only uploads a single conversion, but if you have
# multiple conversions to upload, it's still best to upload them in a single
# request. See the following for per-request limits for reference:
# https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
conversion_adjustments: [enhancement],
# Partial failure must be set to true.
partial_failure: true,
)
# [END upload_enhancement]

# Prints any partial errors returned.
# To review the overall health of your recent uploads, see:
# https://developers.google.com/google-ads/api/docs/conversions/upload-summaries
if response.partial_failure_error
puts "Partial failure encountered: #{response.partial_failure_error.message}."
else
Expand All @@ -98,12 +169,11 @@ def upload_conversion_enhancement(
"order ID #{result.order_id}."
end
end
# [END upload_conversion_enhancement]

# [START normalize_and_hash]
# Returns the result of normalizing and then hashing the string using the
# provided digest. Private customer data must be hashed during upload, as
# described at https://support.google.com/google-ads/answer/7474263.
# described at https://support.google.com/google-ads/answer/9888656.
def normalize_and_hash(str)
# Remove leading and trailing whitespace and ensure all letters are lowercase
# before hasing.
Expand Down
5 changes: 5 additions & 0 deletions examples/remarketing/upload_offline_conversion.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ def upload_offline_conversion(

response = client.service.conversion_upload.upload_click_conversions(
customer_id: customer_id,
# 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:
# https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
conversions: [click_conversion],
partial_failure: true,
)
Expand Down

0 comments on commit 59556e8

Please sign in to comment.