Расширенное отслеживание конверсий

API CM360 для офлайн-конверсий поддерживает повышение эффективности конверсий на основе тегов веб-сайта за счет использования идентификаторов пользователей.

Улучшенная конверсия

  • Примите условия предоставления услуг по расширенному преобразованию данных для вашей конфигурации прожектора в CM360.
  • Настройте свои веб-сайты с помощью идентификатора соответствия (match ID ).
  • Записывайте конверсии, происходящие на вашем веб-сайте при использовании Floodlight. Обязательно записывайте все следующие поля, поскольку они являются обязательными для последующих вызовов API:
    • matchId
    • ordinal
    • timestampMicros
    • floodlightActivityId
    • floodlightConfigurationId
    • quantity
    • value
  • Через 90 минут после того, как онлайн-тег зафиксировал конверсию, вызовите функцию conversions.batchupdate , чтобы добавить в эти данные идентификаторы пользователей.
    • Идентификаторы пользователей следует отформатировать и хешировать , а затем добавить в поле userIdentifiers в объектах Conversion.
    • Необходимо указать количество и стоимость. При желании вы можете скорректировать количество и стоимость преобразования в том же вызове conversions.batchupdate или указать исходные количество и стоимость.
    • Каждая партия вставок и обновлений может содержать как успешные, так и неудачные попытки. В случае ошибок с NOT_FOUND следует повторить попытку, если задержка в процессе преобразования превышает обычно и составляет до 6 часов.
    • Для повышения конверсии необходимо использовать идентификаторы пользователей в течение 24 часов после их получения с помощью онлайн-тегов.

Нормализация и хеширование

Для защиты конфиденциальности адреса электронной почты, номера телефонов, имена, фамилии и почтовые адреса должны быть хешированы с использованием алгоритма SHA-256 перед загрузкой. Для стандартизации результатов хеширования перед хешированием одного из этих значений необходимо:

  • Удалите пробелы в начале или конце текста.
  • Преобразовать текст в нижний регистр.
  • Форматируйте телефонные номера в соответствии со стандартом E164 .
  • Удалите все точки (.) перед доменным именем в адресах электронной почты gmail.com и googlemail.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();
}

Java

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

Руби

# 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.
Все поля, помеченные префиксом hashed, принимают только хеши SHA-256, закодированные в шестнадцатеричном формате.
Поле country_code имеет неправильную длину.
country_code должен состоять ровно из 2 букв.
Конфигурация прожекторов не предусматривает подписания расширенных условий обслуживания.
Условия предоставления услуг по расширенным преобразованиям не были приняты для идентификатора конфигурации Floodlight в запросе.
Указано более пяти идентификаторов пользователей.
В одной операции преобразования может быть не более 5 идентификаторов пользователей.

Часто задаваемые вопросы

Почему рекомендуется использовать идентификатор матча?
Редактирование на основе идентификаторов кликов исключает конверсии, которым не предшествовал клик, и ограничивает ценность расширенной интеграции конверсий.
Почему необходимо фиксировать количество и стоимость?
Для использования API CM360 Offline Conversions необходимо указать количество и стоимость.
Нужно ли мне получать точную микросекундную метку времени, записанную Google, чтобы редактировать онлайн-конверсию, основанную на тегах?
Для правок, основанных на идентификаторе совпадения, API теперь принимает редактирование, если указанная в запросе метка времени отличается от метки времени, зарегистрированной Google, не более чем на 1 минуту.
Почему необходимо ждать 90 минут после того, как онлайн-тег зафиксировал конверсию, прежде чем улучшать её?
Для индексации онлайн-конверсии API и обеспечения возможности редактирования может потребоваться до 90 минут.
На что следует обратить внимание в ответе API?
Даже если API преобразования CM360 возвращает успешный ответ, некоторые отдельные преобразования могли не загрузиться или не обновиться. Проверьте отдельные поля ConversionStatus на наличие ошибок:
  • При возникновении ошибок NOT_FOUND повторную попытку можно и нужно повторять в течение 6 часов, если задержка в процессе преобразования превышает обычное время. Также см. раздел часто задаваемых вопросов (FAQ) о причинах сохранения ошибок NOT_FOUND более 6 часов.
  • При возникновении ошибок INVALID_ARGUMENT и PERMISSION_DENIED повторная попытка не требуется.