实现增强型潜在客户转化

借助增强型潜在客户转化,您可以上传包含经过哈希处理的用户标识符以及一些可选的其他详细信息的点击转化,这些信息有助于 Google Ads 将转化与促成潜在客户的广告相关联,从而提高线下转化衡量的准确性。

在继续实现之前,请务必查看增强型潜在客户转化的入门指南,并实现增强型潜在客户转化的前提条件

您可以通过 Google Ads 界面(如帮助中心中所述)或 Google Ads API(如本指南中所述)上传潜在客户的增强型转化。

设计集成

您可以自行设计集成。

使用流程

以下是使用 Google Ads API 上传增强型潜在客户转化的整体流程。

  1. 请确保您已实现前提条件,包括:

    1. 启用转化跟踪。

    2. 接受客户数据条款。

    3. 在您的网站潜在客户表单上配置代码植入。

    如需获取详细指南,请参阅实现前提条件

  2. 对潜在客户数据(例如电子邮件地址、电话号码和邮寄地址)进行标准化和哈希处理。

  3. 将经过标准化和哈希处理的潜在客户数据放入 ClickConversion 对象中。对于每个 ClickConversion

    1. 使用经过标准化和哈希处理的潜在客户数据填充 user_identifiers。如果您有多个用户标识符,请为每个标识符分别创建 UserIdentifier,最多可创建 5 个标识符。

    2. (可选但强烈建议执行此步骤)填充 order_id

    3. (可选)填充 gclid,以便最准确地衡量效果。

    4. 确保填充 ClickConversion 对象的 consent 字段。

    5. conversion_action 设置为 ConversionAction 的资源名称,typeUPLOAD_CLICKS。这应为您在实现前提条件时创建的 ConversionAction 的资源名称。

  4. ClickConversion 创建操作上传到 ConversionUploadService,并将 partial_failure 设置为 true

  5. 查看您上传的内容。

最佳做法

为潜在客户实现增强型转化时,请遵循以下最佳实践。

检查客户标识符

上传转化数据时,客户 ID 必须设置为包含转化操作并执行转化跟踪的账号。如需检查此设置,请针对 ConversionTrackingSetting 查询投放的 Google Ads Customer 资源。使用 GoogleAdsService.SearchStream 发出以下查询,以查找 customer.conversion_tracking_setting.google_ads_conversion_customer 的值。

添加多个标识符(如果有)

如果您为转化分配了 order_id,我们强烈建议您添加该维度。如果您有转化的 gclid,我们建议您除了发送 user_identifiers 之外,还发送 gclid,以便提升效果。此外,如果您有多个转化 UserIdentifier,添加多个 UserIdentifier 可以提高匹配的可能性。在同一 ClickConversion 中包含所有标识符。

查看设置集成时出现的部分失败错误

首次设置增强型潜在客户转化集成时,请查看并解决响应 partial_failure_error 字段中的任何部分错误。如果您的设置存在问题,您需要检查此字段以进行调查并解决问题。如需详细了解部分失败错误处理以及相关示例,请参阅专门的部分失败指南

在查看部分失败错误时,请参阅问题排查指南中的常见错误表格。解决出现在部分失败错误中的所有问题并完成集成后,请改用线下数据诊断定期检查转化的健康状况。

在单个请求中批量处理多个转化

如果您要上传多个转化,请将这些操作批量到一个 UploadClickConversionsRequest,而不是针对每个转化发送一个上传请求。

请参阅配额指南,了解每个请求的转化次数限制。

如果您希望离线数据诊断将一组请求归为一项逻辑作业,请将所有请求的 job_id 设置为相同的值。如果单个作业或进程使用多个请求上传大量转化,此功能会非常有用。如果您将每个请求的 job_id 设置为相同的值,则可以从 job_summaries 检索作业的单个条目。相反,如果您让 Google Ads API 为每个请求的 job_id 分配系统生成的值,job_summaries 将针对每个请求包含单独的条目,这可能会增加分析作业整体运行状况的难度。

上传所有可用的线下转化事件

为确保生成完整且准确的转化报告,请上传所有可用的线下转化事件,包括可能并非来自 Google Ads 的转化事件。

