管理離線轉換

您可以使用 Google Ads API 將離線轉換匯入 Google Ads,追蹤促成離線銷售 (例如透過電話或業務代表) 的廣告。

為充分發揮匯入轉換資料的效益,建議您導入待開發客戶強化轉換,運用 Google 點擊 ID 和使用者提供的資料,盡可能提升資料準確度和成效。

強化轉換

強化轉換功能會使用電子郵件地址、電話號碼和郵寄地址等第一方轉換資料,補充轉換資料,協助您提升轉換評估的準確度。

強化轉換有兩種,詳情請參閱「關於強化轉換」。

以下章節說明如何強化離線轉換,這項功能也稱為待開發客戶強化轉換。

什麼是待開發客戶強化轉換?

待開發客戶強化轉換是升級版的離線轉換匯入,會將使用者提供的資料 (例如電子郵件地址) 用來補足匯入的離線轉換資料,進而提升評估準確度和出價成效。匯入離線轉換時,系統會將提供的經雜湊處理顧客數位資料,與您網站上收集的相同資料 (例如待開發客戶表單) 以及與廣告互動的已登入顧客進行比對,藉此將轉換歸因於 Google Ads 廣告活動。詳情請參閱「關於待開發客戶強化轉換」一文。

視您是否使用 Google 代碼追蹤網頁上的表單提交事件,導入待開發客戶強化轉換的方式有兩種。為確保最佳成效和耐用性,建議您使用 Google 代碼,導入待開發客戶強化轉換。

  • 如果您是從頭開始,請先參閱「必要條件」一節。
  • 如果您已設定離線轉換匯入,並想升級為待開發客戶強化轉換,建議先參閱「設定代碼」一節。
  • 如果您已設定 Google 代碼,或不打算使用 Google 代碼,且正要開始整合 Google Ads API,請跳至「API 導入」一節。
  • 如果您無法匯入使用者提供的資料,或仰賴外部歸因來計算轉換,請參閱舊版離線轉換匯入指南。

必要條件

首先,請確認您已完成入門指南中的步驟。

您必須先選擇加入強化轉換功能並接受顧客數位資料條款,才能使用待開發客戶強化轉換。您可以向 Google Ads 轉換客戶發出下列查詢,確認是否已符合這些必要條件:

SELECT
  customer.id,
  customer.conversion_tracking_setting.accepted_customer_data_terms,
  customer.conversion_tracking_setting.enablement_setting,
  customer.conversion_tracking_setting.effective_enablement_setting
FROM customer

如果 accepted_customer_data_terms 為 false,或 enablement_setting (使用跨帳戶轉換追蹤時為 effective_enablement_setting) 不是 ON,請按照「建立新的轉換動作」中的操作說明完成這些必要條件。

設定代碼

請按照這篇文章的操作說明,設定 Google 代碼,啟用待開發客戶強化轉換。如要使用 Google 代碼管理工具設定待開發客戶強化轉換,請按照這些 Google 代碼管理工具操作說明進行。

API 導入

以下是使用 Google Ads API 匯入待開發客戶強化轉換的整體流程。

  1. 將使用者提供的資料正規化並進行雜湊處理,例如電子郵件地址、電話號碼和郵寄地址。

  2. 以經過正規化和雜湊處理的使用者提供資料,填入 ClickConversion 物件。

  3. 使用 ConversionUploadService 將 ClickConversion 物件匯入 Google Ads API。詳情請參閱 UploadClickConversions。

  4. 查看匯入內容。

Request 和 ClickConversion 結構定義摘要

下表摘要列出待開發客戶強化轉換的 UploadClickConversionsRequest 和 ClickConversion 重要欄位 (如需完整欄位詳細資料,請參閱「填入 ClickConversion 物件」和「建構要求」):

