향상된 전환

CM360 오프라인 전환 API는 사용자 식별자를 사용하여 웹사이트 태그 기반 전환을 향상하는 기능을 지원합니다.

향상된 전환

  • CM360에서 플러드라이트 구성에 대한 향상된 전환 서비스 약관에 동의합니다.
  • 일치 ID로 웹사이트를 계측합니다.
  • 웹사이트에서 발생하는 플러드라이트 전환을 기록합니다. 후속 API 호출에서 필수 필드이므로 다음을 모두 기록해야 합니다.
    • matchId
    • ordinal
    • timestampMicros
    • floodlightActivityId
    • floodlightConfigurationId
    • quantity
    • value
  • 온라인 태그가 전환을 캡처한 후 90분이 지나면 conversions.batchupdate를 호출하여 사용자 식별자로 이러한 전환을 향상합니다.
    • 사용자 식별자는 형식이 지정되고 해싱되어야 하며 전환 객체의 userIdentifiers 필드에 추가되어야 합니다.
    • 수량과 값을 지정해야 합니다. 선택적으로 동일한 conversions.batchupdate 호출에서 전환의 수량과 값을 조정하거나 원래 수량과 값을 제공할 수 있습니다.
    • 삽입 및 업데이트의 각 일괄 처리에는 성공과 실패가 혼합되어 있을 수 있습니다. 전환 처리가 평소보다 오래 지연되는 경우 최대 6시간 동안 NOT_FOUND 실패를 재시도해야 합니다.
    • 전환은 온라인 태그에 의해 캡처된 후 24시간 이내에 사용자 식별자로 향상되어야 합니다.

정규화 및 해싱

개인 정보 보호를 위해 이메일 주소, 전화번호, 이름, 성, 상세 주소는 업로드하기 전에 SHA-256 알고리즘을 사용하여 해싱해야 합니다. 해싱 결과를 표준화하려면 해당 값을 해싱하기 전에 다음을 따릅니다.

  • 선행 또는 후행 공백을 삭제합니다.
  • 텍스트를 소문자로 변환합니다.
  • 전화번호는 E164 표준에 따른 형식으로 작성합니다. 더하기 기호 (+)와 국가 코드를 포함합니다. 예를 들어 미국 전화번호 (800)555-0200+18005550200으로 형식이 지정되고 정규화되어야 합니다.
  • gmail.comgooglemail.com 이메일 주소의 도메인 이름 앞에 있는 모든 마침표 (.)를 삭제합니다.

C#

/// <summary>
/// Normalizes the email address and hashes it. For this use case, Campaign Manager 360
/// requires removal of any '.' characters preceding <code>gmail.com</code> or
/// <code>googlemail.com</code>.
/// </summary>
/// <param name="emailAddress">The email address.</param>
/// <returns>The hash code.</returns>
private string NormalizeAndHashEmailAddress(string emailAddress)
{
    string normalizedEmail = emailAddress.ToLower();
    string[] emailParts = normalizedEmail.Split('@');
    if (emailParts.Length > 1 && (emailParts[1] == "gmail.com" ||
        emailParts[1] == "googlemail.com"))
    {
        // Removes any '.' characters from the portion of the email address before
        // the domain if the domain is gmail.com or googlemail.com.
        emailParts[0] = emailParts[0].Replace(".", "");
        normalizedEmail = $"{emailParts[0]}@{emailParts[1]}";
    }
    return NormalizeAndHash(normalizedEmail);
}

/// <summary>
/// Normalizes and hashes a string value.
/// </summary>
/// <param name="value">The value to normalize and hash.</param>
/// <returns>The normalized and hashed value.</returns>
private static string NormalizeAndHash(string value)
{
    return ToSha256String(digest, ToNormalizedValue(value));
}

/// <summary>
/// Hash a string value using SHA-256 hashing algorithm.
/// </summary>
/// <param name="digest">Provides the algorithm for SHA-256.</param>
/// <param name="value">The string value (e.g. an email address) to hash.</param>
/// <returns>The hashed value.</returns>
private static string ToSha256String(SHA256 digest, string value)
{
    byte[] digestBytes = digest.ComputeHash(Encoding.UTF8.GetBytes(value));
    // Convert the byte array into an unhyphenated hexadecimal string.
    return BitConverter.ToString(digestBytes).Replace("-", string.Empty);
}

/// <summary>
/// Removes leading and trailing whitespace and converts all characters to
/// lower case.
/// </summary>
/// <param name="value">The value to normalize.</param>
/// <returns>The normalized value.</returns>
private static string ToNormalizedValue(string value)
{
    return value.Trim().ToLower();
}

자바

private String normalizeAndHash(MessageDigest digest, String s)
    throws UnsupportedEncodingException {
  // Normalizes by removing leading and trailing whitespace and converting all characters to
  // lower case.
  String normalized = s.trim().toLowerCase();
  // Hashes the normalized string using the hashing algorithm.
  byte[] hash = digest.digest(normalized.getBytes("UTF-8"));
  StringBuilder result = new StringBuilder();
  for (byte b : hash) {
    result.append(String.format("%02x", b));
  }

  return result.toString();
}

