リードの拡張コンバージョンを実装する

見込み顧客向けの拡張コンバージョンを使用すると、ハッシュ化されたユーザー ID を含むクリック コンバージョンと、Google 広告でコンバージョンを見込み顧客を獲得した広告に関連付けるのに役立つ追加情報をアップロードすることで、オフライン コンバージョン測定の精度を高めることができます。

実装を始める前に、スタートガイドガイドを確認し、リードの拡張コンバージョンの前提条件を実装してください。

見込み顧客の拡張コンバージョンは、ヘルプセンターで説明されているように Google 広告の管理画面から、またはこのガイドで説明されているように Google Ads API からアップロードできます。

統合を設計する

統合を設計できます。

使用フロー

Google Ads API でリードの拡張コンバージョンをアップロードする全体的なフローについては、以下をご覧ください。

  1. 次の前提条件が実装されていることを確認します。

    1. コンバージョン トラッキングを有効にします。

    2. 顧客データに関する規約に同意します。

    3. ウェブサイトのリードフォームでタグ設定を構成します。

    詳細なガイダンスについては、前提条件を実装するをご覧ください。

  2. メールアドレス、電話番号、郵送先住所などの見込み顧客データを正規化してハッシュ化します。

  3. 正規化およびハッシュ化した見込み顧客データを ClickConversion オブジェクトに格納します。各 ClickConversion について:

    1. 正規化されハッシュ化された見込み顧客データを user_identifiers に入力します。使用可能なユーザー ID が複数ある場合は、それぞれに個別の UserIdentifier を作成します(最大 5 つの ID)。

    2. (省略可ですが、強く推奨します)order_id に入力します。

    3. (省略可)最も正確な測定を行うには、gclid に入力します。

    4. ClickConversion オブジェクトの consent フィールドに値を入力してください。

    5. conversion_action を、typeUPLOAD_CLICKSConversionAction のリソース名に設定します。これは、前提条件の実装時に作成した ConversionAction のリソース名にする必要があります。

  4. ClickConversion 作成オペレーションを ConversionUploadService にアップロードし、partial_failuretrue に設定します。

  5. アップロードを確認します。

ベスト プラクティス

見込み顧客向けの拡張コンバージョンを実装する際は、次のベスト プラクティスに留意してください。

お客様 ID を確認する

コンバージョンをアップロードする際は、コンバージョン アクションを含み、コンバージョン トラッキングが行われるアカウントにお客様 ID を設定する必要があります。この設定を確認するには、サービング中の Google 広告 Customer リソースで ConversionTrackingSetting をクエリします。GoogleAdsService.SearchStream を使用して次のクエリを発行し、customer.conversion_tracking_setting.google_ads_conversion_customer の値を確認します。

複数の ID がある場合は、すべて含める

コンバージョンに order_id を割り当てる場合は、その order_id を含めることを強くおすすめします。コンバージョンに gclid がある場合は、user_identifiers に加えて送信することをおすすめします。これにより、パフォーマンスが向上します。さらに、コンバージョンに複数の UserIdentifier がある場合は、複数を含めることで一致の可能性が高まります。すべての識別子を同じ ClickConversion に含めます。

統合の設定時に Partial Failure エラーを確認する

リードの拡張コンバージョンの統合を初めて設定する場合は、レスポンスの partial_failure_error フィールドで部分的なエラーがないかを確認し、エラーがある場合は修正します。設定に問題がある場合は、このフィールドを調べて問題を調査し、対処する必要があります。部分的障害によるエラー処理の詳細と例については、専用の部分的障害ガイドをご覧ください。

部分的な失敗エラーを確認する際は、トラブルシューティング ガイドの一般的なエラーの表を参照してください。部分的なエラーで発生した問題を解決し、統合が完了したら、オフライン データ診断を使用して、コンバージョンの健全性を定期的に確認します。

1 つのリクエストで複数のコンバージョンをバッチ処理する

アップロードするコンバージョンが複数ある場合は、コンバージョンごとにアップロード リクエストを送信するのではなく、オペレーションを 1 つの UploadClickConversionsRequest にバッチ処理します。