欄位路徑 規定 格式和限制
customer_id 必填 設為 Google Ads 廣告轉換客戶 ID (customer.conversion_tracking_setting 的 google_ads_conversion_customer),不含連字號。
partial_failure 必填 必須設為 true,系統才會匯入有效轉換,並在 partial_failure_error 中傳回資料列層級錯誤。
validate_only 選用 如果設為 true,系統會驗證要求,但不會匯入轉換 (在 partial_failure_error 中傳回任何驗證錯誤)。
job_id 選用 非負數 int32 (0 至 2^31 - 1),可在 job_summaries 中將多個要求歸入一個邏輯工作。
conversions[].conversion_action 必填 ENABLED 轉換動作的資源名稱 (customers/{conversion_customer_id}/conversionActions/{action_id}),包含 type = UPLOAD_CLICKS。
conversions[].conversion_date_time 必填 必須晚於點擊時間,且包含時區偏移量:yyyy-mm-dd hh:mm:ss+|-hh:mm (例如 2026-06-01 14:30:00-04:00)。
conversions[].conversion_value和currency_code 建議 轉換價值 (double) 和 3 個字元的 ISO 4217 貨幣代碼 (例如 USD)。
conversions[].order_id 建議 每項轉換動作都有專屬交易 ID,可避免重複匯入,並支援日後調整。
conversions[].gclid/gbraid/wbraid 建議使用 (如果情況允許) 從到達網頁網址擷取的點擊 ID。如果可行,請一併提供 user_identifiers。
conversions[].user_identifiers[] 待開發客戶強化轉換的必要條件 每次轉換一到五個 UserIdentifier 物件。設定選用的 user_identifier_source (例如 FIRST_PARTY),以及 hashed_email (移除 gmail.com 和 googlemail.com 的 @ 前面的點和 + 後置字串,並轉換為小寫,SHA-256 十六進位) 或 hashed_phone_number (E.164 格式,SHA-256 十六進位);請參閱「正規化及雜湊處理資料」。系統不支援「address_info」。
conversions[].consent.ad_user_data 建議 在 Consent 上設為 GRANTED 或 DENIED。(ad_personalization 僅支援 OfflineUserDataJobService 和 UserDataService)。
conversions[].custom_variables和external_attribution_data 不要使用 user_identifiers 設定 包含 user_identifiers 的轉換不得設定 custom_variables 或 external_attribution_data,否則會遭拒。

擷取轉換動作資源名稱

如要上傳轉換,您必須指定在 Google Ads 中設定的 ConversionAction 資源名稱,以便匯入點擊轉換。您可以使用下列 GAQL 查詢,查詢 conversion_action 資源,找出資源名稱:

SELECT
  customer.id,
  conversion_action.id,
  conversion_action.name,
  conversion_action.type,
  conversion_action.resource_name
FROM conversion_action
WHERE conversion_action.type = 'UPLOAD_CLICKS'
  AND conversion_action.status = 'ENABLED'

正規化及雜湊處理使用者提供的資料

基於隱私權考量,請務必使用 SHA-256 雜湊處理,才能匯入下列資料:

  • 電子郵件地址
  • 電話號碼
  • 名字
  • 姓氏
  • 街道地址

請勿雜湊處理下列資料:

  • 國家/地區
  • 州/省
  • 城市
  • 郵遞區號

為標準化雜湊處理結果,在雜湊處理每個值前,請務必:

  • 移除開頭和結尾的空白字元。
  • 將文字轉換為小寫。
  • 根據 E.164 標準設定電話號碼格式。

強化轉換的電子郵件地址格式

為確保強化轉換的媒合率最高,請按照下列步驟正確格式化電子郵件地址並進行雜湊處理:

  1. 套用標準正規化 (所有電子郵件地址):

    • 移除開頭和結尾的 ASCII 空白字元。
    • 將電子郵件地址中的所有字元改成小寫。
  2. 套用特定網域的正規化 (僅限 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。
  3. 雜湊正規化電子郵件地址:

    • 將正規化電子郵件字串編碼為 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)
    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 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);
}

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

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): 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);
}
      

Python

def normalize_and_hash_email_address(email_address: str) -> str:
    """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: str = email_address.strip().lower()
    email_parts: list[str] = 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: str) -> str:
    """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 hashing.
  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;

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

curl

填入 ClickConversion 物件

UploadClickConversionsRequest 中的 ClickConversion 物件集合代表您要匯入的轉換組合。建立 ClickConversion 物件時,請注意下列事項:

gclid

GCLID 是使用者點按廣告並前往網站時,從網址參數擷取的 ID。

gbraid

gbraid 是一種網址參數,使用者在網路上點按廣告並前往 iOS 應用程式時,就會顯示這個參數。

wbraid

wbraid 是網址參數,當使用者點按 iOS 應用程式中的廣告並前往您的網頁時,就會顯示這個參數。

cart_data

包含轉換的項目層級詳細資料。您必須填入 cart_data 欄位,才能在 Google Ads UI 中回報購物籃資料,例如購買的商品、價格和數量。請參閱 CartData 物件定義,瞭解必要結構,並參閱「透過購物車資料回報的轉換」一文,瞭解詳情。

user_identifiers

使用待開發客戶強化轉換時,必須在 user_identifiers 欄位中填入經過正規化和雜湊處理的使用者提供資料。如果您有多個使用者 ID,請為每個 ID 建立個別的 UserIdentifier,最多可建立五個 ID。