/**
 * Returns the result of normalizing and hashing an email address. For this use case, Campaign Manager 360
 * 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);
}

PHP

private static function normalizeAndHash(string $hashAlgorithm, string $value): string
{
    return hash($hashAlgorithm, strtolower(trim($value)));
}

/**
  * Returns the result of normalizing and hashing an email address. For this use case, Campaign
  * Manager 360 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, Campaign Manager 360 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, Campaign Manager 360 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

전환에 사용자 식별자 추가

먼저 Conversion 객체를 업로드 또는 수정을 위해 평소와 같이 준비한 다음 다음과 같이 사용자 식별자를 연결합니다.

{
  "matchId": "my-match-id-846513278",
  "ordinal": "my-ordinal-12345678512",
  "quantity": 1,
  "value": 104.23,
  "timestampMicros": 1656950400000000,
  "floodlightConfigurationId": 99999,
  "floodlightActivityId": 8888,
  "userIdentifiers": [
    { "hashedEmail": "0c7e6a405862e402eb76a70f8a26fc732d07c32931e9fae9ab1582911d2e8a3b" },
    { "hashedPhoneNumber": "1fb1f420856780a29719b994c8764b81770d79f97e2e1861ba938a7a5a15dfb9" },
    {
      "addressInfo": {
        "hashedFirstName": "81f8f6dde88365f3928796ec7aa53f72820b06db8664f5fe76a7eb13e24546a2",
        "hashedLastName": "799ef92a11af918e3fb741df42934f3b568ed2d93ac1df74f1b8d41a27932a6f",
        "hashedStreetAddress": "22b7e2d69b91e0ef4a88e81a73d897b92fd9c93ccfbe0a860f77db16c26f662e",
        "city": "seattle",
        "state": "washington",
        "countryCode": "US",
        "postalCode": "98101"
      }
    }
  ]
}

성공적인 응답은 다음과 같습니다.

{
  "hasFailures": false,
  "status": [
    {
      "conversion": {
        "floodlightConfigurationId": 99999,
        "floodlightActivityId": 8888,
        "timestampMicros": 1656950400000000,
        "value": 104.23,
        "quantity": 1,
        "ordinal": "my-ordinal-12345678512",
        "matchId": "my-match-id-846513278",
        "userIdentifiers": [
          { "hashedEmail": "0c7e6a405862e402eb76a70f8a26fc732d07c32931e9fae9ab1582911d2e8a3b" },
          { "hashedPhoneNumber": "1fb1f420856780a29719b994c8764b81770d79f97e2e1861ba938a7a5a15dfb9" },
          {
            "addressInfo": {
              "hashedFirstName": "81f8f6dde88365f3928796ec7aa53f72820b06db8664f5fe76a7eb13e24546a2",
              "hashedLastName": "799ef92a11af918e3fb741df42934f3b568ed2d93ac1df74f1b8d41a27932a6f",
              "hashedStreetAddress": "22b7e2d69b91e0ef4a88e81a73d897b92fd9c93ccfbe0a860f77db16c26f662e",
              "city": "seattle",
              "state": "washington",
              "countryCode": "US",
              "postalCode": "98101"
            }
          }
        ],
        "kind": "dfareporting#conversion"
      },
      "kind": "dfareporting#conversionStatus"
    }
  ]
}

일반적인 오류

사용자 식별자로 전환을 향상할 때 발생할 수 있는 오류는 다음과 같습니다.

필드 hashed_X는 유효한 SHA-256 해시가 아닙니다.
접두사로 해시가 붙은 모든 필드는 16진수로 인코딩된 SHA-256 해시만 허용합니다.
country_code 필드의 길이가 잘못되었습니다.
country_code 는 정확히 2글자여야 합니다.
플러드라이트 구성에서 향상된 전환 서비스 약관에 서명하지 않았습니다.
요청의 플러드라이트 구성 ID에 대해 향상된 전환 서비스 약관이 수락되지 않았습니다.
user_identifier가 6개 이상 지정되었습니다.
전환에는 사용자 식별자를 최대 5개까지만 사용할 수 있습니다.

자주 묻는 질문(FAQ)

일치 ID가 권장되는 이유는 무엇인가요?
클릭 ID 기반 수정은 클릭이 선행되지 않은 전환을 제외하고 향상된 전환 통합의 가치를 제한합니다.
수량과 값을 기록해야 하는 이유는 무엇인가요?
CM360 오프라인 전환 API에서는 수량과 값을 지정해야 합니다.
온라인 태그 기반 전환을 수정하려면 Google에서 기록한 정확한 마이크로초 타임스탬프를 가져와야 하나요?
일치 ID 기반 수정의 경우 요청에 제공된 타임스탬프가 Google에서 기록한 타임스탬프에서 1분 이내인 경우 API에서 수정을 허용합니다.
온라인 태그가 전환을 캡처한 후 90분을 기다린 후에 전환을 향상해야 하는 이유는 무엇인가요?
온라인 전환이 API에 의해 색인이 생성되고 수정에 사용할 수 있게 되려면 최대 90분이 걸릴 수 있습니다.
API 응답에서 주의해야 할 사항은 무엇인가요?
CM360 전환 API가 성공적인 응답을 반환하더라도 일부 개별 전환이 업로드 또는 업데이트되지 않았을 수 있습니다. 실패한 개별 ConversionStatus 필드를 검사합니다.
  • 전환 처리가 평소보다 오래 지연되는 경우 최대 6시간 동안 NOT_FOUND 실패를 재시도할 수 있으며 재시도해야 합니다. NOT_FOUND 오류가 6 시간 이상 지속될 수 있는 이유에 관한 FAQ도 참고하세요.
  • INVALID_ARGUMENTPERMISSION_DENIED 오류는 재시도해서는 안 됩니다.