リクエストごとのコンバージョン数の制限については、割り当てガイドをご覧ください。

オフライン データ診断で、リクエストのセットを同じ論理ジョブにグループ化する場合、すべてのリクエストの job_id を同じ値に設定します。これは、複数のリクエストを使用して大量のコンバージョンをアップロードする単一のジョブまたはプロセスがある場合に便利です。これらのリクエストの job_id を同じ値に設定すると、job_summaries からジョブのエントリを 1 つ取得できます。システムが生成した値を各リクエストの job_id に割り当てることを Google Ads API に任せた場合、job_summaries にはリクエストごとに個別のエントリが含まれるため、ジョブの全体的な健全性の分析が難しくなる可能性があります。

利用可能なすべてのオフライン コンバージョン イベントをアップロードする

コンバージョン レポートが正確で完全なものになるよう、Google 広告で発生したイベントも含め、利用可能なすべてのオフライン コンバージョン イベントをアップロードします。

すべてのコンバージョン イベントをアップロードすると、Google 広告以外のイベントで CLICK_NOT_FOUND エラーが発生します。これらのエラーは、すべてのコンバージョン イベントをアップロードする際に発生することが想定されるため、UploadClickConversionsRequest には debug_enabled フィールドがあります。

  • debug_enabledfalse の場合、または設定されていない場合、Google Ads API は基本的な入力検証のみを行い、その後のアップロード チェックはスキップします。また、指定された user_identifiers でクリックが検出されない場合でも、成功を返します。

    これがデフォルトです。

  • debug_enabledtrue の場合、Google Ads API はすべての検証を実行し、指定された user_identifiers に対応する Google 広告コンバージョンがないすべての ClickConversion について CLICK_NOT_FOUND エラーを返します。

開発時とテスト時に debug_enabledtrue に設定すると、問題を特定できます。たとえば、Google 広告のコンバージョンであることがわかっているコンバージョンと user_identifiers のセットがある場合は、true 設定を使用して、アップロードによって CLICK_NOT_FOUND エラーが発生しないことを検証できます。ただし、開発とテストを終えたら、過剰なエラーが発生しないように debug_enabledfalse に設定することをおすすめします。

外部のアトリビューション データを使用しない

ClickConversionexternal_attribution_data を設定したり、外部アトリビューション モデルを使用する conversion_action を指定したりしないでください。Google 広告では、ID を使用したアップロードの外部貢献度割り当てコンバージョンはサポートされていません。

アップロードするデータを準備する

プライバシー保護の観点から、次のデータはアップロードする前に SHA-256 を使用してハッシュ化する必要があります。

  • メールアドレス
  • 電話番号
  • 番地

次のデータはハッシュ化しないでください

  • 都道府県
  • 市区町村
  • 郵便番号

ハッシュ結果を標準化するには、これらの値のいずれかをハッシュ化する前に、次のことを行う必要があります。

  • 先頭と末尾の空白文字を削除する。
  • テキストを小文字に変換する。
  • 電話番号を E164 規格の形式にする。
  • gmail.comgooglemail.com のメールアドレスのドメイン名の前にあるすべてのピリオド(.)を削除する。

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 preceding {@code gmail.com} or {@code googlemail.com}.
 *
 * @param digest the digest to use to hash the normalized string.
 * @param emailAddress the email address to normalize and hash.
 */
