향상된 전환

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

향상된 전환

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

정규화 및 해싱

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

  • 선행 또는 후행 공백을 삭제합니다.
  • 텍스트를 소문자로 변환합니다.
  • 전화번호는 E164 표준에 따른 형식으로 작성합니다.
  • 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 필드에서 오류를 검사합니다.
  • NOT_FOUND 실패는 전환 처리 지연이 평소보다 긴 경우 최대 6시간까지 재시도할 수 있으며 재시도해야 합니다. NOT_FOUND 오류가 6시간이 지나도 지속될 수 있는 이유에 관한 FAQ도 참고하세요.
  • INVALID_ARGUMENTPERMISSION_DENIED 오류는 다시 시도해서는 안 됩니다.