conversion_date_time

轉換的日期和時間。

值必須指定時區,且格式須為 yyyy-mm-dd HH:mm:ss+|-HH:mm,例如:2022-01-01 19:32:45-05:00 (忽略日光節約時間)。

時區可以是任何有效值,不一定要與帳戶時區相符。不過,如果您打算比較匯入的轉換資料與 Google Ads 使用者介面中的資料,建議使用與 Google Ads 帳戶相同的時區,這樣轉換次數才會一致。如需更多詳細資料和範例,請參閱「準備要匯入的資料」,並查看「代碼和格式」一文,瞭解有效的時區 ID 清單。

conversion_action

離線轉換的 ConversionAction 資源名稱。

轉換動作的 type 必須為 UPLOAD_CLICKS,且必須存在於與點擊相關聯的 Google Ads 帳戶的 Google Ads 廣告轉換客戶中。

conversion_value

轉換價值。

currency_code

conversion_value 的貨幣代碼。

consent

強烈建議您填入 ClickConversion 物件的 consent 欄位。如果未設定,轉換可能無法歸因。

order_id

也稱為轉換的交易 ID。這個欄位為選填欄位,但極力建議您填寫,因為這樣在進行調整時,就能更輕鬆地參照匯入的轉換。如果您在匯入時設定了交易 ID,就必須使用該值進行任何調整。如要進一步瞭解如何使用交易 ID 避免重複計算轉換,請參閱「使用交易 ID 避免重複計算轉換」一文。

custom_variables

自訂轉換變數的值。Google Ads 不支援自訂轉換變數與 wbraid 或 gbraid 搭配使用。

conversion_environment

表示記錄這項轉換的環境。例如 APP 或 WEB。

session_attributes_encoded和session_attributes_key_value_pairs

工作階段屬性代表用於轉換歸因的匯總 ID。除了 Google 點擊 ID 和網址參數 (例如 GBRAID) 之外,這些資料也會與使用者提供的資料搭配使用,而使用者提供的資料是待開發客戶強化轉換功能的核心。匯入工作階段屬性的方式有兩種:提供瀏覽器中 JavaScript 程式碼產生的編碼權杖,或為每個 ID 提供個別鍵/值組合。

為盡量提升廣告活動成效,建議盡可能匯入點擊 ID、使用者提供的資料和工作階段屬性,以及所有轉換。

Java

// Sets one of the sessionAttributesEncoded or sessionAttributesKeyValuePairs if either is
// provided. The session attribute fields are only available to allowlisted users.
// To include these fields in conversion imports, upgrade to the Data Manager API.
if (rawRecord.containsKey("sessionAttributesEncoded")) {
  clickConversionBuilder.setSessionAttributesEncoded(
      ByteString.copyFromUtf8(rawRecord.get("sessionAttributesEncoded")));
} else if (rawRecord.containsKey("sessionAttributesMap")) {
  List<String> pairings =
      Arrays.stream(rawRecord.get("sessionAttributesMap").split(" "))
          .map(String::trim)
          .collect(Collectors.toList());
  SessionAttributesKeyValuePairs.Builder sessionAttributePairs =
      SessionAttributesKeyValuePairs.newBuilder();
  for (String pair : pairings) {
    String[] parts = pair.split("=", 2);
    if (parts.length != 2) {
      throw new IllegalArgumentException(
          "Failed to read the sessionAttributesMap. SessionAttributesMap must use a"
              + " space-delimited list of session attribute key value pairs. Each pair should"
              + " be separated by an equal sign, for example: 'gad_campaignid=12345"
              + " gad_source=1'");
    }
    sessionAttributePairs.addKeyValuePairs(
        SessionAttributeKeyValuePair.newBuilder()
            .setSessionAttributeKey(parts[0])
            .setSessionAttributeValue(parts[1])
            .build());
  }
  clickConversionBuilder.setSessionAttributesKeyValuePairs(sessionAttributePairs.build());
}
      

C#

// The session attribute fields are only available to allowlisted users. To
// include these fields in conversion imports, upgrade to the Data Manager API.
if (!string.IsNullOrEmpty(sessionAttributesEncoded))
{
    clickConversion.SessionAttributesEncoded =
        ByteString.CopyFrom(sessionAttributesEncoded, Encoding.Unicode);
}
else if (!string.IsNullOrEmpty(sessionAttributes))
{
    IEnumerable<SessionAttributeKeyValuePair> parsedSessionAttributes =
        sessionAttributes.Split(';').Select(pair => {
            string[] split = pair.Split('=');
            return new SessionAttributeKeyValuePair()
            {
                SessionAttributeKey = split[0],
                SessionAttributeValue = split[1]
            };
        });

    clickConversion.SessionAttributesKeyValuePairs =
        new SessionAttributesKeyValuePairs();
    clickConversion.SessionAttributesKeyValuePairs.KeyValuePairs
        .AddRange(parsedSessionAttributes);
}
      