private String normalizeAndHashEmailAddress(MessageDigest digest, String emailAddress)
    throws UnsupportedEncodingException {
  String normalizedEmail = emailAddress.toLowerCase();
  String[] emailParts = normalizedEmail.split("@");
  if (emailParts.length > 1 && emailParts[1].matches("^(gmail|googlemail)\\.com\\s*")) {
    // Removes any '.' characters from the portion of the email address before the domain if the
    // domain is gmail.com or googlemail.com.
    emailParts[0] = emailParts[0].replaceAll("\\.", "");
    normalizedEmail = String.format("%s@%s", emailParts[0], emailParts[1]);
  }
  return normalizeAndHash(digest, normalizedEmail);
}
      

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):
    """Returns the result of normalizing and hashing an email address.

    For this use case, Google Ads requires removal of any '.' characters
    preceding "gmail.com" or "googlemail.com"

    Args:
        email_address: An email address to normalize.

    Returns:
        A normalized (lowercase, removed whitespace) and SHA-265 hashed string.
    """
    normalized_email = email_address.lower()
    email_parts = normalized_email.split("@")
    # Checks whether the domain of the email address is either "gmail.com"
    # or "googlemail.com". If this regex does not match then this statement
    # will evaluate to None.
    is_gmail = re.match(r"^(gmail|googlemail)\.com$", email_parts[1])

    # Check that there are at least two segments and the second segment
    # matches the above regex expression validating the email domain name.
    if len(email_parts) > 1 and is_gmail:
        # Removes any '.' characters from the portion of the email address
        # before the domain if the domain is gmail.com or googlemail.com.
        email_parts[0] = email_parts[0].replace(".", "")
        normalized_email = "@".join(email_parts)

    return normalize_and_hash(normalized_email)


def normalize_and_hash(s):
    """Normalizes and hashes a string with SHA-256.

    Private customer data must be hashed during upload, as described at:
    https://support.google.com/google-ads/answer/7474263

    Args:
        s: The string to perform this operation on.

    Returns:
        A normalized (lowercase, removed whitespace) and SHA-256 hashed string.
    """
    return hashlib.sha256(s.strip().lower().encode()).hexdigest()
      

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/7474263.
def normalize_and_hash(str)
  # Remove leading and trailing whitespace and ensure all letters are lowercase
  # before hasing.
  Digest::SHA256.hexdigest(str.strip.downcase)
end

# Returns the result of normalizing and hashing an email address. For this use
# case, Google Ads requires removal of any '.' characters preceding 'gmail.com'
# or 'googlemail.com'.
def normalize_and_hash_email(email)
  email_parts = email.downcase.split("@")
  # Removes any '.' characters from the portion of the email address before the
  # domain if the domain is gmail.com or googlemail.com.
  if email_parts.last =~ /^(gmail|googlemail)\.com\s*/
    email_parts[0] = email_parts[0].gsub('.', '')
  end
  normalize_and_hash(email_parts.join('@'))
end
      

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

拡張コンバージョンをアップロードする

次のスニペットは、必要に応じて正規化とハッシュ化が適用されたメールアドレスと電話番号の識別子を含むコンバージョン アップロードを作成する方法を示しています。gclidorder_id が利用可能な場合は、コンバージョンに含めることをおすすめします。

ClickConversion にユーザー ID を追加する

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@example.com")
        // Phone number to be converted to E.164 format, with a leading '+' as required.
        .put("phone", "+1 800 5550102")
        // This example lets you put conversion details as arguments, but in reality you might
        // store this data alongside other user data, so we include it in this sample user
        // record.
        .put("conversionActionId", Long.toString(conversionActionId))
        .put("conversionDateTime", conversionDateTime)
        .put("conversionValue", Double.toString(conversionValue))
        .put("currencyCode", "USD");

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

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

// Creates a SHA256 message digest for hashing user identifiers in a privacy-safe way, as
// described at https://support.google.com/google-ads/answer/9888656.
MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256");

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

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

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

// Adds the user identifiers to the conversion.
clickConversionBuilder.addAllUserIdentifiers(userIdentifiers);
      

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
];

// 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 = {
    # Email address that includes a period (.) before the Gmail domain.
    "email": "alex.2@example.com",
    # Phone number to be converted to E.164 format, with a leading '+' as
    # required.
    "phone": "+1 800 5550102",
    # This example lets you input conversion details as arguments,
    # but in reality you might store this data alongside other user data,
    # so we include it in this sample user record.
    "order_id": order_id,
    "gclid": gclid,
    "conversion_action_id": conversion_action_id,
    "conversion_date_time": conversion_date_time,
    "conversion_value": conversion_value,
    "currency_code": "USD",
    "ad_user_data_consent": ad_user_data_consent,
}

