Джава
// 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
//
// 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.
package com.google.ads.googleads.examples.remarketing;
import com.beust.jcommander.Parameter;
import com.google.ads.googleads.examples.utils.ArgumentNames;
import com.google.ads.googleads.examples.utils.CodeSampleParams;
import com.google.ads.googleads.lib.GoogleAdsClient;
import com.google.ads.googleads.v13.common.OfflineUserAddressInfo;
import com.google.ads.googleads.v13.common.UserIdentifier;
import com.google.ads.googleads.v13.enums.ConversionAdjustmentTypeEnum.ConversionAdjustmentType;
import com.google.ads.googleads.v13.enums.UserIdentifierSourceEnum.UserIdentifierSource;
import com.google.ads.googleads.v13.errors.GoogleAdsError;
import com.google.ads.googleads.v13.errors.GoogleAdsException;
import com.google.ads.googleads.v13.services.ConversionAdjustment;
import com.google.ads.googleads.v13.services.ConversionAdjustmentResult;
import com.google.ads.googleads.v13.services.ConversionAdjustmentUploadServiceClient;
import com.google.ads.googleads.v13.services.GclidDateTimePair;
import com.google.ads.googleads.v13.services.UploadConversionAdjustmentsRequest;
import com.google.ads.googleads.v13.services.UploadConversionAdjustmentsResponse;
import com.google.ads.googleads.v13.utils.ResourceNames;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Adjusts an existing conversion by supplying user identifiers so Google can enhance the conversion
* value.
*/
public class UploadConversionEnhancement {
private static class UploadConversionEnhancementParams extends CodeSampleParams {
@Parameter(names = ArgumentNames.CUSTOMER_ID, required = true)
private long customerId;
@Parameter(names = ArgumentNames.CONVERSION_ACTION_ID, required = true)
private long conversionActionId;
@Parameter(names = ArgumentNames.ORDER_ID, required = true)
private String orderId;
@Parameter(
names = ArgumentNames.CONVERSION_DATE_TIME,
required = false,
description =
"The date time at which the conversion with the specified order ID 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'. "
+ "Setting this field is optional, but recommended.")
private String conversionDateTime;
@Parameter(names = ArgumentNames.USER_AGENT, required = false)
private String userAgent;
}
public static void main(String[] args)
throws UnsupportedEncodingException, NoSuchAlgorithmException {
UploadConversionEnhancementParams params = new UploadConversionEnhancementParams();
if (!params.parseArguments(args)) {
// Either pass the required parameters for this example on the command line, or insert them
// into the code here. See the parameter class definition above for descriptions.
params.customerId = Long.parseLong("INSERT_CUSTOMER_ID_HERE");
params.conversionActionId = Long.parseLong("INSERT_CONVERSION_ACTION_ID_HERE");
params.orderId = "INSERT_ORDER_ID_HERE";
// Optional: Specify the conversion date/time and user agent.
params.conversionDateTime = null;
params.userAgent = null;
}
GoogleAdsClient googleAdsClient = null;
try {
googleAdsClient = GoogleAdsClient.newBuilder().fromPropertiesFile().build();
} catch (FileNotFoundException fnfe) {
System.err.printf(
"Failed to load GoogleAdsClient configuration from file. Exception: %s%n", fnfe);
System.exit(1);
} catch (IOException ioe) {
System.err.printf("Failed to create GoogleAdsClient. Exception: %s%n", ioe);
System.exit(1);
}
try {
new UploadConversionEnhancement()
.runExample(
googleAdsClient,
params.customerId,
params.conversionActionId,
params.orderId,
params.conversionDateTime,
params.userAgent);
} catch (GoogleAdsException gae) {
// GoogleAdsException is the base class for most exceptions thrown by an API request.
// Instances of this exception have a message and a GoogleAdsFailure that contains a
// collection of GoogleAdsErrors that indicate the underlying causes of the
// GoogleAdsException.
System.err.printf(
"Request ID %s failed due to GoogleAdsException. Underlying errors:%n",
gae.getRequestId());
int i = 0;
for (GoogleAdsError googleAdsError : gae.getGoogleAdsFailure().getErrorsList()) {
System.err.printf(" Error %d: %s%n", i++, googleAdsError);
}
System.exit(1);
}
}
/**
* Runs the example.
*
* @param googleAdsClient the Google Ads API client.
* @param customerId the client customer ID.
* @param conversionActionId conversion action ID associated with this conversion.
* @param orderId unique order ID (transaction ID) of the conversion.
* @param conversionDateTime
* @param userAgent the HTTP user agent of the conversion.
*/
private void runExample(
GoogleAdsClient googleAdsClient,
long customerId,
long conversionActionId,
String orderId,
String conversionDateTime,
String userAgent)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
// Creates a builder for constructing the enhancement adjustment.
ConversionAdjustment.Builder enhancementBuilder =
ConversionAdjustment.newBuilder()
.setConversionAction(ResourceNames.conversionAction(customerId, conversionActionId))
.setAdjustmentType(ConversionAdjustmentType.ENHANCEMENT)
// Enhancements MUST use order ID instead of GCLID date/time pair.
.setOrderId(orderId);
// Sets the conversion date and time if provided. Providing this value is optional but
// recommended.
if (conversionDateTime != null) {
enhancementBuilder.setGclidDateTimePair(
GclidDateTimePair.newBuilder().setConversionDateTime(conversionDateTime));
}
// Creates a SHA256 message digest for hashing user identifiers in a privacy-safe way, as
// described at https://support.google.com/google-ads/answer/9888656.
MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256");
// Adds user identifiers, hashing where required.
// Creates a user identifier using sample values for the user address.
UserIdentifier addressIdentifier =
UserIdentifier.newBuilder()
.setAddressInfo(
OfflineUserAddressInfo.newBuilder()
.setHashedFirstName(normalizeAndHash(sha256Digest, "Joanna"))
.setHashedLastName(normalizeAndHash(sha256Digest, "Smith"))
.setHashedStreetAddress(
normalizeAndHash(sha256Digest, "1600 Amphitheatre Pkwy"))
.setCity("Mountain View")
.setState("CA")
.setPostalCode("94043")
.setCountryCode("US"))
// Optional: Specifies the user identifier source.
.setUserIdentifierSource(UserIdentifierSource.FIRST_PARTY)
.build();
// Creates a user identifier using the hashed email address.
UserIdentifier emailIdentifier =
UserIdentifier.newBuilder()
.setUserIdentifierSource(UserIdentifierSource.FIRST_PARTY)
// Uses the normalize and hash method specifically for email addresses.
.setHashedEmail(normalizeAndHashEmailAddress(sha256Digest, "joannasmith@example.com"))
.build();
// Adds the user identifiers to the enhancement adjustment.
enhancementBuilder.addUserIdentifiers(addressIdentifier).addUserIdentifiers(emailIdentifier);
// Sets optional fields where a value was provided.
if (userAgent != null) {
// Sets the user agent. This should match the user agent of the request that sent the original
// conversion so the conversion and its enhancement are either both attributed as same-device
// or both attributed as cross-device.
enhancementBuilder.setUserAgent(userAgent);
}
// Creates the conversion upload service client.
try (ConversionAdjustmentUploadServiceClient conversionUploadServiceClient =
googleAdsClient.getLatestVersion().createConversionAdjustmentUploadServiceClient()) {
// Uploads the enhancement adjustment. Partial failure should always be set to true.
UploadConversionAdjustmentsResponse response =
conversionUploadServiceClient.uploadConversionAdjustments(
UploadConversionAdjustmentsRequest.newBuilder()
.setCustomerId(Long.toString(customerId))
.addConversionAdjustments(enhancementBuilder)
// Enables partial failure (must be true).
.setPartialFailure(true)
.build());
// Prints any partial errors returned.
if (response.hasPartialFailureError()) {
System.out.printf(
"Partial error encountered: '%s'.%n", response.getPartialFailureError().getMessage());
} else {
// Prints the result.
ConversionAdjustmentResult result = response.getResults(0);
System.out.printf(
"Uploaded conversion adjustment of '%s' for order ID '%s'.%n",
result.getConversionAction(), result.getOrderId());
}
}
}
/**
* 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.
*
* @param digest the digest to use to hash the normalized string.
* @param s the string to normalize and hash.
*/
private String normalizeAndHash(MessageDigest digest, String s)
throws UnsupportedEncodingException {
// Normalizes by removing leading and trailing whitespace and converting all characters to
// lower case.
String normalized = s.trim().toLowerCase();
// Hashes the normalized string using the hashing algorithm.
byte[] hash = digest.digest(normalized.getBytes("UTF-8"));
StringBuilder result = new StringBuilder();
for (byte b : hash) {
result.append(String.format("%02x", b));
}
return result.toString();
}
/**
* Returns the result of normalizing and hashing an email address. For this use case, Google Ads
* requires removal of any '.' characters preceding {@code gmail.com} or {@code googlemail.com}.
*
* @param digest the digest to use to hash the normalized string.
* @param emailAddress the email address to normalize and hash.
*/
private String normalizeAndHashEmailAddress(MessageDigest digest, String emailAddress)
throws UnsupportedEncodingException {
String normalizedEmail = emailAddress.toLowerCase();
String[] emailParts = normalizedEmail.split("@");
if (emailParts.length > 1 && emailParts[1].matches("^(gmail|googlemail)\\.com\\s*")) {
// Removes any '.' characters from the portion of the email address before the domain if the
// domain is gmail.com or googlemail.com.
emailParts[0] = emailParts[0].replaceAll("\\.", "");
normalizedEmail = String.format("%s@%s", emailParts[0], emailParts[1]);
}
return normalizeAndHash(digest, normalizedEmail);
}
}
С#
// 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
//
// 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.
using CommandLine;
using Google.Ads.Gax.Examples;
using Google.Ads.GoogleAds.Lib;
using Google.Ads.GoogleAds.V13.Common;
using Google.Ads.GoogleAds.V13.Errors;
using Google.Ads.GoogleAds.V13.Services;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using static Google.Ads.GoogleAds.V13.Enums.ConversionAdjustmentTypeEnum.Types;
using static Google.Ads.GoogleAds.V13.Enums.UserIdentifierSourceEnum.Types;
namespace Google.Ads.GoogleAds.Examples.V13
{
/// <summary>
/// This code example adjusts an existing conversion by supplying user identifiers so
/// Google can enhance the conversion value.
/// </summary>
public class UploadConversionEnhancement : ExampleBase
{
/// <summary>
/// Command line options for running the <see cref="UploadConversionEnhancement"/> example.
/// </summary>
public class Options : OptionsBase
{
/// <summary>
/// The Google Ads customer ID for which the conversion action is added.
/// </summary>
[Option("customerId", Required = true, HelpText =
"The Google Ads customer ID for which the conversion action is added.")]
public long CustomerId { get; set; }
/// <summary>
/// ID of the conversion action for which adjustments are uploaded.
/// </summary>
[Option("conversionActionId", Required = true, HelpText =
"ID of the conversion action for which adjustments are uploaded.")]
public long ConversionActionId { get; set; }
/// <summary>
/// The unique order ID (transaction ID) of the conversion.
/// </summary>
[Option("orderId", Required = true, HelpText =
"The unique order ID (transaction ID) of the conversion.")]
public string OrderId { get; set; }
/// <summary>
/// The date time at which the conversion with the specified order ID 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'. Setting this
/// field is optional, but recommended.
/// </summary>
[Option("conversionDateTime", Required = false, HelpText =
"The date time at which the conversion with the specified order ID 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'. " +
"Setting this field is optional, but recommended.")]
public string ConversionDateTime { get; set; }
/// <summary>
/// The HTTP user agent of the conversion.
/// </summary>
[Option("userAgent", Required = true, HelpText =
"The HTTP user agent of the conversion.")]
public string UserAgent { get; set; }
/// <summary>
/// The restatement value.
/// </summary>
[Option("restatementValue", Required = true, HelpText = "The restatement value.")]
public double? RestatementValue { get; set; }
/// <summary>
/// The currency of the restatement value.
/// </summary>
[Option("currencyCode", Required = false, HelpText =
"The currency of the restatement value.")]
public string CurrencyCode { get; set; }
}
/// <summary>
/// Main method, to run this code example as a standalone application.
/// </summary>
/// <param name="args">The command line arguments.</param>
public static void Main(string[] args)
{
Options options = ExampleUtilities.ParseCommandLine<Options>(args);
UploadConversionEnhancement codeExample = new UploadConversionEnhancement();
Console.WriteLine(codeExample.Description);
codeExample.Run(new GoogleAdsClient(), options.CustomerId, options.ConversionActionId,
options.OrderId, options.ConversionDateTime, options.UserAgent,
options.RestatementValue, options.CurrencyCode);
}
private static SHA256 digest = SHA256.Create();
/// <summary>
/// Returns a description about the code example.
/// </summary>
public override string Description =>
"This code example adjusts an existing conversion by supplying user identifiers so " +
"Google can enhance the conversion value.";
/// <summary>
/// Runs the code example.
/// </summary>
/// <param name="client">The Google Ads client.</param>
/// <param name="customerId">The Google Ads customer ID for which the conversion
/// enhancement is uploaded.</param>
/// <param name="conversionActionId">ID of the conversion action for which adjustments are
/// uploaded.</param>
/// <param name="orderId">The unique order ID (transaction ID) of the conversion.</param>
/// <param name="conversionDateTime">The date time at which the conversion with the
/// specified order ID occurred.</param>
/// <param name="userAgent">The HTTP user agent of the conversion.</param>
/// <param name="restatementValue">The restatement value.</param>
/// <param name="restatementCurrencyCode">The currency of the restatement value.</param>
public void Run(GoogleAdsClient client, long customerId, long conversionActionId,
string orderId, string conversionDateTime, string userAgent, double? restatementValue,
string restatementCurrencyCode)
{
// Get the ConversionAdjustmentUploadService.
ConversionAdjustmentUploadServiceClient conversionAdjustmentUploadService =
client.GetService(Services.V13.ConversionAdjustmentUploadService);
// Creates the enhancement adjustment.
ConversionAdjustment enhancement = new ConversionAdjustment()
{
ConversionAction = ResourceNames.ConversionAction(customerId, conversionActionId),
AdjustmentType = ConversionAdjustmentType.Enhancement,
// Enhancements MUST use order ID instead of GCLID date/time pair.
OrderId = orderId
};
// Sets the conversion date and time if provided. Providing this value is optional but
// recommended.
if (string.IsNullOrEmpty(conversionDateTime))
{
enhancement.GclidDateTimePair = new GclidDateTimePair()
{
ConversionDateTime = conversionDateTime
};
}
// Adds user identifiers, hashing where required.
// Creates a user identifier using sample values for the user address.
UserIdentifier addressIdentifier = new UserIdentifier()
{
AddressInfo = new OfflineUserAddressInfo()
{
HashedFirstName = NormalizeAndHash("Joanna"),
HashedLastName = NormalizeAndHash("Smith"),
HashedStreetAddress = NormalizeAndHash("1600 Amphitheatre Pkwy"),
City = "Mountain View",
State = "CA",
PostalCode = "94043",
CountryCode = "US"
},
// Optional: Specifies the user identifier source.
UserIdentifierSource = UserIdentifierSource.FirstParty
};
// Creates a user identifier using the hashed email address.
UserIdentifier emailIdentifier = new UserIdentifier()
{
UserIdentifierSource = UserIdentifierSource.FirstParty,
// Uses the normalize and hash method specifically for email addresses.
HashedEmail = NormalizeAndHashEmailAddress("joannasmith@example.com")
};
// Adds the user identifiers to the enhancement adjustment.
enhancement.UserIdentifiers.AddRange(new[] { addressIdentifier, emailIdentifier });
// Sets optional fields where a value was provided.
if (!string.IsNullOrEmpty(userAgent))
{
// Sets the user agent. This should match the user agent of the request that
// sent the original conversion so the conversion and its enhancement are either
// both attributed as same-device or both attributed as cross-device.
enhancement.UserAgent = userAgent;
}
if (restatementValue != null)
{
enhancement.RestatementValue = new RestatementValue()
{
// Sets the new value of the conversion.
AdjustedValue = restatementValue.Value
};
// Sets the currency of the new value, if provided. Otherwise, the default currency
// from the conversion action is used, and if that is not set then the account
// currency is used.
if (restatementCurrencyCode != null)
{
enhancement.RestatementValue.CurrencyCode = restatementCurrencyCode;
}
}
try
{
// Uploads the enhancement adjustment. Partial failure should always be set to true.
UploadConversionAdjustmentsResponse response =
conversionAdjustmentUploadService.UploadConversionAdjustments(
new UploadConversionAdjustmentsRequest()
{
CustomerId = customerId.ToString(),
ConversionAdjustments = { enhancement },
// Enables partial failure (must be true).
PartialFailure = true,
});
// Prints the status message if any partial failure error is returned.
// Note: The details of each partial failure error are not printed here,
// you can refer to the example HandlePartialFailure.cs to learn more.
if (response.PartialFailureError != null)
{
// Extracts the partial failure from the response status.
GoogleAdsFailure partialFailure = response.PartialFailure;
Console.WriteLine($"{partialFailure.Errors.Count} partial failure error(s) " +
$"occurred");
}
else
{
// Prints the result.
ConversionAdjustmentResult result = response.Results[0];
Console.WriteLine($"Uploaded conversion adjustment of " +
$"'{result.ConversionAction}' for order ID '{result.OrderId}'.");
}
}
catch (GoogleAdsException e)
{
Console.WriteLine("Failure:");
Console.WriteLine($"Message: {e.Message}");
Console.WriteLine($"Failure: {e.Failure}");
Console.WriteLine($"Request ID: {e.RequestId}");
throw;
}
}
/// <summary>
/// Normalizes the email address and hashes it. For this use case, Google Ads requires
/// removal of any '.' characters preceding <code>gmail.com</code> or
/// <code>googlemail.com</code>.
/// </summary>
/// <param name="emailAddress">The email address.</param>
/// <returns>The hash code.</returns>
private string NormalizeAndHashEmailAddress(string emailAddress)
{
string normalizedEmail = emailAddress.ToLower();
string[] emailParts = normalizedEmail.Split('@');
if (emailParts.Length > 1 && (emailParts[1] == "gmail.com" ||
emailParts[1] == "googlemail.com"))
{
// Removes any '.' characters from the portion of the email address before
// the domain if the domain is gmail.com or googlemail.com.
emailParts[0] = emailParts[0].Replace(".", "");
normalizedEmail = $"{emailParts[0]}@{emailParts[1]}";
}
return NormalizeAndHash(normalizedEmail);
}
/// <summary>
/// Normalizes and hashes a string value.
/// </summary>
/// <param name="value">The value to normalize and hash.</param>
/// <returns>The normalized and hashed value.</returns>
private static string NormalizeAndHash(string value)
{
return ToSha256String(digest, ToNormalizedValue(value));
}
/// <summary>
/// Hash a string value using SHA-256 hashing algorithm.
/// </summary>
/// <param name="digest">Provides the algorithm for SHA-256.</param>
/// <param name="value">The string value (e.g. an email address) to hash.</param>
/// <returns>The hashed value.</returns>
private static string ToSha256String(SHA256 digest, string value)
{
byte[] digestBytes = digest.ComputeHash(Encoding.UTF8.GetBytes(value));
// Convert the byte array into an unhyphenated hexadecimal string.
return BitConverter.ToString(digestBytes).Replace("-", string.Empty);
}
/// <summary>
/// Removes leading and trailing whitespace and converts all characters to
/// lower case.
/// </summary>
/// <param name="value">The value to normalize.</param>
/// <returns>The normalized value.</returns>
private static string ToNormalizedValue(string value)
{
return value.Trim().ToLower();
}
}
}
PHP
<?php
/**
* 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
*
* 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.
*/
namespace Google\Ads\GoogleAds\Examples\Remarketing;
require __DIR__ . '/../../vendor/autoload.php';
use GetOpt\GetOpt;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentNames;
use Google\Ads\GoogleAds\Examples\Utils\ArgumentParser;
use Google\Ads\GoogleAds\Lib\OAuth2TokenBuilder;
use Google\Ads\GoogleAds\Lib\V13\GoogleAdsClient;
use Google\Ads\GoogleAds\Lib\V13\GoogleAdsClientBuilder;
use Google\Ads\GoogleAds\Lib\V13\GoogleAdsException;
use Google\Ads\GoogleAds\Util\V13\ResourceNames;
use Google\Ads\GoogleAds\V13\Common\OfflineUserAddressInfo;
use Google\Ads\GoogleAds\V13\Common\UserIdentifier;
use Google\Ads\GoogleAds\V13\Enums\ConversionAdjustmentTypeEnum\ConversionAdjustmentType;
use Google\Ads\GoogleAds\V13\Enums\UserIdentifierSourceEnum\UserIdentifierSource;
use Google\Ads\GoogleAds\V13\Errors\GoogleAdsError;
use Google\Ads\GoogleAds\V13\Services\ConversionAdjustment;
use Google\Ads\GoogleAds\V13\Services\ConversionAdjustmentResult;
use Google\Ads\GoogleAds\V13\Services\GclidDateTimePair;
use Google\ApiCore\ApiException;
/**
* This example adjusts an existing conversion by supplying user identifiers so Google can enhance
* the conversion value.
*/
class UploadConversionEnhancement
{
private const CUSTOMER_ID = 'INSERT_CUSTOMER_ID_HERE';
private const CONVERSION_ACTION_ID = 'INSERT_CONVERSION_ACTION_ID_HERE';
private const ORDER_ID = 'INSERT_ORDER_ID_HERE';
// Optional parameters.
// The date time at which the conversion with the specified order ID 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'.
// Setting this field is optional, but recommended.
private const CONVERSION_DATE_TIME = null;
private const USER_AGENT = null;
public static function main()
{
// Either pass the required parameters for this example on the command line, or insert them
// into the constants above.
$options = (new ArgumentParser())->parseCommandArguments([
ArgumentNames::CUSTOMER_ID => GetOpt::REQUIRED_ARGUMENT,
ArgumentNames::CONVERSION_ACTION_ID => GetOpt::REQUIRED_ARGUMENT,
ArgumentNames::ORDER_ID => GetOpt::REQUIRED_ARGUMENT,
ArgumentNames::CONVERSION_DATE_TIME => GetOpt::OPTIONAL_ARGUMENT,
ArgumentNames::USER_AGENT => GetOpt::OPTIONAL_ARGUMENT
]);
// Generate a refreshable OAuth2 credential for authentication.
$oAuth2Credential = (new OAuth2TokenBuilder())->fromFile()->build();
// Construct a Google Ads client configured from a properties file and the
// OAuth2 credentials above.
$googleAdsClient = (new GoogleAdsClientBuilder())
->fromFile()
->withOAuth2Credential($oAuth2Credential)
->build();
try {
self::runExample(
$googleAdsClient,
$options[ArgumentNames::CUSTOMER_ID] ?: self::CUSTOMER_ID,
$options[ArgumentNames::CONVERSION_ACTION_ID] ?: self::CONVERSION_ACTION_ID,
$options[ArgumentNames::ORDER_ID] ?: self::ORDER_ID,
$options[ArgumentNames::CONVERSION_DATE_TIME] ?: self::CONVERSION_DATE_TIME,
$options[ArgumentNames::USER_AGENT] ?: self::USER_AGENT
);
} catch (GoogleAdsException $googleAdsException) {
printf(
"Request with ID '%s' has failed.%sGoogle Ads failure details:%s",
$googleAdsException->getRequestId(),
PHP_EOL,
PHP_EOL
);
foreach ($googleAdsException->getGoogleAdsFailure()->getErrors() as $error) {
/** @var GoogleAdsError $error */
printf(
"\t%s: %s%s",
$error->getErrorCode()->getErrorCode(),
$error->getMessage(),
PHP_EOL
);
}
exit(1);
} catch (ApiException $apiException) {
printf(
"ApiException was thrown with message '%s'.%s",
$apiException->getMessage(),
PHP_EOL
);
exit(1);
}
}
/**
* Runs the example.
*
* @param GoogleAdsClient $googleAdsClient the Google Ads API client
* @param int $customerId the customer ID
* @param int $conversionActionId the ID of the conversion action associated with this
* conversion
* @param string $orderId the unique order ID (transaction ID) of the conversion
* @param string|null $conversionDateTime the date and time of the conversion.
* The format is "yyyy-mm-dd hh:mm:ss+|-hh:mm", e.g. “2019-01-01 12:32:45-08:00”
* @param string|null $userAgent the HTTP user agent of the conversion
*/
public static function runExample(
GoogleAdsClient $googleAdsClient,
int $customerId,
int $conversionActionId,
string $orderId,
?string $conversionDateTime,
?string $userAgent
) {
// Creates the conversion enhancement.
$conversionAdjustment = new ConversionAdjustment([
'conversion_action' =>
ResourceNames::forConversionAction($customerId, $conversionActionId),
'adjustment_type' => ConversionAdjustmentType::ENHANCEMENT,
// Enhancements must use order ID instead of GCLID date/time pair.
'order_id' => $orderId
]);
// Uses the SHA-256 hash algorithm for hashing user identifiers in a privacy-safe way, as
// described at https://support.google.com/google-ads/answer/9888656.
$hashAlgorithm = "sha256";
// Adds user identifiers, hashing where required.
// Creates a user identifier using sample values for the user address.
$addressIdentifier = new UserIdentifier([
'address_info' => new OfflineUserAddressInfo([
'hashed_first_name' => self::normalizeAndHash($hashAlgorithm, 'Dana'),
'hashed_last_name' => self::normalizeAndHash($hashAlgorithm, 'Quinn'),
'hashed_street_address' => self::normalizeAndHash(
$hashAlgorithm,
'1600 Amphitheatre Pkwy'
),
'city' => 'Mountain View',
'state' => 'CA',
'postal_code' => '94043',
'country_code' => 'US'
]),
// Optional: Specifies the user identifier source.
'user_identifier_source' => UserIdentifierSource::FIRST_PARTY
]);
// Creates a user identifier using the hashed email address.
$emailIdentifier = new UserIdentifier([
// Uses the normalize and hash method specifically for email addresses.
'hashed_email' => self::normalizeAndHashEmailAddress(
$hashAlgorithm,
'dana@example.com'
),
// Optional: Specifies the user identifier source.
'user_identifier_source' => UserIdentifierSource::FIRST_PARTY
]);
// Adds the user identifiers to the enhancement adjustment.
$conversionAdjustment->setUserIdentifiers([$addressIdentifier, $emailIdentifier]);
// Sets optional fields where a value was provided.
if ($conversionDateTime !== null) {
// Sets the conversion date and time if provided. Providing this value is optional but
// recommended.
$conversionAdjustment->setGclidDateTimePair(new GclidDateTimePair([
'conversion_date_time' => $conversionDateTime
]));
}
if ($userAgent !== null) {
// Sets the user agent. This should match the user agent of the request that sent the
// original conversion so the conversion and its enhancement are either both attributed
// as same-device or both attributed as cross-device.
$conversionAdjustment->setUserAgent($userAgent);
}
// Issues a request to upload the conversion enhancement.
$conversionAdjustmentUploadServiceClient =
$googleAdsClient->getConversionAdjustmentUploadServiceClient();
$response = $conversionAdjustmentUploadServiceClient->uploadConversionAdjustments(
$customerId,
[$conversionAdjustment],
// Enables partial failure (must be true).
true
);
// Prints the status message if any partial failure error is returned.
// Note: The details of each partial failure error are not printed here, you can refer to
// the example HandlePartialFailure.php to learn more.
if ($response->hasPartialFailureError()) {
printf(
"Partial failures occurred: '%s'.%s",
$response->getPartialFailureError()->getMessage(),
PHP_EOL
);
} else {
// Prints the result if exists.
/** @var ConversionAdjustmentResult $uploadedConversionAdjustment */
$uploadedConversionAdjustment = $response->getResults()[0];
printf(
"Uploaded conversion adjustment of '%s' for order ID '%s'.%s",
$uploadedConversionAdjustment->getConversionAction(),
$uploadedConversionAdjustment->getOrderId(),
PHP_EOL
);
}
}
/**
* Returns the result of normalizing and then hashing the string using the provided hash
* algorithm. Private customer data must be hashed during upload, as described at
* https://support.google.com/google-ads/answer/7474263.
*
* @param string $hashAlgorithm the hash algorithm to use
* @param string $value the value to normalize and hash
* @return string the normalized and hashed value
*/
private static function normalizeAndHash(string $hashAlgorithm, string $value): string
{
return hash($hashAlgorithm, strtolower(trim($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".
*
* @param string $hashAlgorithm the hash algorithm to use
* @param string $emailAddress the email address to normalize and hash
* @return string the normalized and hashed email address
*/
private static function normalizeAndHashEmailAddress(
string $hashAlgorithm,
string $emailAddress
): string {
$normalizedEmail = strtolower($emailAddress);
$emailParts = explode("@", $normalizedEmail);
if (
count($emailParts) > 1
&& preg_match('/^(gmail|googlemail)\.com\s*/', $emailParts[1])
) {
// Removes any '.' characters from the portion of the email address before the domain
// if the domain is gmail.com or googlemail.com.
$emailParts[0] = str_replace(".", "", $emailParts[0]);
$normalizedEmail = sprintf('%s@%s', $emailParts[0], $emailParts[1]);
}
return self::normalizeAndHash($hashAlgorithm, $normalizedEmail);
}
}
UploadConversionEnhancement::main();
питон
#!/usr/bin/env python
# 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
#
# 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.
"""Uploads a conversion using hashed email address instead of GCLID."""
import argparse
import hashlib
import re
import sys
from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
def main(
client,
customer_id,
conversion_action_id,
order_id,
conversion_date_time,
user_agent,
):
"""The main method that creates all necessary entities for the example.
Args:
client: An initialized GoogleAdsClient instance.
customer_id: The client customer ID string.
conversion_action_id: The ID of the conversion action to upload to.
order_id: The unique ID (transaction ID) of the conversion.
conversion_date_time: The date and time of the conversion.
user_agent: The HTTP user agent of the conversion.
"""
conversion_action_service = client.get_service("ConversionActionService")
conversion_adjustment = client.get_type("ConversionAdjustment")
conversion_adjustment.conversion_action = conversion_action_service.conversion_action_path(
customer_id, conversion_action_id
)
conversion_adjustment.adjustment_type = (
client.enums.ConversionAdjustmentTypeEnum.ENHANCEMENT
)
# Enhancements MUST use order ID instead of GCLID date/time pair.
conversion_adjustment.order_id = order_id
# Sets the conversion date and time if provided. Providing this value is
# optional but recommended.
if conversion_date_time:
conversion_adjustment.gclid_date_time_pair.conversion_date_time = (
conversion_date_time
)
# Creates a user identifier using sample values for the user address,
# hashing where required.
address_identifier = client.get_type("UserIdentifier")
address_identifier.address_info.hashed_first_name = normalize_and_hash(
"Joanna"
)
address_identifier.address_info.hashed_last_name = normalize_and_hash(
"Joanna"
)
address_identifier.address_info.hashed_street_address = normalize_and_hash(
"1600 Amphitheatre Pkwy"
)
address_identifier.address_info.city = "Mountain View"
address_identifier.address_info.state = "CA"
address_identifier.address_info.postal_code = "94043"
address_identifier.address_info.country_code = "US"
# Optional: Specifies the user identifier source.
address_identifier.user_identifier_source = (
client.enums.UserIdentifierSourceEnum.FIRST_PARTY
)
# Creates a user identifier using the hashed email address.
email_identifier = client.get_type("UserIdentifier")
# Optional: Specifies the user identifier source.
email_identifier.user_identifier_source = (
client.enums.UserIdentifierSourceEnum.FIRST_PARTY
)
# Uses the normalize and hash method specifically for email addresses.
email_identifier.hashed_email = normalize_and_hash_email_address(
"dana@example.com"
)
# Adds both user identifiers to the conversion adjustment.
conversion_adjustment.user_identifiers.extend(
[address_identifier, email_identifier]
)
# Sets optional fields where a value was provided
if user_agent:
# Sets the user agent. This should match the user agent of the request
# that sent the original conversion so the conversion and its
# enhancement are either both attributed as same-device or both
# attributed as cross-device.
conversion_adjustment.user_agent = user_agent
# Creates the conversion adjustment upload service client.
conversion_adjustment_upload_service = client.get_service(
"ConversionAdjustmentUploadService"
)
# Uploads the enhancement adjustment. Partial failure should always be set
# to true.
response = conversion_adjustment_upload_service.upload_conversion_adjustments(
customer_id=customer_id,
conversion_adjustments=[conversion_adjustment],
# Enables partial failure (must be true).
partial_failure=True,
)
# Prints any partial errors returned.
if response.partial_failure_error:
print(
"Partial error encountered: "
f"{response.partial_failure_error.message}"
)
# Prints the result.
result = response.results[0]
# Only prints valid results. If the click conversion failed then this
# result will be returned as an empty message and will be falsy.
if result:
print(
f"Uploaded conversion adjustment of {result.conversion_action} for "
f"order ID {result,order_id}."
)
def normalize_and_hash_email_address(email_address):
"""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"
Args:
email_address: An email address to normalize.
Returns:
A normalized (lowercase, removed whitespace) and SHA-265 hashed string.
"""
normalized_email = email_address.lower()
email_parts = normalized_email.split("@")
# Checks whether the domain of the email address is either "gmail.com"
# or "googlemail.com". If this regex does not match then this statement
# will evaluate to None.
is_gmail = re.match(r"^(gmail|googlemail)\.com$", email_parts[1])
# Check that there are at least two segments and the second segment
# matches the above regex expression validating the email domain name.
if len(email_parts) > 1 and is_gmail:
# Removes any '.' characters from the portion of the email address
# before the domain if the domain is gmail.com or googlemail.com.
email_parts[0] = email_parts[0].replace(".", "")
normalized_email = "@".join(email_parts)
return normalize_and_hash(normalized_email)
def normalize_and_hash(s):
"""Normalizes and hashes a string with SHA-256.
Private customer data must be hashed during upload, as described at:
https://support.google.com/google-ads/answer/7474263
Args:
s: The string to perform this operation on.
Returns:
A normalized (lowercase, removed whitespace) and SHA-256 hashed string.
"""
return hashlib.sha256(s.strip().lower().encode()).hexdigest()
if __name__ == "__main__":
# GoogleAdsClient will read the google-ads.yaml configuration file in the
# home directory if none is specified.
googleads_client = GoogleAdsClient.load_from_storage(version="v13")
parser = argparse.ArgumentParser(
description="Imports offline call conversion values for calls related "
"to your ads."
)
# The following argument(s) should be provided to run the example.
parser.add_argument(
"-c",
"--customer_id",
type=str,
required=True,
help="The Google Ads customer ID.",
)
parser.add_argument(
"-a",
"--conversion_action_id",
type=str,
required=True,
help="The ID of the conversion action to upload to.",
)
parser.add_argument(
"-o",
"--order_id",
type=str,
required=True,
help="the unique ID (transaction ID) of the conversion.",
)
parser.add_argument(
"-d",
"--conversion_date_time",
type=str,
help="The date time at which the conversion with the specified order "
"ID 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'. Setting this field is optional, "
"but recommended",
)
parser.add_argument(
"-u",
"--user_agent",
type=str,
help="The HTTP user agent of the conversion.",
)
args = parser.parse_args()
try:
main(
googleads_client,
args.customer_id,
args.conversion_action_id,
args.order_id,
args.conversion_date_time,
args.user_agent,
)
except GoogleAdsException as ex:
print(
f"Request with ID '{ex.request_id}'' failed with status "
f"'{ex.error.code().name}' and includes the following errors:"
)
for error in ex.failure.errors:
print(f"\tError with message '{error.message}'.")
if error.location:
for field_path_element in error.location.field_path_elements:
print(f"\t\tOn field: {field_path_element.field_name}")
sys.exit(1)
Рубин
#!/usr/bin/env ruby
#
# 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
#
# 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.
#
# Adjusts an existing conversion by supplying user identifiers so Google can
# enhance the conversion value.
require 'optparse'
require 'google/ads/google_ads'
require 'digest'
def upload_conversion_enhancement(
customer_id,
conversion_action_id,
order_id,
conversion_date_time,
user_agent
)
# GoogleAdsClient will read a config file from
# ENV['HOME']/google_ads_config.rb when called without parameters
client = Google::Ads::GoogleAds::GoogleAdsClient.new
enhancement = client.resource.conversion_adjustment do |ca|
ca.conversion_action = client.path.conversion_action(customer_id, conversion_action_id)
ca.adjustment_type = :ENHANCEMENT
ca.order_id = order_id
# Sets the conversion date and time if provided. Providing this value is
# optional but recommended.
unless conversion_date_time.nil?
ca.gclid_date_time_pair = client.resource.gclid_date_time_pair do |pair|
pair.conversion_date_time = conversion_date_time
end
end
# Creates a user identifier using sample values for the user address.
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
# 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("dana@example.com")
ui.user_identifier_source = :FIRST_PARTY
end
# Sets optional fields where a value was provided.
unless user_agent.nil?
# Sets the user agent. This should match the user agent of the request
# that sent the original conversion so the conversion and its enhancement
# are either both attributed as same-device or both attributed as
# cross-device.
ca.user_agent = user_agent
end
end
response = client.service.conversion_adjustment_upload.upload_conversion_adjustments(
customer_id: customer_id,
conversion_adjustments: [enhancement],
# Partial failure must be set to true.
partial_failure: true,
)
if response.partial_failure_error
puts "Partial failure encountered: #{response.partial_failure_error.message}."
else
result = response.results.first
puts "Uploaded conversion adjustment of #{result.conversion_action} for "\
"order ID #{result.order_id}."
end
end
# 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.
def normalize_and_hash(str)
# Remove leading and trailing whitespace and ensure all letters are lowercase
# before hasing.
Digest::SHA256.hexdigest(str.strip.downcase)
end
# 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'.
def normalize_and_hash_email(email)
email_parts = email.downcase.split("@")
# Removes any '.' characters from the portion of the email address before the
# domain if the domain is gmail.com or googlemail.com.
if email_parts.last =~ /^(gmail|googlemail)\.com\s*/
email_parts[0] = email_parts[0].gsub('.', '')
end
normalize_and_hash(email_parts.join('@'))
end
if __FILE__ == $0
options = {}
# 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.
options[:customer_id] = 'INSERT_CUSTOMER_ID_HERE'
options[:conversion_action_id] = 'INSERT_CONVERSION_ACTION_ID_HERE'
options[:order_id] = 'INSERT_ORDER_ID_HERE'
OptionParser.new do |opts|
opts.banner = format('Usage: %s [options]', File.basename(__FILE__))
opts.separator ''
opts.separator 'Options:'
opts.on('-C', '--customer-id CUSTOMER-ID', String, 'Customer ID') do |v|
options[:customer_id] = v
end
opts.on('-c', '--conversion-action-id CONVERSION-ACTION-ID', String,
'Conversion Action ID') do |v|
options[:conversion_action_id] = v
end
opts.on('-o', '--order-id ORDER-ID', String, 'Order ID') do |v|
options[:order_id] = v
end
opts.on('-d', '--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", '\
'e.g. "2019-01-01 12:32:45-08:00".') do |v|
options[:conversion_date_time] = v
end
opts.on('-u', '--user-agent USER-AGENT', String, 'User Agent') do |v|
options[:user_agent] = v
end
opts.separator ''
opts.separator 'Help:'
opts.on_tail('-h', '--help', 'Show this message') do
puts opts
exit
end
end.parse!
begin
upload_conversion_enhancement(
options.fetch(:customer_id).tr('-', ''),
options.fetch(:conversion_action_id),
options.fetch(:order_id),
options[:conversion_date_time],
options[:user_agent]
)
rescue Google::Ads::GoogleAds::Errors::GoogleAdsError => e
e.failure.errors.each do |error|
STDERR.printf("Error with message: %s\n", error.message)
error.location&.field_path_elements&.each do |field_path_element|
STDERR.printf("\tOn field: %s\n", field_path_element.field_name)
end
error.error_code.to_h.each do |k, v|
next if v == :UNSPECIFIED
STDERR.printf("\tType: %s\n\tCode: %s\n", k, v)
end
end
raise
end
end
Перл
#!/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
#
# 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.
#
# Adjusts an existing conversion by supplying user identifiers so Google can
# enhance the conversion value.
use strict;
use warnings;
use utf8;
use FindBin qw($Bin);
use lib "$Bin/../../lib";
use Google::Ads::GoogleAds::Client;
use Google::Ads::GoogleAds::Utils::GoogleAdsHelper;
use Google::Ads::GoogleAds::V13::Common::UserIdentifier;
use Google::Ads::GoogleAds::V13::Common::OfflineUserAddressInfo;
use Google::Ads::GoogleAds::V13::Enums::ConversionAdjustmentTypeEnum
qw(ENHANCEMENT);
use Google::Ads::GoogleAds::V13::Enums::UserIdentifierSourceEnum
qw(FIRST_PARTY);
use
Google::Ads::GoogleAds::V13::Services::ConversionAdjustmentUploadService::ConversionAdjustment;
use
Google::Ads::GoogleAds::V13::Services::ConversionAdjustmentUploadService::GclidDateTimePair;
use Google::Ads::GoogleAds::V13::Utils::ResourceNames;
use Getopt::Long qw(:config auto_help);
use Pod::Usage;
use Cwd qw(abs_path);
use Digest::SHA qw(sha256_hex);
# 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 $order_id = "INSERT_ORDER_ID_HERE";
# Optional: Specify the conversion date/time and user agent.
my $conversion_date_time = undef;
my $user_agent = undef;
sub upload_conversion_enhancement {
my (
$api_client, $customer_id, $conversion_action_id,
$order_id, $conversion_date_time, $user_agent
) = @_;
# Construct the enhancement adjustment.
my $enhancement =
Google::Ads::GoogleAds::V13::Services::ConversionAdjustmentUploadService::ConversionAdjustment
->new({
conversionAction =>
Google::Ads::GoogleAds::V13::Utils::ResourceNames::conversion_action(
$customer_id, $conversion_action_id
),
adjustmentType => ENHANCEMENT,
# Enhancements MUST use order ID instead of GCLID date/time pair.
orderId => $order_id
});
# Set the conversion date and time if provided. Providing this value is optional
# but recommended.
if (defined $conversion_date_time) {
$enhancement->{gclidDateTimePair} =
Google::Ads::GoogleAds::V13::Services::ConversionAdjustmentUploadService::GclidDateTimePair
->new({
conversionDateTime => $conversion_date_time
});
}
# Add user identifiers, hashing where required.
# Create a user identifier using sample values for the user address.
my $address_identifier =
Google::Ads::GoogleAds::V13::Common::UserIdentifier->new({
addressInfo =>
Google::Ads::GoogleAds::V13::Common::OfflineUserAddressInfo->new({
hashedFirstName => normalize_and_hash("Dana"),
hashedLastName => normalize_and_hash("Quinn"),
hashedStreetAddress => normalize_and_hash("1600 Amphitheatre Pkwy"),
city => "Mountain View",
state => "CA",
postalCode => "94043",
countryCode => "US"
}
),
# Optional: Specify the user identifier source.
userIdentifierSource => FIRST_PARTY
});
# Create a user identifier using the hashed email address.
my $email_identifier =
Google::Ads::GoogleAds::V13::Common::UserIdentifier->new({
userIdentifierSource => FIRST_PARTY,
# Use the normalize and hash method specifically for email addresses.
hashedEmail => normalize_and_hash_email_address('dana@example.com')});
# Add the user identifiers to the enhancement adjustment.
$enhancement->{userIdentifiers} = [$address_identifier, $email_identifier];
# Set optional fields where a value was provided.
if (defined $user_agent) {
# Set the user agent. This should match the user agent of the request that
# sent the original conversion so the conversion and its enhancement are
# either both attributed as same-device or both attributed as cross-device.
$enhancement->{userAgent} = $user_agent;
}
# Upload the enhancement adjustment. Partial failure should always be set to true.
my $response =
$api_client->ConversionAdjustmentUploadService()
->upload_conversion_adjustments({
customerId => $customer_id,
conversionAdjustments => [$enhancement],
# Enable partial failure (must be true).
partialFailure => "true"
});
# Print any partial errors returned.
if ($response->{partialFailureError}) {
printf "Partial error encountered: '%s'.\n",
$response->{partialFailureError}{message};
} else {
# Print the result.
my $result = $response->{results}[0];
printf "Uploaded conversion adjustment of '%s' for order ID '%s'.\n",
$result->{conversionAction}, $result->{orderId};
}
return 1;
}
# Normalizes and hashes a string value.
# Private customer data must be hashed during upload, as described at
# https://support.google.com/google-ads/answer/7474263.
sub normalize_and_hash {
my $value = shift;
$value =~ s/^\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);
}
# 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,
"order_id=s" => \$order_id,
"conversion_date_time=s" => \$conversion_date_time,
"user_agent=s" => \$user_agent
);
# 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, $order_id);
# Call the example.
upload_conversion_enhancement($api_client, $customer_id =~ s/-//gr,
$conversion_action_id, $order_id, $conversion_date_time, $user_agent);
=pod
=head1 NAME
upload_conversion_enhancement
=head1 DESCRIPTION
Adjusts an existing conversion by supplying user identifiers so Google can
enhance the conversion value.
=head1 SYNOPSIS
upload_conversion_enhancement.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.
-order_id The unique order ID (transaction ID) of the conversion.
-conversion_date_time [optional] The date time at which the conversion with the specified order ID
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".
Setting this field is optional, but recommended.
-user_agent [optional] The HTTP user agent of the conversion.
=cut