PHP

This example is not yet available in PHP; you can take a look at the other languages.
    

Python

# Set one of the session_attributes_encoded or
# session_attributes_key_value_pairs fields if either are provided.
# The session attribute fields are only available to allowlisted users.
# To include these fields in conversion imports, upgrade to the Data Manager API.
if session_attributes_encoded:
    click_conversion.session_attributes_encoded = session_attributes_encoded
elif session_attributes_dict:
    for key, value in session_attributes_dict.items():
        pair: SessionAttributeKeyValuePair = client.get_type(
            "SessionAttributeKeyValuePair"
        )
        pair.session_attribute_key = key
        pair.session_attribute_value = value
        click_conversion.session_attributes_key_value_pairs.key_value_pairs.append(
            pair
        )
      

小茹

# Set one of the session_attributes_encoded or
# session_attributes_key_value_pairs fields if either are provided.
# The session attribute fields are only available to allowlisted users.
# To include these fields in conversion imports, upgrade to the Data Manager API.
if session_attributes_encoded != nil
  cc.class.module_eval { attr_accessor :session_attributes_encoded}
  cc.session_attributes_encoded = session_attributes_encoded
elsif session_attributes_hash != nil
  # Add new attribute to click conversion object
  cc.class.module_eval { attr_accessor :session_attributes_key_value_pairs}
  cc.session_attributes_key_value_pairs = ::Google::Ads::GoogleAds::V19::Services::SessionAttributesKeyValuePairs.new

  # Loop thru inputted session_attributes_hash to populate session_attributes_key_value_pairs
  session_attributes_hash.each do |key, value|
    pair = ::Google::Ads::GoogleAds::V19::Services::SessionAttributeKeyValuePair.new
    pair.session_attribute_key = key
    pair.session_attribute_value = value
    cc.session_attributes_key_value_pairs.key_value_pairs << pair
  end
end    
      

Perl

# Set one of the session_attributes_encoded or session_attributes_key_value_pairs
# fields if either are provided.
if (defined $session_attributes_encoded) {
  $click_conversion->{sessionAttributesEncoded} = $session_attributes_encoded;
} elsif (defined $session_attributes_hash) {
  while (my ($key, $value) = each %$session_attributes_hash) {
    my $pair =
      Google::Ads::GoogleAds::V26::Services::ConversionUploadService::SessionAttributeKeyValuePair
      ->new({sessionAttributeKey => $key, sessionAttributeValue => $value});
    push @{$click_conversion->{sessionAttributesKeyValuePairs}{keyValuePairs}
    }, $pair;
  }
}
      

curl

user_ip_address

顧客在點按廣告後抵達到達網頁,以及發生轉換事件前的 IP 位址。這是顧客裝置的 IP 位址,而非廣告主伺服器的 IP 位址。

這個欄位是字串,代表 IPv4 或 IPv6 格式的 IP 位址。例如:

  • IPv4:"192.0.2.0"
  • IPv6:"2001:0DB8:1234:5678:9999:1111:0000:0001"

程式碼範例

以下範例說明如何將正規化和雜湊處理的使用者提供資料,設定到 ClickConversion 物件。

Java

// 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+myalias@gmail.com")
        // 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("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());
}
if (sessionAttributesEncoded != null) {
  rawRecordBuilder.put("sessionAttributesEncoded", sessionAttributesEncoded);
}
if (sessionAttributesMap != null) {
  rawRecordBuilder.put("sessionAttributesMap", sessionAttributesMap);
}

// 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(normalizeAndHashPhoneNumber(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);
      

C#

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

PHP

// 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,
    'sessionAttributesEncoded' => $sessionAttributesEncoded,
    'sessionAttributesDict' => $sessionAttributesDict
];

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

Python