如果上传所有转化事件,则会导致任何非 Google Ads 事件都出现 CLICK_NOT_FOUND 错误。由于在上传所有转化事件时预计会出现这些错误,因此 UploadClickConversionsRequest 包含 debug_enabled 字段。

  • 如果 debug_enabledfalse 或未设置,Google Ads API 仅执行基本输入验证,跳过后续上传检查,并且即使未找到所提供 user_identifiers 的任何点击,也会返回成功。

    这是默认值。

  • 如果 debug_enabledtrue,Google Ads API 会执行所有验证,并针对提供的 user_identifiers 没有 Google Ads 转化的任何 ClickConversion 返回 CLICK_NOT_FOUND 错误。

在开发和测试期间,您可以将 debug_enabled 设置为 true,以帮助发现问题。例如,如果您有一组转化和 user_identifiers,并且您知道这些转化来自 Google Ads 转化,则可以使用 true 设置来验证这些上传内容不会导致 CLICK_NOT_FOUND 错误。不过,在开发和测试完成后,我们建议将 debug_enabled 设为 false,以避免出现过多错误。

请勿使用外部归因数据

请勿在 ClickConversion 上设置 external_attribution_data,也不要在 conversion_action 中指定使用外部归因模型的 conversion_action。Google Ads 不支持使用标识符上传的外部归因转化。

准备要上传的数据

出于隐私保护方面的考虑,以下数据在上传之前必须使用 SHA-256 算法进行哈希处理:

  • 电子邮件地址
  • 电话号码
  • 名字
  • 姓氏
  • 街道地址

请勿对以下数据进行哈希处理

  • 国家/地区
  • 州/省/自治区/直辖市
  • 城市
  • 邮编

为了使哈希结果实现标准化,在对其中某个值进行哈希处理之前,您必须执行以下操作:

  • 移除开头和结尾处的空格。
  • 将文字转换为小写形式。
  • 根据 E164 标准设置电话号码的格式。
  • 移除 gmail.comgooglemail.com 电子邮件地址中域名前面的所有句点 (.)。

private String normalizeAndHash(MessageDigest digest, String s)
   
throws UnsupportedEncodingException {
 
// Normalizes by first converting all characters to lowercase, then trimming spaces.
 
String normalized = s.toLowerCase();
 
// Removes leading, trailing, and intermediate spaces.
  normalized
= normalized.replaceAll("\\s+", "");
 
// 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);
}
     
/// <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();
}
     
private static function normalizeAndHash(string $hashAlgorithm, string $value): string
{
   
// Normalizes by first converting all characters to lowercase, then trimming spaces.
    $normalized
= strtolower($value);
   
// Removes leading, trailing, and intermediate spaces.
    $normalized
= str_replace(' ', '', $normalized);
   
return hash($hashAlgorithm, strtolower(trim($normalized)));
}