# Constructs the click conversion.
click_conversion = client.get_type("ClickConversion")
# Creates a user identifier using the hashed email address, using the
# normalize and hash method specifically for email addresses.
email_identifier = client.get_type("UserIdentifier")
# Optional: Specifies the user identifier source.
email_identifier.user_identifier_source = (
    client.enums.UserIdentifierSourceEnum.FIRST_PARTY
)
# Uses the normalize and hash method specifically for email addresses.
email_identifier.hashed_phone_number = normalize_and_hash_email_address(
    raw_record["email"]
)
# Adds the user identifier to the conversion.
click_conversion.user_identifiers.append(email_identifier)

# Checks if the record has a phone number, and if so, adds a UserIdentifier
# for it.
if raw_record.get("phone") is not None:
    phone_identifier = client.get_type("UserIdentifier")
    phone_identifier.hashed_phone_number = normalize_and_hash(
        raw_record["phone"]
    )
    # Adds the phone identifier to the conversion adjustment.
    click_conversion.user_identifiers.append(phone_identifier)
      

Ruby

# Extract user email and phone from the raw data, normalize and hash it,
# then wrap it in UserIdentifier objects. Create a separate UserIdentifier
# object for each. The data in this example is hardcoded, but in your
# application you might read the raw data from an input file.

# IMPORTANT: Since the identifier attribute of UserIdentifier
# (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier)
# is a oneof
# (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must
# set only ONE of hashed_email, hashed_phone_number, mobile_id,
# third_party_user_id, or address_info. Setting more than one of these
# attributes on the same UserIdentifier will clear all the other members of
# the oneof. For example, the following code is INCORRECT and will result in
# a UserIdentifier with ONLY a hashed_phone_number:
#
# incorrectly_populated_user_identifier.hashed_email = "...""
# incorrectly_populated_user_identifier.hashed_phone_number = "...""

raw_record = {
  # Email address that includes a period (.) before the Gmail domain.
  "email" => "alex.2@example.com",
  # Phone number to be converted to E.164 format, with a leading '+' as
  # required.
  "phone" => "+1 800 5550102",
  # This example lets you input conversion details as arguments,
  # but in reality you might store this data alongside other user data,
  # so we include it in this sample user record.
  "order_id" => order_id,
  "gclid" => gclid,
  "conversion_action_id" => conversion_action_id,
  "conversion_date_time" => conversion_date_time,
  "conversion_value" => conversion_value,
  "currency_code" => "USD",
  "ad_user_data_consent" => ad_user_data_consent,
}

click_conversion = client.resource.click_conversion do |cc|
  cc.conversion_action = client.path.conversion_action(customer_id, conversion_action_id)
  cc.conversion_date_time = conversion_date_time
  cc.conversion_value = conversion_value.to_f
  cc.currency_code = 'USD'

  unless order_id.nil?
    cc.order_id = order_id
  end

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

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

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

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

Perl

# Create an empty click conversion.
my $click_conversion =
  Google::Ads::GoogleAds::V18::Services::ConversionUploadService::ClickConversion
  ->new({});

# Extract user email and phone from the raw data, normalize and hash it,
# then wrap it in UserIdentifier objects. Create a separate UserIdentifier
# object for each.
# The data in this example is hardcoded, but in your application
# you might read the raw data from an input file.
#
# IMPORTANT: Since the identifier attribute of UserIdentifier
# (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier)
# is a oneof
# (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must set
# only ONE of hashed_email, hashed_phone_number, mobile_id, third_party_user_id,
# or address-info. Setting more than one of these attributes on the same UserIdentifier
# will clear all the other members of the oneof. For example, the following code is
# INCORRECT and will result in a UserIdentifier with ONLY a hashed_phone_number:
#
# my $incorrect_user_identifier = Google::Ads::GoogleAds::V18::Common::UserIdentifier->new({
#   hashedEmail => '...',
#   hashedPhoneNumber => '...',
# });
my $raw_record = {
  # Email address that includes a period (.) before the Gmail domain.
  email => 'alex.2@example.com',
  # Phone number to be converted to E.164 format, with a leading '+' as
  # required.
  phone => '+1 800 5550102',
  # This example lets you input conversion details as arguments,
  # but in reality you might store this data alongside other user data,
  # so we include it in this sample user record.
  orderId            => $order_id,
  gclid              => $gclid,
  conversionActionId => $conversion_action_id,
  conversionDateTime => $conversion_date_time,
  conversionValue    => $conversion_value,
  currencyCode       => "USD",
  adUserDataConsent  => $ad_user_data_consent
};
my $user_identifiers = [];