# 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: Dict[str, Union[str, float]] = {
    # 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: ClickConversion = 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: UserIdentifier = 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 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: UserIdentifier = 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,
  "session_attributes_encoded" => session_attributes_encoded,
  "session_attributes_hash" => session_attributes_hash
}

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

  # Set one of the session_attributes_encoded or
  # session_attributes_key_value_pairs fields if either are provided.
  # The session attribute fields are only available to allowlisted users.
  # To include these fields in conversion imports, upgrade to the Data Manager API.
  if session_attributes_encoded != nil
    cc.class.module_eval { attr_accessor :session_attributes_encoded}
    cc.session_attributes_encoded = session_attributes_encoded
  elsif session_attributes_hash != nil
    # Add new attribute to click conversion object
    cc.class.module_eval { attr_accessor :session_attributes_key_value_pairs}
    cc.session_attributes_key_value_pairs = ::Google::Ads::GoogleAds::V19::Services::SessionAttributesKeyValuePairs.new

    # Loop thru inputted session_attributes_hash to populate session_attributes_key_value_pairs
    session_attributes_hash.each do |key, value|
      pair = ::Google::Ads::GoogleAds::V19::Services::SessionAttributeKeyValuePair.new
      pair.session_attribute_key = key
      pair.session_attribute_value = value
      cc.session_attributes_key_value_pairs.key_value_pairs << pair
    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_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?
    cc.user_identifiers << client.resource.user_identifier do |ui|
      ui.hashed_phone_number = normalize_and_hash(raw_record["phone"])
    end
  end
end
      

Perl

# Create an empty click conversion.
my $click_conversion =
  Google::Ads::GoogleAds::V26::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::V26::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::V26::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::V26::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;
      

curl

這個範例說明如何在 ClickConversion 物件上設定其他必要欄位。

Java

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

// Sets one of the sessionAttributesEncoded or sessionAttributesKeyValuePairs if either is
// provided. The session attribute fields are only available to allowlisted users.
// To include these fields in conversion imports, upgrade to the Data Manager API.
if (rawRecord.containsKey("sessionAttributesEncoded")) {
  clickConversionBuilder.setSessionAttributesEncoded(
      ByteString.copyFromUtf8(rawRecord.get("sessionAttributesEncoded")));
} else if (rawRecord.containsKey("sessionAttributesMap")) {
  List<String> pairings =
      Arrays.stream(rawRecord.get("sessionAttributesMap").split(" "))
          .map(String::trim)
          .collect(Collectors.toList());
  SessionAttributesKeyValuePairs.Builder sessionAttributePairs =
      SessionAttributesKeyValuePairs.newBuilder();
  for (String pair : pairings) {
    String[] parts = pair.split("=", 2);
    if (parts.length != 2) {
      throw new IllegalArgumentException(
          "Failed to read the sessionAttributesMap. SessionAttributesMap must use a"
              + " space-delimited list of session attribute key value pairs. Each pair should"
              + " be separated by an equal sign, for example: 'gad_campaignid=12345"
              + " gad_source=1'");
    }
    sessionAttributePairs.addKeyValuePairs(
        SessionAttributeKeyValuePair.newBuilder()
            .setSessionAttributeKey(parts[0])
            .setSessionAttributeValue(parts[1])
            .build());
  }
  clickConversionBuilder.setSessionAttributesKeyValuePairs(sessionAttributePairs.build());
}

// Calls build to build the conversion.
ClickConversion clickConversion = clickConversionBuilder.build();
      

C#

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

// The session attribute fields are only available to allowlisted users. To
// include these fields in conversion imports, upgrade to the Data Manager API.
if (!string.IsNullOrEmpty(sessionAttributesEncoded))
{
    clickConversion.SessionAttributesEncoded =
        ByteString.CopyFrom(sessionAttributesEncoded, Encoding.Unicode);
}
else if (!string.IsNullOrEmpty(sessionAttributes))
{
    IEnumerable<SessionAttributeKeyValuePair> parsedSessionAttributes =
        sessionAttributes.Split(';').Select(pair => {
            string[] split = pair.Split('=');
            return new SessionAttributeKeyValuePair()
            {
                SessionAttributeKey = split[0],
                SessionAttributeValue = split[1]
            };
        });

    clickConversion.SessionAttributesKeyValuePairs =
        new SessionAttributesKeyValuePairs();
    clickConversion.SessionAttributesKeyValuePairs.KeyValuePairs
        .AddRange(parsedSessionAttributes);
}

      

PHP

// 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']])
    );
}