/**
 * 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);
}
     
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()
     
# 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
     
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);
}
     

上传增强型转化

以下代码段演示了如何构建包含电子邮件地址和电话号码标识符的转化上传内容,并根据需要应用标准化和哈希处理。最佳实践是,在转化中添加 gclidorder_id(如果有)。

向 ClickConversion 添加用户标识符

// Creates an empty builder for constructing the click conversion.
ClickConversion.Builder clickConversionBuilder = ClickConversion.newBuilder();

// Extracts user email and phone 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
// hashedEmail, hashedPhoneNumber, mobileId, thirdPartyUserId, or addressInfo. 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 hashedPhoneNumber.
//
// UserIdentifier incorrectlyPopulatedUserIdentifier =
//     UserIdentifier.newBuilder()
//         .setHashedEmail("...")
//         .setHashedPhoneNumber("...")
//         .build();

ImmutableMap.Builder<String, String> rawRecordBuilder =
   
ImmutableMap.<String, String>builder()
       
.put("email", "alex.2@example.com")
       
// Phone number to be converted to E.164 format, with a leading '+' as required.
       
.put("phone", "+1 800 5550102")
       
// This example lets you put 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.
       
.put("conversionActionId", Long.toString(conversionActionId))
       
.put("conversionDateTime", conversionDateTime)
       
.put("conversionValue", Double.toString(conversionValue))
       
.put("currencyCode", "USD");

// Adds entries for the optional fields.
if (orderId != null) {
  rawRecordBuilder
.put("orderId", orderId);
}
if (gclid != null) {
  rawRecordBuilder
.put("gclid", gclid);
}
if (adUserDataConsent != null) {
  rawRecordBuilder
.put("adUserDataConsent", adUserDataConsent.name());
}

// Builds the map representing the record.
Map<String, String> rawRecord = rawRecordBuilder.build();

// 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");

// Creates a list for the user identifiers.
List<UserIdentifier> userIdentifiers = new ArrayList<>();

// Creates a user identifier using the hashed email address, using the normalize and hash method
// specifically for email addresses.
UserIdentifier emailIdentifier =
   
UserIdentifier.newBuilder()
       
// Optional: specify the user identifier source.
       
.setUserIdentifierSource(UserIdentifierSource.FIRST_PARTY)
       
// Uses the normalize and hash method specifically for email addresses.
       
.setHashedEmail(normalizeAndHashEmailAddress(sha256Digest, rawRecord.get("email")))
       
.build();
userIdentifiers
.add(emailIdentifier);

// Creates a user identifier using normalized and hashed phone info.
UserIdentifier hashedPhoneNumberIdentifier =
   
UserIdentifier.newBuilder()
       
.setHashedPhoneNumber(normalizeAndHash(sha256Digest, rawRecord.get("phone")))
       
.build();
// Adds the hashed phone number identifier to the UserData object's list.
userIdentifiers
.add(hashedPhoneNumberIdentifier);

// Adds the user identifiers to the conversion.
clickConversionBuilder
.addAllUserIdentifiers(userIdentifiers);
     
// Adds a user identifier using the hashed email address, using the normalize
// and hash method specifically for email addresses.
clickConversion
.UserIdentifiers.Add(new UserIdentifier()
{
   
HashedEmail = NormalizeAndHashEmailAddress("alex.2@example.com"),
   
// Optional: Specifies the user identifier source.
   
UserIdentifierSource = UserIdentifierSource.FirstParty
});

// Adds a user identifier using normalized and hashed phone info.
clickConversion
.UserIdentifiers.Add(new UserIdentifier()
{
   
HashedPhoneNumber = NormalizeAndHash("+1 800 5550102"),
   
// Optional: Specifies the user identifier source.
   
UserIdentifierSource = UserIdentifierSource.FirstParty
});

// Adds a user identifier with all the required mailing address elements.
clickConversion
.UserIdentifiers.Add(new UserIdentifier()
{
   
AddressInfo = new OfflineUserAddressInfo()
   
{
       
// FirstName and LastName must be normalized and hashed.
       
HashedFirstName = NormalizeAndHash("Alex"),
       
HashedLastName = NormalizeAndHash("Quinn"),
       
// CountryCode and PostalCode are sent in plain text.
       
CountryCode = "US",
       
PostalCode = "94045"
   
}
});
     
// Creates a click conversion with the specified attributes.
$clickConversion
= new ClickConversion();

// Extract user email and phone from the raw data, normalize and hash it, then wrap 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 hashedEmail, hashedPhoneNumber, mobileId, thirdPartyUserId, or addressInfo. 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 hashedPhoneNumber.
//
// $incorrectlyPopulatedUserIdentifier = new UserIdentifier([
//    'hashed_email' => '...',
//    'hashed_phone_number' => '...'
// ]);

$rawRecord
= [
   
// Email address that includes a period (.) before the Gmail domain.
   
'email' => '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' => $orderId,
   
'gclid' => $gclid,
   
'conversionActionId' => $conversionActionId,
   
'conversionDateTime' => $conversionDateTime,
   
'conversionValue' => $conversionValue,
   
'currencyCode' => 'USD',
   
'adUserDataConsent' => $adUserDataConsent
];

// Creates a list for the user identifiers.
$userIdentifiers
= [];

// 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";

// Creates a user identifier using the hashed email address, using the normalize and hash
// method specifically for email addresses.
$emailIdentifier
= new UserIdentifier([
   
// Uses the normalize and hash method specifically for email addresses.
   
'hashed_email' => self::normalizeAndHashEmailAddress(
        $hashAlgorithm
,
        $rawRecord
['email']
   
),
   
// Optional: Specifies the user identifier source.
   
'user_identifier_source' => UserIdentifierSource::FIRST_PARTY
]);
$userIdentifiers
[] = $emailIdentifier;

// Checks if the record has a phone number, and if so, adds a UserIdentifier for it.
if (array_key_exists('phone', $rawRecord)) {
    $hashedPhoneNumberIdentifier
= new UserIdentifier([
       
'hashed_phone_number' => self::normalizeAndHash(
            $hashAlgorithm
,
            $rawRecord
['phone'],
           
true
       
)
   
]);
   
// Adds the hashed email identifier to the user identifiers list.
    $userIdentifiers
[] = $hashedPhoneNumberIdentifier;
}

// Adds the user identifiers to the conversion.
$clickConversion
->setUserIdentifiers($userIdentifiers);
     
# 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 = client.get_type("UserIdentifier")
# 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": "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.
   
"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,
}

# Constructs the click conversion.
click_conversion
= client.get_type("ClickConversion")
# Creates a user identifier using the hashed email address, using the
# normalize and hash method specifically for email addresses.
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_phone_number = normalize_and_hash_email_address(
    raw_record
["email"]
)
# Adds the user identifier to the conversion.
click_conversion
.user_identifiers.append(email_identifier)

# Checks if the record has a phone number, and if so, adds a UserIdentifier
# for it.
if raw_record.get("phone") is not None:
    phone_identifier
= client.get_type("UserIdentifier")
    phone_identifier
.hashed_phone_number = normalize_and_hash(
        raw_record
["phone"]
   
)
   
# Adds the phone identifier to the conversion adjustment.
    click_conversion
.user_identifiers.append(phone_identifier)
     
# 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" => "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.
 
"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|
  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
  cc
.currency_code = 'USD'

 
unless order_id.nil?
    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 = client.resource.consent do |c|
      c
.ad_user_data = ad_user_data_consent
   
end
 
end

 
# 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 |ui|
    ui
.hashed_phone_number = normalize_and_hash_email(raw_record["email"])
   
# Optional: Specifies the user identifier source.
    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
     
# Create an empty click conversion.
my $click_conversion =
 
Google::Ads::GoogleAds::V18::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
# (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:
#
# my $incorrect_user_identifier = Google::Ads::GoogleAds::V18::Common::UserIdentifier->new({
#   hashedEmail => '...',
#   hashedPhoneNumber => '...',
# });
my $raw_record = {
 
# Email address that includes a period (.) before the Gmail domain.
  email
=> '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::V18::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::V18::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;
     

向 ClickConversion 添加转化详情

// Adds details of the conversion.
clickConversionBuilder
.setConversionAction(
   
ResourceNames.conversionAction(
        customerId
, Long.parseLong(rawRecord.get("conversionActionId"))));
clickConversionBuilder
.setConversionDateTime(rawRecord.get("conversionDateTime"));
clickConversionBuilder
.setConversionValue(Double.parseDouble(rawRecord.get("conversionValue")));
clickConversionBuilder
.setCurrencyCode(rawRecord.get("currencyCode"));

// Sets the order ID if provided.
if (rawRecord.containsKey("orderId")) {
  clickConversionBuilder
.setOrderId(rawRecord.get("orderId"));
}

// Sets the Google click ID (gclid) if provided.
if (rawRecord.containsKey("gclid")) {
  clickConversionBuilder
.setGclid(rawRecord.get("gclid"));
}

// Sets the consent information, if provided.
if (rawRecord.containsKey("adUserDataConsent")) {
 
// Specifies whether user consent was obtained for the data you are uploading. See
 
// https://www.google.com/about/company/user-consent-policy for details.
  clickConversionBuilder
.setConsent(
     
Consent.newBuilder()
         
.setAdUserData(ConsentStatus.valueOf(rawRecord.get("adUserDataConsent"))));
}

// Calls build to build the conversion.
ClickConversion clickConversion = clickConversionBuilder.build();
     
// Adds details of the conversion.
clickConversion
.ConversionAction =
   
ResourceNames.ConversionAction(customerId, conversionActionId);
clickConversion
.ConversionDateTime = conversionDateTime;
clickConversion
.ConversionValue = conversionValue;
clickConversion
.CurrencyCode = "USD";

// Sets the order ID if provided.
if (!string.IsNullOrEmpty(orderId))
{
    clickConversion
.OrderId = orderId;
}

// Sets the Google click ID (gclid) if provided.
if (!string.IsNullOrEmpty(gclid))
{
    clickConversion
.Gclid = gclid;
}

     
// Adds details of the conversion.
$clickConversion
->setConversionAction(
   
ResourceNames::forConversionAction($customerId, $rawRecord['conversionActionId'])
);
$clickConversion
->setConversionDateTime($rawRecord['conversionDateTime']);
$clickConversion
->setConversionValue($rawRecord['conversionValue']);
$clickConversion
->setCurrencyCode($rawRecord['currencyCode']);

// Sets the order ID if provided.
if (!empty($rawRecord['orderId'])) {
    $clickConversion
->setOrderId($rawRecord['orderId']);
}

// Sets the Google click ID (gclid) if provided.
if (!empty($rawRecord['gclid'])) {
    $clickConversion
->setGclid($rawRecord['gclid']);
}

// Sets the ad user data consent if provided.
if (!empty($rawRecord['adUserDataConsent'])) {
   
// Specifies whether user consent was obtained for the data you are uploading. See
   
// https://www.google.com/about/company/user-consent-policy for details.
    $clickConversion
->setConsent(
       
new Consent(['ad_user_data' => $rawRecord['adUserDataConsent']])
   
);
}
     
# Add details of the conversion.
# Gets the conversion action resource name.
conversion_action_service
= client.get_service("ConversionActionService")
click_conversion
.conversion_action = (
    conversion_action_service
.conversion_action_path(
        customer_id
, raw_record["conversion_action_id"]
   
)
)
click_conversion
.conversion_date_time = raw_record["conversion_date_time"]
click_conversion
.conversion_value = raw_record["conversion_value"]
click_conversion
.currency_code = raw_record["currency_code"]

# Sets the order ID if provided.
if raw_record.get("order_id"):
    click_conversion
.order_id = raw_record["order_id"]

# Sets the gclid if provided.
if raw_record.get("gclid"):
    click_conversion
.gclid = raw_record["gclid"]

# 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
if raw_record["ad_user_data_consent"]:
    click_conversion
.consent.ad_user_data = client.enums.ConsentStatusEnum[
        raw_record
["ad_user_data_consent"]
   
]
     
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
cc
.currency_code = 'USD'

unless order_id.nil?
  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 = client.resource.consent do |c|
    c
.ad_user_data = ad_user_data_consent
 
end
end
     
# Add details of the conversion.
$click_conversion
->{conversionAction} =
 
Google::Ads::GoogleAds::V18::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::V18::Common::Consent->new({
      adUserData
=> $raw_record->{adUserDataConsent}});
}
     

上传 ClickConversion

// Creates the conversion upload service client.
try (ConversionUploadServiceClient conversionUploadServiceClient =
    googleAdsClient
.getLatestVersion().createConversionUploadServiceClient()) {
 
// Uploads 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:
 
// https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
 
UploadClickConversionsResponse response =
      conversionUploadServiceClient
.uploadClickConversions(
         
UploadClickConversionsRequest.newBuilder()
             
.setCustomerId(Long.toString(customerId))
             
.addConversions(clickConversion)
             
// Enables partial failure (must be true).
             
.setPartialFailure(true)
             
.build());
     
// Uploads 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:
// https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload
UploadClickConversionsResponse response =
    conversionUploadService
.UploadClickConversions(
       
new UploadClickConversionsRequest()
       
{
           
CustomerId = customerId.ToString(),
           
Conversions = { clickConversion },
           
// Enables partial failure (must be true).
           
PartialFailure = true
       
});

     
// Issues a request to upload the click conversion.
$conversionUploadServiceClient
= $googleAdsClient->getConversionUploadServiceClient();
// 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
$response
= $conversionUploadServiceClient->uploadClickConversions(
   
// Enables partial failure (must be true).
   
UploadClickConversionsRequest::build($customerId, [$clickConversion], true)
);
     
# Creates the conversion upload service client.
conversion_upload_service
= client.get_service("ConversionUploadService")
# Uploads the click conversion. Partial failure should always be set to
# True.
# NOTE: This request only uploads a single conversion, but if you have
# multiple conversions to upload, it's most efficient 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
response
= conversion_upload_service.upload_click_conversions(
    customer_id
=customer_id,
    conversions
=[click_conversion],
   
# Enables partial failure (must be true).
    partial_failure
=True,
)
     
response = client.service.conversion_upload.upload_click_conversions(
  customer_id
: customer_id,
  conversions
: [click_conversion],
 
# Partial failure must be 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 click conversion that happened at #{result.conversion_date_time} " \
   
"to #{result.conversion_action}."
end
     
# 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:
# https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
my $response =
  $api_client
->ConversionUploadService()->upload_click_conversions({
    customerId  
=> $customer_id,
    conversions
=> [$click_conversion],
   
# Enable partial failure (must be true).
    partialFailure
=> "true"
 
});
     

查看您上传的内容

您可以使用线下数据诊断功能查看近期上传内容的整体健康状况。请注意,上传成功并不一定意味着上传内容有匹配项。

在报告广告系列的转化指标时,请参阅映射界面指标,将 Google Ads 界面指标与 Google Ads API 报告字段相关联。您还可以查询 conversion_action 资源,查看指定转化操作的总转化次数和总转化价值。

后续步骤

如果您需要调整转化,请参阅上传转化调整指南。

如需有关排查增强型潜在客户转化集成问题的指南,请参阅问题排查指南。