Conversiones avanzadas

La API de conversiones sin conexión de CM360 admite la mejora de las conversiones basadas en etiquetas de sitios web con identificadores de usuario.

Conversión avanzada

  • Acepta las Condiciones del Servicio de las conversiones avanzadas para tu configuración de Floodlight en CM360.
  • Instrumenta tus sitios web con el ID de coincidencia.
  • Registrar las conversiones de Floodlight que se producen en tu sitio web Asegúrate de registrar todos los siguientes elementos, ya que son campos obligatorios en las llamadas a la API posteriores:
    • matchId
    • ordinal
    • timestampMicros
    • floodlightActivityId
    • floodlightConfigurationId
    • quantity
    • value
  • Después de que transcurran 90 minutos desde que la etiqueta en línea capturó la conversión, llama a conversions.batchupdate para mejorar estas conversiones con identificadores de usuario.
    • Los identificadores de usuario deben estar formateados y con codificación hash, y agregarse al campo userIdentifiers en los objetos Conversion.
    • Se deben especificar la cantidad y el valor. De manera opcional, puedes ajustar la cantidad y el valor de la conversión en la misma llamada a conversions.batchupdate o proporcionar la cantidad y el valor originales.
    • Cada lote de inserciones y actualizaciones puede contener una combinación de éxitos y errores. Los errores de NOT_FOUND se deben reintentar en caso de que haya un retraso mayor de lo habitual en el procesamiento de conversiones, hasta por 6 horas.
    • Las conversiones deben mejorarse con identificadores de usuario en un plazo de 24 horas después de que las etiquetas en línea las registren.

Normalización y generación de hash

Para ayudar a proteger la privacidad, las direcciones de correo electrónico, los números de teléfono, los nombres, los apellidos y las direcciones deben codificarse con hash utilizando el algoritmo SHA-256 antes de subirse. Para estandarizar los resultados del hash, debes hacer lo siguiente antes de generar un hash para uno de estos valores:

  • Quita los espacios en blanco iniciales o finales.
  • Convierte el texto a minúsculas.
  • Escribe los números de teléfono con el formato estándar E164.
  • Quita todos los puntos (.) que anteceden al nombre de dominio en las direcciones de correo electrónico gmail.com y 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()

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

Agrega identificadores de usuarios a las conversiones

Primero, prepara el objeto Conversion para subirlo o editarlo como de costumbre y, luego, adjunta el identificador del usuario de la siguiente manera:

{
  "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"
      }
    }
  ]
}

Una respuesta correcta debería verse de la siguiente manera:

{
  "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"
    }
  ]
}

Errores comunes

A continuación, se muestran algunos errores que pueden aparecer cuando se mejora una conversión con identificadores de usuario:

El campo hashed_X no es un hash SHA-256 válido
Todos los campos con el prefijo hashed solo aceptan hashes SHA-256 codificados en hexadecimales.
El campo country_code tiene la longitud incorrecta
country_code debe tener exactamente 2 letras.
La configuración de Floodlight no firmó las Condiciones del Servicio de las conversiones avanzadas
No se aceptaron las Condiciones del Servicio de las Conversiones Mejoradas para el ID de configuración de Floodlight de la solicitud.
Se especificaron más de cinco user_identifiers
Una conversión solo puede tener hasta 5 identificadores de usuario.

Preguntas frecuentes

¿Por qué se recomienda el ID de coincidencia?
Las ediciones basadas en el ID de clic excluyen las conversiones que no se precedieron de un clic y limitan el valor de la integración de las conversiones avanzadas.
¿Por qué se deben registrar la cantidad y el valor?
La API de conversiones sin conexión de CM360 requiere que se especifiquen la cantidad y el valor.
¿Necesito obtener la marca de tiempo exacta en microsegundos que registró Google para editar una conversión en línea basada en etiquetas?
En el caso de las ediciones basadas en el ID de coincidencia, la API ahora acepta una edición siempre que la marca de tiempo proporcionada en la solicitud se encuentre dentro de 1 minuto de la marca de tiempo registrada por Google.
¿Por qué debo esperar 90 minutos después de que una etiqueta en línea registra una conversión antes de mejorarla?
La API puede tardar hasta 90 minutos en indexar la conversión en línea y que esté disponible para editarla.
¿A qué debo prestar atención en la respuesta de la API?
Incluso cuando la API de conversiones de CM360 devuelve una respuesta correcta, es posible que no se hayan podido subir o actualizar algunas conversiones individuales. Inspecciona los campos ConversionStatus individuales para detectar errores:
  • Las fallas de NOT_FOUND se pueden y se deben reintentar hasta por 6 horas en caso de que haya una demora más larga de lo habitual en el procesamiento de la conversión. Consulta también las preguntas frecuentes sobre por qué los errores de NOT_FOUND pueden persistir durante más de 6 horas.
  • No se deben reintentar los errores de INVALID_ARGUMENT y PERMISSION_DENIED.