// Set one of the sessionAttributesEncoded or
// SessionAttributeKeyValuePair fields if either are provided. The session attribute
// fields are only available to allowlisted users. To include these fields in conversion
// imports, upgrade to the Data Manager API.
if (!empty($sessionAttributesEncoded)) {
    $clickConversion->setSessionAttributesEncoded($sessionAttributesEncoded);
} elseif (!empty($sessionAttributesDict)) {
    // Create a new container object to hold key-value pairs.
    $sessionAttributesKeyValuePairs = new SessionAttributesKeyValuePairs();
    // Initialize an array to hold individual key-value pair messages.
    $keyValuePairs = [];
    // Append each key-value pair provided to the $keyValuePairs array
    foreach ($sessionAttributesDict as $key => $value) {
        $pair = new SessionAttributeKeyValuePair();
        $pair->setSessionAttributeKey($key);
        $pair->setSessionAttributeValue($value);
        $keyValuePairs[] = $pair;
    }
    // Set the the full list of key-value pairs on the container object.
    $sessionAttributesKeyValuePairs->setKeyValuePairs($keyValuePairs);
    // Attach the container of key-value pairs to the ClickConversion object.
    $clickConversion->setSessionAttributesKeyValuePairs($sessionAttributesKeyValuePairs);
}
      

Python

# Add details of the conversion.
# Gets the conversion action resource name.
conversion_action_service: ConversionActionServiceClient = (
    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"]
    ]

# Set one of the session_attributes_encoded or
# session_attributes_key_value_pairs fields if either are provided.
# The session attribute fields are only available to allowlisted users.
# To include these fields in conversion imports, upgrade to the Data Manager API.
if session_attributes_encoded:
    click_conversion.session_attributes_encoded = session_attributes_encoded
elif session_attributes_dict:
    for key, value in session_attributes_dict.items():
        pair: SessionAttributeKeyValuePair = client.get_type(
            "SessionAttributeKeyValuePair"
        )
        pair.session_attribute_key = key
        pair.session_attribute_value = value
        click_conversion.session_attributes_key_value_pairs.key_value_pairs.append(
            pair
        )
      

小茹

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

# Set one of the session_attributes_encoded or
# session_attributes_key_value_pairs fields if either are provided.
# The session attribute fields are only available to allowlisted users.
# To include these fields in conversion imports, upgrade to the Data Manager API.
if session_attributes_encoded != nil
  cc.class.module_eval { attr_accessor :session_attributes_encoded}
  cc.session_attributes_encoded = session_attributes_encoded
elsif session_attributes_hash != nil
  # Add new attribute to click conversion object
  cc.class.module_eval { attr_accessor :session_attributes_key_value_pairs}
  cc.session_attributes_key_value_pairs = ::Google::Ads::GoogleAds::V19::Services::SessionAttributesKeyValuePairs.new

  # Loop thru inputted session_attributes_hash to populate session_attributes_key_value_pairs
  session_attributes_hash.each do |key, value|
    pair = ::Google::Ads::GoogleAds::V19::Services::SessionAttributeKeyValuePair.new
    pair.session_attribute_key = key
    pair.session_attribute_value = value
    cc.session_attributes_key_value_pairs.key_value_pairs << pair
  end
end    
      

Perl

# Add details of the conversion.
$click_conversion->{conversionAction} =
  Google::Ads::GoogleAds::V26::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::V26::Common::Consent->new({
      adUserData => $raw_record->{adUserDataConsent}});
}

# Set one of the session_attributes_encoded or session_attributes_key_value_pairs
# fields if either are provided.
if (defined $session_attributes_encoded) {
  $click_conversion->{sessionAttributesEncoded} = $session_attributes_encoded;
} elsif (defined $session_attributes_hash) {
  while (my ($key, $value) = each %$session_attributes_hash) {
    my $pair =
      Google::Ads::GoogleAds::V26::Services::ConversionUploadService::SessionAttributeKeyValuePair
      ->new({sessionAttributeKey => $key, sessionAttributeValue => $value});
    push @{$click_conversion->{sessionAttributesKeyValuePairs}{keyValuePairs}
    }, $pair;
  }
}
      

curl

建構要求

設定 ClickConversion 物件並將其新增至 UploadClickConversionsRequest 物件的 conversions 欄位後,請設定下列欄位,並將要求傳送至 ConversionUploadService 的 UploadClickConversions 方法。

customer_id
請將此值設為點擊來源帳戶的 Google Ads 轉換客戶。如果不確定哪個帳戶正確,請參閱「入門指南」一節中範例查詢的 customer.conversion_tracking_setting.google_ads_conversion_customer 欄位。
job_id

提供機制,將匯入要求與離線資料診斷中的每項工作資訊建立關聯。

如未設定這個欄位,Google Ads API 會為每項要求指派 [2^31, 2^63) 範圍內的專屬值。如要將多個要求分組為單一邏輯工作,請將這個欄位設為工作內每個要求在 [0, 2^31) 範圍內的值。

無論您是否指定值,或讓 Google Ads API 指派值,response 中的 job_id 都會包含要求的作業 ID。

partial_failure

匯入轉換時,這個欄位必須設為 true。處理回應時,請遵循部分失敗指南。