# Create a user identifier using the hashed email address, using the normalize
# and hash method specifically for email addresses.
my $hashed_email = normalize_and_hash_email_address($raw_record->{email});
push(
  @$user_identifiers,
  Google::Ads::GoogleAds::V18::Common::UserIdentifier->new({
      hashedEmail => $hashed_email,
      # Optional: Specify the user identifier source.
      userIdentifierSource => FIRST_PARTY
    }));

# Create a user identifier using normalized and hashed phone info.
my $hashed_phone = normalize_and_hash($raw_record->{phone});
push(
  @$user_identifiers,
  Google::Ads::GoogleAds::V18::Common::UserIdentifier->new({
      hashedPhone => $hashed_phone,
      # Optional: Specify the user identifier source.
      userIdentifierSource => FIRST_PARTY
    }));

# Add the user identifiers to the conversion.
$click_conversion->{userIdentifiers} = $user_identifiers;
      

ClickConversion にコンバージョンの詳細を追加する

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

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

      

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

Python

# Add details of the conversion.
# Gets the conversion action resource name.
conversion_action_service = client.get_service("ConversionActionService")
click_conversion.conversion_action = (
    conversion_action_service.conversion_action_path(
        customer_id, raw_record["conversion_action_id"]
    )
)
click_conversion.conversion_date_time = raw_record["conversion_date_time"]
click_conversion.conversion_value = raw_record["conversion_value"]
click_conversion.currency_code = raw_record["currency_code"]

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

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

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

Ruby

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
      

Perl

# Add details of the conversion.
$click_conversion->{conversionAction} =
  Google::Ads::GoogleAds::V18::Utils::ResourceNames::conversion_action(
  $customer_id, $raw_record->{conversionActionId});
$click_conversion->{conversionDateTime} = $raw_record->{conversionDateTime};
$click_conversion->{conversionValue}    = $raw_record->{conversionValue};
$click_conversion->{currencyCode}       = $raw_record->{currencyCode};

# Set the order ID if provided.
if (defined $raw_record->{orderId}) {
  $click_conversion->{orderId} = $raw_record->{orderId};
}

# Set the Google click ID (gclid) if provided.
if (defined $raw_record->{gclid}) {
  $click_conversion->{gclid} = $raw_record->{gclid};
}

# Set the consent information, if provided.
if (defined $raw_record->{adUserDataConsent}) {
  $click_conversion->{consent} =
    Google::Ads::GoogleAds::V18::Common::Consent->new({
      adUserData => $raw_record->{adUserDataConsent}});
}
      

ClickConversion をアップロードする

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 = client.get_service("ConversionUploadService")
# Uploads the click conversion. Partial failure should always be set to
# True.
# NOTE: This request only uploads a single conversion, but if you have
# multiple conversions to upload, it's most efficient to upload them in a
# single request. See the following for per-request limits for reference:
# https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
response = conversion_upload_service.upload_click_conversions(
    customer_id=customer_id,
    conversions=[click_conversion],
    # Enables partial failure (must be true).
    partial_failure=True,
)
      

Ruby

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

アップロードを確認する

オフライン データの診断を使用して、最近アップロードした動画の全体的な状態を確認します。アップロードが成功したからといって、必ずしもアップロードが一致しているわけではありません。

キャンペーンのコンバージョン指標に関するレポートを作成する場合は、ユーザー インターフェース指標のマッピングを参照して、Google 広告の UI の指標と Google Ads API のレポート フィールドを関連付けることができます。conversion_action リソースをクエリして、特定のコンバージョン アクションの合計コンバージョン数と合計コンバージョン値を確認することもできます。

次のステップ

コンバージョンを調整する必要がある場合は、コンバージョンの調整のアップロードに関するガイドをご覧ください。

リードの拡張コンバージョンの統合に関するトラブルシューティングについては、トラブルシューティング ガイドをご覧ください。