Conversioni avanzate

L'API CM360 Offline Conversion supporta il miglioramento delle conversioni basate sui tag del sito web con gli identificatori utente.

Conversione avanzata

  • Accetta i Termini di servizio delle conversioni avanzate per la configurazione Floodlight in CM360.
  • Inserisci l'ID corrispondenza sui tuoi siti web.
  • Registra le conversioni Floodlight che si verificano sul tuo sito web. Assicurati di registrare tutti i seguenti campi, in quanto sono obbligatori nelle chiamate API successive:
    • matchId
    • ordinal
    • timestampMicros
    • floodlightActivityId
    • floodlightConfigurationId
    • quantity
    • value
  • Dopo 90 minuti dall'acquisizione della conversione da parte del tag online, chiama conversions.batchupdate per migliorare queste conversioni con gli identificatori utente.
    • Gli identificatori utente devono essere formattati e sottoposti ad hashing e aggiunti a l campo userIdentifiers degli oggetti Conversion.
    • È necessario specificare la quantità e il valore. Facoltativamente, puoi modificare la quantità e il valore della conversione nella stessa chiamata conversions.batchupdate o fornire la quantità e il valore originali.
    • Ogni batch di inserimenti e aggiornamenti può contenere un mix di successi e errori. In caso di ritardo superiore al normale nell'elaborazione delle conversioni, è necessario riprovare a eseguire le richieste che hanno generato errori NOT_FOUND fino a 6 ore.
    • Le conversioni devono essere migliorate con gli identificatori utente entro 24 ore dall'acquisizione da parte dei tag online.

Normalizzazione e hashing

Per proteggere la privacy, gli indirizzi email, i numeri di telefono, i nomi, i cognomi e gli indirizzi devono essere sottoposti ad hashing utilizzando l'algoritmo SHA-256 prima di essere caricati. Per standardizzare i risultati dell'hash, prima di eseguire l'hashing di uno di questi valori devi:

  • Rimuovere gli spazi vuoti iniziali o finali.
  • Convertire il testo in minuscolo.
  • Formattare i numeri di telefono secondo lo standard E164. Inserire il segno più (+) e il codice paese. Ad esempio, il numero di telefono statunitense (800)555-0200 deve essere formattato e normalizzato in +18005550200.
  • Rimuovere tutti i punti (.) che precedono il nome di dominio negli indirizzi email gmail.com e 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

Aggiungere identificatori utente alle conversioni

Innanzitutto, prepara l'oggetto Conversion per il caricamento o la modifica come di consueto, poi allega l'identificatore utente nel seguente modo:

{
  "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 risposta corretta dovrebbe essere simile alla seguente:

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

Errori comuni

Ecco alcuni errori che potresti visualizzare quando migliori una conversione con gli identificatori utente:

Il campo hashed_X non è un hash SHA-256 valido
Tutti i campi con il prefisso hashed accettano solo hash SHA-256 codificati in esadecimale.
Il campo country_code ha una lunghezza errata
country_code deve essere composto esattamente da 2 lettere.
La configurazione Floodlight non ha firmato i Termini di servizio delle conversioni avanzate
I Termini di servizio delle conversioni avanzate non sono stati accettati per l'ID configurazione Floodlight della richiesta.
Sono stati specificati più di cinque user_identifiers
Una conversione può avere al massimo 5 identificatori utente.

Domande frequenti

Perché l'ID corrispondenza è consigliato?
Le modifiche basate sull'ID clic escludono le conversioni non precedute da un clic e limitano il valore dell'integrazione delle conversioni avanzate.
Perché è necessario registrare la quantità e il valore?
L'API CM360 Offline Conversion richiede la specifica della quantità e del valore.
Devo ottenere il timestamp esatto in microsecondi registrato da Google per modificare una conversione basata su tag online?
Per le modifiche basate sull'ID corrispondenza, l'API ora accetta una modifica a condizione che il timestamp fornito nella richiesta rientri in un intervallo di 1 minuto dal timestamp registrato da Google.
Perché devo attendere 90 minuti dopo che una conversione è stata acquisita da un tag online prima di migliorarla?
L'indicizzazione della conversione online da parte dell'API e la sua disponibilità per le modifiche possono richiedere fino a 90 minuti.
A cosa devo prestare attenzione nella risposta dell'API?
Anche quando l'API CM360 Conversion restituisce una risposta corretta, il caricamento o l'aggiornamento di alcune singole conversioni potrebbe non essere riuscito. Esamina i singoli campi ConversionStatus per verificare la presenza di errori:
  • In caso di ritardo superiore al normale nell'elaborazione delle conversioni, è possibile e consigliabile riprovare a eseguire le richieste che hanno generato errori NOT_FOUND fino a 6 ore. Consulta anche le Domande frequenti sul motivo per cui gli errori NOT_FOUND possono persistere oltre le 6 ore.
  • Non è necessario riprovare a eseguire le richieste che hanno generato errori INVALID_ARGUMENT e PERMISSION_DENIED.