您可以使用 Google Ads API 管理 Google Ads 中的在线点击转化。在线点击转化可帮助您跟踪促成在线销售(例如通过网站)的广告。
在线转化是使用 Google 代码跟踪的,但您 可以使用 Google Ads API 对其进行调整或增强。
如果您已设置 Google 代码并想要调整在线 转化,请参阅转化调整页面。如果您已设置 Google 代码,并且想要使用用户提供的数据(也称为增强型网站转化)来增强在线转化,请继续阅读。
增强型网站转化
以下部分介绍了如何增强在线点击转化,也称为增强型网站转化 。
增强型网站转化需要设置一个代码,该代码会在用户完成转化时自动将点击标识符(例如 GCLID)和订单 ID 发送给 Google Ads。您可以选择通过 Google 跟踪代码管理器、Google 代码或 Google Ads API 设置增强型转化。 使用 Google Ads API 的优势在于,您可以在转化事件发生后 24 小时内发送第一方转化数据,而不是在同一时间发送。这样,您就可以从各种来源(例如客户数据库或 CRM 系统)找到第一方数据。
增强型网站转化的运作方式
Google Ads API 中的增强型网站转化是对下图中的第 3 步的补充。该代码不会在用户完成转化时发送经过哈希处理的用户信息,而是仅发送 GCLID 和订单 ID,然后您可以通过导入订单 ID 和经过哈希处理的数据来发送经过哈希处理的用户信息。如需详细了解增强型网站转化,请参阅 增强型转化简介。
前提条件
您必须先接受客户数据条款,然后才能 使用增强型网站转化。您可以通过向 Google Ads 广告转化客户发出以下查询来验证是否已接受客户数据条款:
SELECT
customer.id,
customer.conversion_tracking_setting.accepted_customer_data_terms
FROM customer
如果 accepted_customer_data_terms 为 false,请按照
设置增强型网站转化中的说明完成此
前提条件。
配置代码植入
您可以按照 使用 Google Ads API 设置增强型网站转化中的说明,为您的网站配置代码植入。 建议您还 向转化跟踪代码添加交易 ID(订单 ID),以帮助进行转化匹配。
API 实现
以下是在 Google Ads API 中导入增强型网站转化的总体流程。
对用户提供的数据(例如电子邮件 地址、电话号码和邮寄地址)进行规范化和哈希处理。
将
ConversionAdjustment对象导入ConversionAdjustmentUploadService。
对用户提供的数据进行规范化和哈希处理
出于隐私保护方面的考虑,以下数据在导入之前必须使用 SHA-256 算法进行哈希处理:
- 电子邮件地址
- 电话号码
- 名字
- 姓氏
- 街道地址
请勿对以下数据进行哈希处理:
- 国家/地区
- 州/省级行政区
- 城市
- 邮政编码
为了使哈希结果实现标准化,在对其中一个值进行哈希处理之前,请执行以下操作:
- 移除开头和结尾处的空格。
- 将文字转换为小写形式。
- 根据 E.164 标准 设置电话号码的格式。
增强型转化的电子邮件地址格式
为了确保增强型转化的匹配率最高,您必须按照以下步骤正确设置电子邮件地址的格式并对其进行哈希处理:
应用标准规范化(所有电子邮件地址):
- 移除任何开头和结尾处的 ASCII 空格。
- 将电子邮件地址中的所有字符转换为小写形式。
应用特定于网域的规范化(仅限
gmail.com和googlemail.com):- 将电子邮件地址转换为小写形式后,检查网域(
@符号之后的部分)是否为gmail.com或googlemail.com。 - 移除句点 (
.): 从用户名部分(@符号之前的部分)移除所有句点字符。 - 移除加号后缀 (
+): 从用户名部分移除第一个加号 (+) 以及后续所有字符(直到@符号)。- 示例:
Jane.Doe+Shopping@googlemail.com首先变为jane.doe+shopping@googlemail.com(小写),然后变为janedoe@googlemail.com(Gmail 和 Googlemail 规则)。
- 示例:
- 其他网域: 对于
gmail.com或googlemail.com以外的任何网域,请勿从 用户名中移除句点或加号后缀。仅应用标准规范化(移除空格并转换为小写形式)。- 示例:
user.name+NYC@Example.com规范化为user.name+nyc@example.com。
- 示例:
- 将电子邮件地址转换为小写形式后,检查网域(
对规范化的电子邮件地址进行哈希处理:
- 将规范化的电子邮件字符串编码为 UTF-8 字节。
- 使用 SHA-256 算法对 UTF-8 字节进行哈希处理。
- 将生成的摘要格式设置为 小写十六进制字符串 (64 个字符)。
import hashlib
import re
def normalize_and_hash_email(email: str) -> str:
"""Normalizes and SHA-256 hashes an email address for enhanced conversions."""
normalized = email.strip().lower()
parts = normalized.split("@")
if len(parts) != 2:
raise ValueError("Invalid email address format.")
username, domain = parts
if domain in ("gmail.com", "googlemail.com"):
username = username.replace(".", "")
username = re.sub(r"\+.*$", "", username)
normalized = f"{username}@{domain}"
return hashlib.sha256(normalized.encode("utf-8")).hexdigest()
代码示例
此示例展示了如何对用户提供的数据进行规范化和哈希处理。
Java
private String normalizeAndHash(MessageDigest digest, String s, boolean trimIntermediateSpaces) throws UnsupportedEncodingException { // Normalizes by first converting all characters to lowercase, then trimming spaces. String normalized = s.toLowerCase(); if (trimIntermediateSpaces) { // Removes leading, trailing, and intermediate spaces. normalized = normalized.replaceAll("\\s+", ""); } else { // Removes only leading and trailing spaces. normalized = normalized.trim(); } // 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 or trailing '+' and characters that follow it from the * username portion of the email address if the domain is {@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 { // Removes all whitespace (leading, trailing, and intermediate) from the email address. String normalizedEmail = emailAddress.toLowerCase().replaceAll("\\s+", ""); String[] emailParts = normalizedEmail.split("@", 2); if (emailParts.length == 2 && emailParts[1].matches("^(gmail|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].replaceAll("\\.", ""); // Removes any '+' and all characters that follow it 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, true); } /** * Returns the result of normalizing and hashing a phone number. For this use case, Google Ads * requires phone numbers to be in E.164 format. * * @param digest the digest to use to hash the normalized string. * @param phoneNumber the phone number to normalize and hash. */ private String normalizeAndHashPhoneNumber(MessageDigest digest, String phoneNumber) throws UnsupportedEncodingException { // Removes non-digit characters and prepends a leading '+' sign. String digitsOnly = phoneNumber.replaceAll("[^0-9]", ""); String formattedPhone = "+" + digitsOnly; if (!formattedPhone.matches("^\\+[1-9]\\d{6,14}$")) { throw new IllegalArgumentException("Phone number must be in E.164 format: " + phoneNumber); } return normalizeAndHash(digest, formattedPhone, true); }
C#
/// <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
private static function normalizeAndHash( string $hashAlgorithm, string $value, bool $trimIntermediateSpaces ): string { // Normalizes by first converting all characters to lowercase, then trimming spaces. $normalized = strtolower($value); if ($trimIntermediateSpaces === true) { // Removes leading, trailing, and intermediate spaces. $normalized = str_replace(' ', '', $normalized); } else { // Removes only leading and trailing spaces. $normalized = trim($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, true); }
Python
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.strip().lower() email_parts = normalized_email.split("@") # Check that there are at least two segments if len(email_parts) > 1: # Removes any '.' and '+' characters from the portion of the email address # before the domain chars_to_remove = ".+" translation_table = str.maketrans("", "", chars_to_remove) email_parts[0] = email_parts[0].translate(translation_table) 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/9888656 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()
Ruby
# 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/9888656. 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
Perl
sub normalize_and_hash { my $value = shift; my $trim_intermediate_spaces = shift; if ($trim_intermediate_spaces) { $value =~ s/\s+//g; } else { $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, 1); }
curl
填充 ConversionAdjustment 对象
以下部分演示了如何构建包含订单 ID 以及电子邮件地址、电话号码和实际地址的标识符的增强调整,并根据需要应用标准化和哈希处理。作为最佳实践,如果调整中包含 gclid,请将其添加进去。
此步骤与 导入转化调整指南几乎相同,但有一些注意事项:
- 使用
user_identifiers填充 规范化和经过哈希处理的用户数据。如果您有多个用户标识符可用,请为每个标识符创建一个单独的UserIdentifier,最多可创建五个标识符。
Java
// Creates a builder for constructing the enhancement adjustment. ConversionAdjustment.Builder enhancementBuilder = ConversionAdjustment.newBuilder().setAdjustmentType(ConversionAdjustmentType.ENHANCEMENT); // Extracts user email, phone, and address info from the raw data, normalizes and hashes it, // then wraps it in UserIdentifier objects. // Creates a separate UserIdentifier object for each. The data in this example is hardcoded, but // in your application you might read the raw data from an input file. // IMPORTANT: Since the identifier attribute of UserIdentifier // (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier) is a // oneof // (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must set only ONE of // 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() // Email address that includes a period (.) and plus (+) suffix before the Gmail domain. .put("email", "alex.2+myalias@gmail.com") // Address that includes all four required elements: first name, last name, country // code, and postal code. .put("firstName", "Alex") .put("lastName", "Quinn") .put("countryCode", "US") .put("postalCode", "94045") // Phone number to be converted to E.164 format, with a leading '+' as required. .put("phone", "+1 800-555-0102") // 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("orderId", orderId) .put("conversionActionId", Long.toString(conversionActionId)) .put("currencyCode", "USD"); // Adds entries for the optional fields. if (conversionDateTime != null) { rawRecordBuilder.put("conversionDateTime", conversionDateTime); } if (userAgent != null) { rawRecordBuilder.put("userAgent", userAgent); } // 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); // Checks if the record has a phone number, and if so, adds a UserIdentifier for it. if (rawRecord.containsKey("phone")) { UserIdentifier hashedPhoneNumberIdentifier = UserIdentifier.newBuilder() .setHashedPhoneNumber( normalizeAndHashPhoneNumber(sha256Digest, rawRecord.get("phone"))) .build(); // Adds the hashed phone number identifier to the UserData object's list. userIdentifiers.add(hashedPhoneNumberIdentifier); } // Checks if the record has all the required mailing address elements, and if so, adds a // UserIdentifier for the mailing address. if (rawRecord.containsKey("firstName")) { // Checks if the record contains all the other required elements of a mailing address. Set<String> missingAddressKeys = new HashSet<>(); for (String addressKey : new String[] {"lastName", "countryCode", "postalCode"}) { if (!rawRecord.containsKey(addressKey)) { missingAddressKeys.add(addressKey); } } if (!missingAddressKeys.isEmpty()) { System.out.printf( "Skipping addition of mailing address information because the following required keys" + " are missing: %s%n", missingAddressKeys); } else { // Creates an OfflineUserAddressInfo object that contains all the required elements of a // mailing address. OfflineUserAddressInfo addressInfo = OfflineUserAddressInfo.newBuilder() .setHashedFirstName( normalizeAndHash(sha256Digest, rawRecord.get("firstName"), false)) .setHashedLastName(normalizeAndHash(sha256Digest, rawRecord.get("lastName"), false)) .setCountryCode(rawRecord.get("countryCode")) .setPostalCode(rawRecord.get("postalCode")) .build(); UserIdentifier addressIdentifier = UserIdentifier.newBuilder().setAddressInfo(addressInfo).build(); // Adds the address identifier to the UserData object's list. userIdentifiers.add(addressIdentifier); } } // Adds the user identifiers to the enhancement adjustment. enhancementBuilder.addAllUserIdentifiers(userIdentifiers);
C#
// Normalize and hash the raw data, 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: // UserIdentifier incorrectlyPopulatedUserIdentifier = new UserIdentifier() // { // HashedEmail = "..." // HashedPhoneNumber = "..." // } UserIdentifier addressIdentifier = new UserIdentifier() { AddressInfo = new OfflineUserAddressInfo() { HashedFirstName = NormalizeAndHash("Dana"), HashedLastName = NormalizeAndHash("Quinn"), 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("dana@example.com") }; // Adds the user identifiers to the enhancement adjustment. enhancement.UserIdentifiers.AddRange(new[] { addressIdentifier, emailIdentifier });
PHP
// Creates the conversion enhancement. $enhancement = new ConversionAdjustment(['adjustment_type' => ConversionAdjustmentType::ENHANCEMENT]); // Extracts user email, phone, and address info from the raw data, normalizes and hashes it, // then wraps it in UserIdentifier objects. // Creates a separate UserIdentifier object for each. The data in this example is hardcoded, // but in your application you might read the raw data from an input file. // IMPORTANT: Since the identifier attribute of UserIdentifier // (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier) is a // oneof // (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must set only ONE // of 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', // Address that includes all four required elements: first name, last name, country // code, and postal code. 'firstName' => 'Alex', 'lastName' => 'Quinn', 'countryCode' => 'US', 'postalCode' => '94045', // Phone number to be converted to E.164 format, with a leading '+' as required. 'phone' => '+1 800 5550102', // This example lets you input conversion details as arguments, but in reality you might // store this data alongside other user data, so we include it in this sample user // record. 'orderId' => $orderId, 'conversionActionId' => $conversionActionId, 'conversionDateTime' => $conversionDateTime, 'currencyCode' => 'USD' ]; // 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; } // Checks if the record has all the required mailing address elements, and if so, adds a // UserIdentifier for the mailing address. if (array_key_exists('firstName', $rawRecord)) { // Checks if the record contains all the other required elements of a mailing // address. $missingAddressKeys = []; foreach (['lastName', 'countryCode', 'postalCode'] as $addressKey) { if (!array_key_exists($addressKey, $rawRecord)) { $missingAddressKeys[] = $addressKey; } } if (!empty($missingAddressKeys)) { printf( "Skipping addition of mailing address information because the " . "following required keys are missing: %s%s", json_encode($missingAddressKeys), PHP_EOL ); } else { // Creates an OfflineUserAddressInfo object that contains all the required // elements of a mailing address. $addressIdentifier = new UserIdentifier( [ 'address_info' => new OfflineUserAddressInfo( [ 'hashed_first_name' => self::normalizeAndHash( $hashAlgorithm, $rawRecord['firstName'], false ), 'hashed_last_name' => self::normalizeAndHash( $hashAlgorithm, $rawRecord['lastName'], false ), 'country_code' => $rawRecord['countryCode'], 'postal_code' => $rawRecord['postalCode'] ] ) ] ); // Adds the address identifier to the user identifiers list. $userIdentifiers[] = $addressIdentifier; } } // Adds the user identifiers to the conversion. $enhancement->setUserIdentifiers($userIdentifiers);
Python
# Extracts user email, phone, and address info from the raw data, normalizes # and hashes it, then wraps it in UserIdentifier objects. Creates a separate # UserIdentifier object for each. The data in this example is hardcoded, but # in your application you might read the raw data from an input file. # IMPORTANT: Since the identifier attribute of UserIdentifier # (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier) # is a oneof # (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must # set only ONE of hashed_email, hashed_phone_number, mobile_id, # third_party_user_id, or address_info. Setting more than one of these # attributes on the same UserIdentifier will clear all the other members of # the oneof. For example, the following code is INCORRECT and will result in # a UserIdentifier with ONLY a hashed_phone_number: # # incorrectly_populated_user_identifier = 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", # Address that includes all four required elements: first name, last # name, country code, and postal code. "first_name": "Alex", "last_name": "Quinn", "country_code": "US", "postal_code": "94045", # Phone number to be converted to E.164 format, with a leading '+' as # required. "phone": "+1 800 5550102", # This example lets you input conversion details as arguments, but in # reality you might store this data alongside other user data, so we # include it in this sample user record. "order_id": order_id, "conversion_action_id": conversion_action_id, "conversion_date_time": conversion_date_time, "currency_code": "USD", "user_agent": user_agent, } # Constructs the enhancement adjustment. conversion_adjustment = client.get_type("ConversionAdjustment") conversion_adjustment.adjustment_type = ( client.enums.ConversionAdjustmentTypeEnum.ENHANCEMENT ) # 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_email = normalize_and_hash_email_address( raw_record["email"] ) # Adds the email identifier to the conversion adjustment. conversion_adjustment.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. conversion_adjustment.user_identifiers.append(phone_identifier) # Checks if the record has all the required mailing address elements, and if # so, adds a UserIdentifier for the mailing address. if raw_record.get("first_name") is not None: # Checks if the record contains all the other required elements of a # mailing address. required_keys = ["last_name", "country_code", "postal_code"] # Builds a new list of the required keys that are missing from # raw_record. missing_keys = [ key for key in required_keys if key not in raw_record.keys() ] if len(missing_keys) > 0: print( "Skipping addition of mailing address information because the" f"following required keys are missing: {missing_keys}" ) else: # Creates a user identifier using sample values for the user address, # hashing where required. address_identifier = client.get_type("UserIdentifier") address_info = address_identifier.address_info address_info.hashed_first_name = normalize_and_hash( raw_record["first_name"] ) address_info.hashed_last_name = normalize_and_hash( raw_record["last_name"] ) address_info.country_code = raw_record["country_code"] address_info.postal_code = raw_record["postal_code"] # Adds the address identifier to the conversion adjustment. conversion_adjustment.user_identifiers.append(address_identifier)
Ruby
# Extracts user email, phone, and address info from the raw data, normalizes # and hashes it, then wraps it in UserIdentifier objects. Creates a separate # UserIdentifier object for each. The data in this example is hardcoded, but # in your application you might read the raw data from an input file. # IMPORTANT: Since the identifier attribute of UserIdentifier # (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier) # is a oneof # (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must # set only ONE of hashed_email, hashed_phone_number, mobile_id, # third_party_user_id, or address_info. Setting more than one of these # attributes on the same UserIdentifier will clear all the other members of # the oneof. For example, the following code is INCORRECT and will result in # a UserIdentifier with ONLY a hashed_phone_number: # # incorrectly_populated_user_identifier.hashed_email = "..."" # incorrectly_populated_user_identifier.hashed_phone_number = "..."" raw_record = { # Email address that includes a period (.) before the Gmail domain. "email" => "alex.2@example.com", # Address that includes all four required elements: first name, last # name, country code, and postal code. "first_name" => "Alex", "last_name" => "Quinn", "country_code" => "US", "postal_code" => "94045", # Phone number to be converted to E.164 format, with a leading '+' as # required. "phone" => "+1 800 5550102", # This example lets you input conversion details as arguments, but in # reality you might store this data alongside other user data, so we # include it in this sample user record. "order_id" => order_id, "conversion_action_id" => conversion_action_id, "conversion_date_time" => conversion_date_time, "currency_code" => "USD", "user_agent" => user_agent, } enhancement = client.resource.conversion_adjustment do |ca| 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 the hashed email address, using the # normalize and hash method specifically for email addresses. 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(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? ca.user_identifiers << client.resource.user_identifier do |ui| ui.hashed_phone_number = normalize_and_hash_email(raw_record["phone"]) end end # Checks if the record has all the required mailing address elements, and if # so, adds a UserIdentifier for the mailing address. unless raw_record["first_name"].nil? # Checks if the record contains all the other required elements of a # mailing address. required_keys = ["last_name", "country_code", "postal_code"] # Builds a new list of the required keys that are missing from # raw_record. missing_keys = required_keys - raw_record.keys if missing_keys puts( "Skipping addition of mailing address information because the" \ "following required keys are missing: #{missing_keys}" ) else ca.user_identifiers << client.resource.user_identifier do |ui| ui.address_info = client.resource.offline_user_address_info do |info| # Certain fields must be hashed using SHA256 in order to handle # identifiers in a privacy-safe way, as described at # https://support.google.com/google-ads/answer/9888656. info.hashed_first_name = normalize_and_hash( raw_record["first_name"]) info.hashed_last_name = normalize_and_hash( raw_record["last_name"]) info.postal_code = normalize_and_hash(raw_record["country_code"]) info.country_code = normalize_and_hash(raw_record["postal_code"]) end end end end
Perl
# Construct the enhancement adjustment. my $enhancement = Google::Ads::GoogleAds::V26::Services::ConversionAdjustmentUploadService::ConversionAdjustment ->new({ adjustmentType => ENHANCEMENT }); # Extract user email, phone, and address info 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::V26::Common::UserIdentifier->new({ # hashedEmail => '...', # hashedPhoneNumber => '...', # }); my $raw_record = { # Email address that includes a period (.) before the Gmail domain. email => 'alex.2@example.com', # Address that includes all four required elements: first name, last # name, country code, and postal code. firstName => 'Alex', lastName => 'Quinn', countryCode => 'US', postalCode => '94045', # Phone number to be converted to E.164 format, with a leading '+' as # required. phone => '+1 800 5550102', # This example lets you input conversion details as arguments, # but in reality you might store this data alongside other user data, # so we include it in this sample user record. orderId => $order_id, conversionActionId => $conversion_action_id, conversionDateTime => $conversion_date_time, currencyCode => "USD", userAgent => $user_agent, }; 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::V26::Common::UserIdentifier->new({ hashedEmail => $hashed_email, # Optional: Specify the user identifier source. userIdentifierSource => FIRST_PARTY })); # Check if the record has a phone number, and if so, add a UserIdentifier for it. if (defined $raw_record->{phone}) { # Add the hashed phone number identifier to the list of UserIdentifiers. push( @$user_identifiers, Google::Ads::GoogleAds::V26::Common::UserIdentifier->new({ hashedPhoneNumber => normalize_and_hash($raw_record->{phone}, 1)})); } # Confirm the record has all the required mailing address elements, and if so, add # a UserIdentifier for the mailing address. if (defined $raw_record->{firstName}) { my $required_keys = ["lastName", "countryCode", "postalCode"]; my $missing_keys = []; foreach my $key (@$required_keys) { if (!defined $raw_record->{$key}) { push(@$missing_keys, $key); } } if (@$missing_keys) { print "Skipping addition of mailing address information because the following" . "keys are missing: " . join(",", @$missing_keys); } else { push( @$user_identifiers, Google::Ads::GoogleAds::V26::Common::UserIdentifier->new({ addressInfo => Google::Ads::GoogleAds::V26::Common::OfflineUserAddressInfo->new({ # First and last name must be normalized and hashed. hashedFirstName => normalize_and_hash($raw_record->{firstName}), hashedLastName => normalize_and_hash($raw_record->{lastName}), # Country code and zip code are sent in plain text. countryCode => $raw_record->{countryCode}, postalCode => $raw_record->{postalCode}, })})); } } # Add the user identifiers to the enhancement adjustment. $enhancement->{userIdentifiers} = $user_identifiers;
curl
- 设置
order_id、adjustment_type(ENHANCEMENT) 和conversion_action(WEBPAGE), 以及可选的gclid_date_time_pair(格式为yyyy-mm-dd HH:mm:ss+|-HH:mm,例如:2022-01-01 19:32:45-05:00(忽略夏令时) )和user_agent:
Java
// Sets the conversion action. enhancementBuilder.setConversionAction( ResourceNames.conversionAction( customerId, Long.parseLong(rawRecord.get("conversionActionId")))); // Sets the order ID. Enhancements MUST use order ID instead of GCLID date/time pair. enhancementBuilder.setOrderId(rawRecord.get("orderId")); // Sets the conversion date and time if provided. Providing this value is optional but // recommended. if (rawRecord.containsKey("conversionDateTime")) { enhancementBuilder.setGclidDateTimePair( GclidDateTimePair.newBuilder() .setConversionDateTime(rawRecord.get("conversionDateTime"))); } // Sets the user agent if provided. 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. if (rawRecord.containsKey("userAgent")) { enhancementBuilder.setUserAgent(rawRecord.get("userAgent")); }
C#
// Set the conversion action. enhancement.ConversionAction = ResourceNames.ConversionAction(customerId, conversionActionId); // Set the order ID. Enhancements MUST use order ID instead of GCLID date/time pair. enhancement.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 }; } // 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; }
PHP
// Sets the conversion action. $enhancement->setConversionAction( ResourceNames::forConversionAction($customerId, $rawRecord['conversionActionId']) ); // Sets the order ID. Enhancements MUST use order ID instead of GCLID date/time pair. if (!empty($rawRecord['orderId'])) { $enhancement->setOrderId($rawRecord['orderId']); } // Sets the conversion date and time if provided. Providing this value is optional but // recommended. if (!empty($rawRecord['conversionDateTime'])) { // Sets the conversion date and time if provided. Providing this value is optional but // recommended. $enhancement->setGclidDateTimePair( new GclidDateTimePair( [ 'conversion_date_time' => $rawRecord['conversionDateTime'] ] ) ); } // Sets the user agent if provided. 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. if (!empty($rawRecord['userAgent'])) { $enhancement->setUserAgent($rawRecord['userAgent']); }
Python
conversion_action_service = client.get_service("ConversionActionService") # Sets the conversion action. conversion_adjustment.conversion_action = ( conversion_action_service.conversion_action_path( customer_id, raw_record["conversion_action_id"] ) ) # Sets the order ID. 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 raw_record.get("conversion_date_time"): conversion_adjustment.gclid_date_time_pair.conversion_date_time = ( raw_record["conversion_date_time"] ) # Sets optional fields where a value was provided if raw_record.get("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
Ruby
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 the hashed email address, using the # normalize and hash method specifically for email addresses. 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(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? ca.user_identifiers << client.resource.user_identifier do |ui| ui.hashed_phone_number = normalize_and_hash_email(raw_record["phone"]) end end # Checks if the record has all the required mailing address elements, and if # so, adds a UserIdentifier for the mailing address. unless raw_record["first_name"].nil? # Checks if the record contains all the other required elements of a # mailing address. required_keys = ["last_name", "country_code", "postal_code"] # Builds a new list of the required keys that are missing from # raw_record. missing_keys = required_keys - raw_record.keys if missing_keys puts( "Skipping addition of mailing address information because the" \ "following required keys are missing: #{missing_keys}" ) else ca.user_identifiers << client.resource.user_identifier do |ui| ui.address_info = client.resource.offline_user_address_info do |info| # Certain fields must be hashed using SHA256 in order to handle # identifiers in a privacy-safe way, as described at # https://support.google.com/google-ads/answer/9888656. info.hashed_first_name = normalize_and_hash( raw_record["first_name"]) info.hashed_last_name = normalize_and_hash( raw_record["last_name"]) info.postal_code = normalize_and_hash(raw_record["country_code"]) info.country_code = normalize_and_hash(raw_record["postal_code"]) end end end end # 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
Perl
# Set the conversion action. $enhancement->{conversionAction} = Google::Ads::GoogleAds::V26::Utils::ResourceNames::conversion_action( $customer_id, $raw_record->{conversionActionId}); # Set the order ID. Enhancements MUST use order ID instead of GCLID date/time pair. $enhancement->{orderId} = $raw_record->{orderId}; # Set the conversion date and time if provided. Providing this value is optional # but recommended. if (defined $raw_record->{conversionDateTime}) { $enhancement->{gclidDateTimePair} = Google::Ads::GoogleAds::V26::Services::ConversionAdjustmentUploadService::GclidDateTimePair ->new({ conversionDateTime => $raw_record->{conversionDateTime}}); } # Set the user agent if provided. 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. if (defined $raw_record->{userAgent}) { $enhancement->{userAgent} = $raw_record->{userAgent}; }
curl
请求和 ConversionAdjustment 架构摘要
下表总结了使用
ConversionAdjustmentUploadService.UploadConversionAdjustments上传增强型网站转化时,
UploadConversionAdjustmentsRequest
上的顶级字段以及 ConversionAdjustment
(conversion_adjustments[]) 上的每项字段:
| 请求字段 | 要求 | 格式和限制 |
|---|---|---|
customer_id |
必填 | 设置为 Google Ads 广告转化客户 ID(customer.conversion_tracking_setting 上的 google_ads_conversion_customer),不含连字符。 |
conversion_adjustments[] |
必填 | 每个请求最多 2,000 个 ConversionAdjustment 条目 (TOO_MANY_ADJUSTMENTS_IN_REQUEST)。 |
partial_failure |
必填 | 必须设置为 true,以便处理有效调整并在 partial_failure_error 中返回行级错误。 |
validate_only |
可选 | 如果为 true,则验证请求,但不执行调整。 |
job_id |
可选 | 正 int32(1 到 2^31 - 1;0 是未设置的 sentinel,如果指定,则返回 INVALID_JOB_ID),用于在 job_summaries 中将多个请求归入一个逻辑作业。 |
ConversionAdjustment 中的每个
conversion_adjustments[](每个请求最多 2,000 个调整)都支持以下字段:
ConversionAdjustment 字段 |
要求 | 格式和限制 |
|---|---|---|
adjustment_type |
必填 | 必须设置为 ENHANCEMENT (ConversionAdjustmentType)。 |
conversion_action |
必填 | 资源名称 (customers/{conversion_customer_id}/conversionActions/{action_id}),指在上传前至少 6 小时创建的 ENABLED 转化操作,且 type = WEBPAGE (TOO_RECENT_CONVERSION_ACTION)。 |
order_id |
必填 | 要增强的转化的交易 ID;必须与网站转化代码发送的订单 ID 匹配。 |
user_identifiers[] |
必填 | 每次增强操作需要 1 到 5 个 UserIdentifier 对象。为每个条目设置可选的 user_identifier_source(例如 FIRST_PARTY)和 一个 标识符:• hashed_email:SHA-256 十六进制字符串。• hashed_phone_number:E.164 SHA-256 十六进制字符串。• address_info:OfflineUserAddressInfo,其中包含经过 SHA-256 哈希处理的 hashed_first_name、hashed_last_name、hashed_street_address,以及未经过哈希处理的 city、state、country_code、postal_code。 |
gclid_date_time_pair |
可选(推荐) | GclidDateTimePair,其中包含原始转化的 gclid 和 conversion_date_time(
yyyy-mm-dd HH:mm:ss+|-HH:mm,例如:2022-01-01 19:32:45-05:00(忽略夏令时)
,例如:2026-06-01 14:30:00-04:00)。超过 54 天的转化无法调整 (CONVERSION_EXPIRED)。 |
adjustment_date_time |
可选 | 发生调整时的时间戳(
yyyy-mm-dd HH:mm:ss+|-HH:mm,例如:2022-01-01 19:32:45-05:00(忽略夏令时)
);如果设置,则必须晚于 conversion_date_time。 |
user_agent |
可选 | 原始转化请求中的 HTTP User-Agent 标头字符串,以便转化和增强操作共享相同的设备归因(same-device 或 cross-device)。 |
restatement_value |
请勿在 ENHANCEMENT 上设置 |
当 adjustment_type 为 ENHANCEMENT 时,系统会忽略此字段。发送一个单独的操作,并将 adjustment_type = RESTATEMENT 设置为更改转化的值。 |
导入转化增强操作
Java
// Creates the conversion adjustment upload service client. try (ConversionAdjustmentUploadServiceClient conversionUploadServiceClient = googleAdsClient.getLatestVersion().createConversionAdjustmentUploadServiceClient()) { // Uploads the enhancement adjustment. Partial failure should always be set to true. // NOTE: This request contains a single adjustment as a demonstration. However, if you have // multiple adjustments to upload, it's best to upload multiple adjustments per request // instead of sending a separate request per adjustment. See the following for per-request // limits: // https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_adjustment_upload_service UploadConversionAdjustmentsResponse response = conversionUploadServiceClient.uploadConversionAdjustments( UploadConversionAdjustmentsRequest.newBuilder() .setCustomerId(Long.toString(customerId)) .addConversionAdjustments(enhancementBuilder) // Enables partial failure (must be true). .setPartialFailure(true) .build());
C#
// Uploads the enhancement adjustment. Partial failure should always be set to true. // // NOTE: This request contains a single adjustment as a demonstration. // However, if you have multiple adjustments to upload, it's best to upload // multiple adjustmenst per request instead of sending a separate request per // adjustment. See the following for per-request limits: // https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_adjust UploadConversionAdjustmentsResponse response = conversionAdjustmentUploadService.UploadConversionAdjustments( new UploadConversionAdjustmentsRequest() { CustomerId = customerId.ToString(), ConversionAdjustments = { enhancement }, // Enables partial failure (must be true). PartialFailure = true, });
PHP
// Issues a request to upload the conversion enhancement. $conversionAdjustmentUploadServiceClient = $googleAdsClient->getConversionAdjustmentUploadServiceClient(); // NOTE: This request contains a single adjustment as a demonstration. However, if you have // multiple adjustments to upload, it's best to upload multiple adjustments per request // instead of sending a separate request per adjustment. See the following for per-request // limits: // https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_adjustment_upload_service $response = $conversionAdjustmentUploadServiceClient->uploadConversionAdjustments( // Enables partial failure (must be true). UploadConversionAdjustmentsRequest::build($customerId, [$enhancement], true) );
Python
# 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. # NOTE: This request only uploads a single conversion, but if you have # multiple conversions to upload, it's still best to upload them in a single # request. See the following for per-request limits for reference: # https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service 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, )
Ruby
response = client.service.conversion_adjustment_upload.upload_conversion_adjustments( customer_id: customer_id, # NOTE: This request only uploads a single conversion, but if you have # multiple conversions to upload, it's still best to upload them in a single # request. See the following for per-request limits for reference: # https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service conversion_adjustments: [enhancement], # Partial failure must be set to true. partial_failure: true, )
Perl
# Upload the enhancement adjustment. Partial failure should always be set to true. # # NOTE: This request contains a single adjustment as a demonstration. # However, if you have multiple adjustments to upload, it's best to # upload multiple adjustments per request instead of sending a separate # request per adjustment. See the following for per-request limits: # https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_adjustment_upload_service my $response = $api_client->ConversionAdjustmentUploadService() ->upload_conversion_adjustments({ customerId => $customer_id, conversionAdjustments => [$enhancement], # Enable partial failure (must be true). partialFailure => "true" });
curl
REST 请求和响应结构
通过 REST 调用
ConversionAdjustmentUploadService.UploadConversionAdjustments
时,请发送 POST 请求,并将 partialFailure 设置为 true:
POST https://googleads.googleapis.com/v26/customers/{customer_id}:uploadConversionAdjustments
{
"partialFailure": true,
"jobId": 2001,
"conversionAdjustments": [
{
"conversionAction": "customers/{customer_id}/conversionActions/{conversion_action_id}",
"adjustmentType": "ENHANCEMENT",
"orderId": "ORDER-2026-1001",
"gclidDateTimePair": {
"gclid": "EAIaIQobChMI...",
"conversionDateTime": "2026-06-01 14:30:00-04:00"
},
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
"userIdentifiers": [
{
"userIdentifierSource": "FIRST_PARTY",
"hashedEmail": "f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a"
},
{
"userIdentifierSource": "FIRST_PARTY",
"hashedPhoneNumber": "42975f8f9e46c2e13c1a2294957e5cb8d8e6f4f7341a036c6e595bc9f5e24621"
},
{
"userIdentifierSource": "FIRST_PARTY",
"addressInfo": {
"hashedFirstName": "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3",
"hashedLastName": "b3a8e0e1f9ab1bfe3a36f231f676f78bb30a519d2b21e6c530c0eee8ebb4a5d0",
"hashedStreetAddress": "35a9e381b1a27567549b5f8a6f783c167ebf809f1c4d6a9e367240484d8ce281",
"city": "New York",
"state": "NY",
"postalCode": "10011",
"countryCode": "US"
}
}
]
},
{
"conversionAction": "customers/{customer_id}/conversionActions/{conversion_action_id}",
"adjustmentType": "ENHANCEMENT",
"userIdentifiers": [
{
"userIdentifierSource": "FIRST_PARTY",
"hashedEmail": "f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a"
}
]
}
]
}
在此包含两个调整的批处理中,第二个调整省略了 orderId,
成功的行会返回填充的
ConversionAdjustmentResult 条目,results[],
而失败的行会在 results[] 中返回空 {} 对象,并在 partialFailureError 的
UploadConversionAdjustmentsResponse 中返回行级
错误详细信息:
{
"results": [
{
"gclidDateTimePair": {
"gclid": "EAIaIQobChMI...",
"conversionDateTime": "2026-06-01 14:30:00-04:00"
},
"orderId": "ORDER-2026-1001",
"conversionAction": "customers/{customer_id}/conversionActions/{conversion_action_id}",
"adjustmentType": "ENHANCEMENT"
},
{}
],
"jobId": "2001",
"partialFailureError": {
"code": 3,
"message": "The required field was not present., at conversion_adjustments[1].order_id",
"details": [
{
"@type": "type.googleapis.com/google.ads.googleads.v26.errors.GoogleAdsFailure",
"errors": [
{
"errorCode": {
"fieldError": "REQUIRED"
},
"message": "The required field was not present.",
"location": {
"fieldPathElements": [
{
"fieldName": "conversion_adjustments",
"index": 1
},
{
"fieldName": "order_id"
}
]
}
}
]
}
]
}
}
查看导入情况
使用增强型转化 API 诊断报告验证增强型网站转化是否在有效运行,并诊断设置中的问题。
使用 线下数据诊断 查看近期导入的总体运行状况。
使用 GAQL 查询上传诊断信息
您还可以通过针对
转化客户 ID 查询
offline_conversion_upload_client_summary,以编程方式检查账号级上传运行状况、近期作业计数和错误
提醒:
SELECT
customer.id,
offline_conversion_upload_client_summary.client,
offline_conversion_upload_client_summary.status,
offline_conversion_upload_client_summary.total_event_count,
offline_conversion_upload_client_summary.successful_event_count,
offline_conversion_upload_client_summary.success_rate,
offline_conversion_upload_client_summary.pending_event_count,
offline_conversion_upload_client_summary.pending_rate,
offline_conversion_upload_client_summary.last_upload_date_time,
offline_conversion_upload_client_summary.alerts,
offline_conversion_upload_client_summary.daily_summaries,
offline_conversion_upload_client_summary.job_summaries
FROM offline_conversion_upload_client_summary
在报告广告系列转化指标时,请参阅
映射用户界面指标,将 Google Ads 界面指标与
Google Ads API 报告字段相关联。您还可以查询
conversion_action资源,以查看给定转化的总
次数和总转化价值
操作。
最佳做法
在实现增强型网站转化时,请牢记以下最佳做法。
检查客户标识符
导入转化时,客户 ID 必须设置为包含转化操作并执行转化跟踪的账号。如需检查
此设置,请查询投放 Google Ads Customer 资源
的 ConversionTrackingSetting。使用 GoogleAdsService.SearchStream 发出以下查询,以查找 customer.conversion_tracking_setting.google_ads_conversion_customer 的值。
SELECT
customer.conversion_tracking_setting.google_ads_conversion_customer,
customer.conversion_tracking_setting.conversion_tracking_status,
customer.conversion_tracking_setting.conversion_tracking_id,
customer.conversion_tracking_setting.cross_account_conversion_tracking_id
FROM customer
在导入转化的请求中,将 customer_id 设置为 google_ads_conversion_customer 值。
如果拥有多个标识符,请全部添加
如果您拥有转化的 GCLID,我们建议您将其与 user_identifiers 一起发送,以提高效果。此外,如果您拥有转化的多个 UserIdentifier,则添加所有这些标识符可以提高匹配的可能性。在同一 ConversionAdjustment 中添加所有标识符。
设置集成时查看部分失败错误
首次设置增强型网站转化集成时,
请查看并解决响应的
partial_failure_error
字段中的任何部分错误。如果设置中存在问题,您可以检查此字段以调查并解决这些问题。如需了解与
部分失败错误处理相关的更多详细信息和示例,请访问专门的
部分失败指南。
解决部分失败错误中显示的任何问题并完成集成后,请切换为使用 线下数据诊断定期查看转化的运行状况。
在单个请求中批量调整
如果您要导入多个调整,请将这些操作(每个请求最多 2,000
个转化调整)批量处理到一个
UploadConversionAdjustmentsRequest,
中,而不是为每个调整发送一个导入请求。
如需了解每个
请求的调整数量限制,请查看配额指南。如果您希望 线下数据诊断 将一组
请求归入同一个逻辑作业,请将所有
请求的 job_id 设置为相同的值。
问题排查
使用增强型转化 API 诊断报告 验证增强型网站转化是否在有效运行,并诊断设置中的问题。
调试常见错误
以下指南可帮助您诊断和修复增强型网站转化的常见错误。
| 错误 | |
|---|---|
CONVERSION_NOT_FOUND
|
找不到提供的转化操作和转化标识符对或
order_id 对应的转化。验证转化是否为请求的 customer_id 中指定的
Google Ads 转化客户 的 Google Ads 转化。此外,还要验证转化是否为点击,其中填充了 gbraid
或 wbraid 而不是
gclid。
Google Ads 不支持对这些转化使用增强型网站转化。
|
CUSTOMER_NOT_ACCEPTED_CUSTOMER_DATA_TERMS
|
尚未接受请求的
customer_id 的客户数据条款及条件。如需了解相关说明,请参阅
前提条件指南。
|
CONVERSION_ALREADY_ENHANCED
|
此转化已收到具有给定
order_id 和 conversion_action 的调整。请务必为每个转化提供唯一的 order_id。
|
CONVERSION_ACTION_NOT_ELIGIBLE_FOR_ENHANCEMENT
|
提供的 conversion_action 不符合增强型
网站转化的条件。在 Google Ads 界面中,请务必选中请求中引用的转化操作的 启用
增强型转化 复选框。如需了解相关说明,请参阅
帮助中心。
|