匯入要求

填入 ClickConversion 物件並建構要求後,即可提交匯入作業。

Java

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

C#

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

      

PHP

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

Python

# Creates the conversion upload service client.
conversion_upload_service: ConversionUploadServiceClient = (
    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: UploadClickConversionsResponse = (
    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
      

Perl

# 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"
  });
      

curl

REST 要求和回應結構

透過 REST 呼叫 ConversionUploadService.UploadClickConversions 時,請傳送 POST 要求,並將 partialFailure 設為 true:

POST https://googleads.googleapis.com/v26/customers/{customer_id}:uploadClickConversions
{
  "partialFailure": true,
  "jobId": 1001,
  "conversions": [
    {
      "conversionAction": "customers/{customer_id}/conversionActions/{conversion_action_id}",
      "conversionDateTime": "2026-06-01 14:30:00-04:00",
      "conversionValue": 125.50,
      "currencyCode": "USD",
      "orderId": "ORDER-2026-0001",
      "gclid": "EAIaIQobChMI...",
      "consent": {
        "adUserData": "GRANTED"
      },
      "userIdentifiers": [
        {
          "userIdentifierSource": "FIRST_PARTY",
          "hashedEmail": "f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a"
        },
        {
          "userIdentifierSource": "FIRST_PARTY",
          "hashedPhoneNumber": "42975f8f9e46c2e13c1a2294957e5cb8d8e6f4f7341a036c6e595bc9f5e24621"
        }
      ]
    },
    {
      "conversionAction": "customers/{customer_id}/conversionActions/{conversion_action_id}",
      "conversionDateTime": "2026-06-01 14:35:00-04:00",
      "conversionValue": 80.00,
      "currencyCode": "USD",
      "orderId": "ORDER-2026-0002",
      "gclid": "EAIaIQobChMI_expired...",
      "consent": {
        "adUserData": "GRANTED"
      }
    }
  ]
}

在這個包含兩項轉換的批次中,如果第二個項目失敗,成功的資料列會在 results[] 中傳回已填入的 ClickConversionResult 項目,而失敗的資料列則會在 results[] 中傳回空白的 {} 物件,並在 UploadClickConversionsResponse 上傳回 partialFailureError 中的錯誤詳細資料:

{
  "results": [
    {
      "conversionAction": "customers/{customer_id}/conversionActions/{conversion_action_id}",
      "conversionDateTime": "2026-06-01 14:30:00-04:00",
      "gclid": "EAIaIQobChMI...",
      "userIdentifiers": [
        {
          "userIdentifierSource": "FIRST_PARTY",
          "hashedEmail": "f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a"
        },
        {
          "userIdentifierSource": "FIRST_PARTY",
          "hashedPhoneNumber": "42975f8f9e46c2e13c1a2294957e5cb8d8e6f4f7341a036c6e595bc9f5e24621"
        }
      ]
    },
    {}
  ],
  "jobId": "1001",
  "partialFailureError": {
    "code": 3,
    "message": "The click associated with the given identifier or iOS URL parameter occurred less recently than the maximum lookback window., at conversions[1].gclid",
    "details": [
      {
        "@type": "type.googleapis.com/google.ads.googleads.v26.errors.GoogleAdsFailure",
        "errors": [
          {
            "errorCode": {
              "conversionUploadError": "EXPIRED_EVENT"
            },
            "message": "The click associated with the given identifier or iOS URL parameter occurred less recently than the maximum lookback window.",
            "location": {
              "fieldPathElements": [
                {
                  "fieldName": "conversions",
                  "index": 1
                },
                {
                  "fieldName": "gclid"
                }
              ]
            }
          }
        ]
      }
    ]
  }
}

檢查匯入內容

使用待開發客戶強化轉換診斷報告,查看近期匯入作業的整體健康狀態。

使用 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

匯入的轉換會反映在原始點擊的曝光日期報表中,而非匯入要求日期或conversion_date_time的ClickConversion日期。

如果是最終點擊歸因,匯入的轉換統計資料最多需要三小時,才會顯示在 Google Ads 帳戶中。如果是其他搜尋歸因模式,可能需要超過三小時。詳情請參閱資料更新間隔指南。

製作廣告活動轉換指標報表時,請參閱「對應使用者介面指標」,將 Google Ads UI 指標與 Google Ads API 報表欄位建立關聯。您也可以查詢 conversion_action 資源,查看特定轉換動作的轉換總數和總轉換價值。

最佳做法

導入待開發客戶強化轉換時,請注意下列最佳做法。

無論完整性如何,一律傳送所有轉換資料

為確保產生完整、準確的轉換報表,請匯入所有可用的離線轉換事件 (包括可能不是來自 Google Ads 的事件),僅包含使用者提供資料的轉換仍有助於 Google Ads 廣告活動最佳化。

如果您為轉換指派 order_id,建議您加入這項資訊。如果您有轉換的 Google 點擊 ID,建議一併傳送該 ID 和 user_identifiers,以提升成效。此外,如果轉換有 多個 UserIdentifier,請將所有納入 ClickConversion 物件,提高比對成功的機率。

在單一要求中批次處理多項轉換

如有多項轉換要匯入,請將轉換批次匯入單一 UploadClickConversionsRequest,而不是為每項轉換傳送匯入要求。

請參閱配額指南,瞭解每個要求可上傳的轉換次數上限。

如要讓離線資料診斷將一組要求歸入同一個邏輯工作,請將所有要求的 job_id 設為相同的值。如果您有單一工作或程序,需要使用多個要求匯入大量轉換,這項功能就非常實用。如果將每個要求的 job_id 設為相同值,即可從 job_summaries 擷取單一工作項目。如果改為讓 Google Ads API 為每個要求指派系統產生的值job_id,則 job_summaries 會包含每個要求的個別項目,這可能會增加分析工作整體健康狀態的難度。

不使用外部歸因資料

使用待開發客戶強化轉換時,請勿在 ClickConversion 上設定 external_attribution_data,或指定使用外部歸因模式的 conversion_action。Google Ads 不支援使用使用者提供的資料匯入外部已歸因轉換。

不含自訂變數

使用待開發客戶強化轉換時,請勿加入任何 custom_variables。Google Ads 不支援在轉換匯入中使用自訂變數和使用者提供的資料。如果轉換包含使用者提供的資料,且包含自訂變數,系統會判定這些轉換無效並捨棄。

疑難排解

離線資料診斷提供單一資源,可供您持續查看匯入資料的整體健康狀態。不過,在導入期間,您可以使用本節中的資訊,調查回應的 partial_failure_error 欄位中回報的任何錯誤。

匯入轉換動作時,最常見的錯誤是授權錯誤,例如 USER_PERMISSION_DENIED。請仔細檢查要求中的客戶 ID 是否已設為擁有轉換動作的 Google Ads 轉換客戶。如需更多詳細資訊,請參閱授權指南。如需偵錯這些不同錯誤的提示,請參閱常見錯誤指南。

排解常見錯誤

以下指引有助於診斷及修正待開發客戶強化轉換的常見錯誤。

錯誤
NO_CONVERSION_ACTION_FOUND

指定的轉換動作未啟用,或要求中 customer_id 欄位指定的客戶帳戶無法存取該動作。請確認上傳的轉換動作已啟用,且屬於傳送上傳要求的客戶。

如果要求中的 Google 點擊 ID 屬於無權存取要求中指定轉換動作的客戶帳戶,也可能發生這項錯誤。您可以使用 click_view 資源,提交依 click_view.gclid 和 segments.date 篩選的查詢,驗證 Google 點擊 ID 是否屬於客戶帳戶,其中日期是點擊發生的日期。

INVALID_CONVERSION_ACTION_TYPE 指定的轉換動作類型不適用於待開發客戶強化轉換。請確認上傳要求中指定的 ConversionAction 類型為 UPLOAD_CLICKS。
CUSTOMER_NOT_ENABLED_ENHANCED_CONVERSIONS_FOR_LEADS 請確認您已在轉換設定中啟用待開發客戶強化轉換。如需相關操作說明,請參閱必要條件指南。
DUPLICATE_ORDER_ID 匯入的事件包含具有相同訂單 ID 的多個轉換,因此無法處理。 請確認訂單 ID 並未重複,然後再試一次。
CLICK_NOT_FOUND 找不到與提供的使用者 ID 相符的點擊。

如果轉換遇到這項警告,Google Ads API 會將其納入離線資料診斷的 successful_event_count。Google Ads API 在 alerts 集合中包含 CLICK_NOT_FOUND 項目,方便您監控這項警告的頻率。

如果點擊並非來自 Google Ads 廣告活動,就會發生這項錯誤。例如,可能來自 SA360 或 DV360。其他可能原因如下:

在極少數情況下,如果上傳客戶與 Google Ads 轉換客戶不同,這項錯誤可能表示上傳客戶已接受顧客數位資料條款,但放送客戶尚未接受。

如要確認帳戶是否已接受顧客數位資料條款,請查詢 customer 資源,並檢查 customer.conversion_tracking_setting.accepted_customer_data_terms 欄位。