Suivi avancé des conversions

L'API de conversion hors connexion CM360 permet d'améliorer les conversions basées sur les balises de site Web avec des identifiants utilisateur.

Suivi avancé des conversions

  • Acceptez les Conditions d'utilisation du suivi avancé des conversions pour votre configuration Floodlight dans CM360.
  • Instrumentez vos sites Web avec match ID.
  • Enregistrez les conversions Floodlight qui se produisent sur votre site Web. Veillez à enregistrer tous les éléments suivants, car il s'agit de champs obligatoires dans les appels d'API ultérieurs :
    • matchId
    • ordinal
    • timestampMicros
    • floodlightActivityId
    • floodlightConfigurationId
    • quantity
    • value
  • Une fois 90 minutes écoulées depuis que la balise en ligne a enregistré la conversion, appelez conversions.batchupdate pour améliorer ces conversions avec des identifiants utilisateur.
    • Les identifiants utilisateur doivent être mis en forme et hachés, puis ajoutés au champ userIdentifiers des objets de conversion.
    • La quantité et la valeur doivent être spécifiées. Vous pouvez éventuellement ajuster la quantité et la valeur de la conversion dans le même appel conversions.batchupdate ou fournir la quantité et la valeur d'origine.
    • Chaque lot d'insertions et de mises à jour peut contenir un mélange de réussites et d'échecs. En cas de délai de traitement des conversions plus long que d'habitude, les échecs NOT_FOUND doivent faire l'objet d'une nouvelle tentative pendant six heures maximum.
    • Les conversions doivent être améliorées avec des identifiants utilisateur dans les 24 heures suivant leur enregistrement par les balises en ligne.

Normalisation et hachage

Pour protéger la confidentialité, les adresses e-mail, les numéros de téléphone, les prénoms, les noms et les adresses postales doivent être hachés à l'aide de l'algorithme SHA-256 avant d'être importés. Afin de standardiser les résultats du hachage, avant de hacher l'une de ces valeurs, vous devez :

  • Supprimez les espaces blancs de début ou de fin.
  • convertir le texte en minuscules ;
  • Mettez en forme les numéros de téléphone conformément à la norme E164.
  • Supprimez tous les points (.) qui précèdent le nom de domaine des adresses e-mail gmail.com et 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

Ajouter des identifiants utilisateur aux conversions

Préparez d'abord l'objet Conversion pour l'importation ou la modification comme d'habitude, puis associez l'identifiant utilisateur comme suit :

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

Une réponse indiquant un succès devrait se présenter comme suit :

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

Erreurs fréquentes

Voici quelques-unes des erreurs que vous pouvez rencontrer lorsque vous améliorez une conversion avec des identifiants utilisateur :

Le champ hashed_X n'est pas un hachage SHA-256 valide
Tous les champs préfixés par "hashed" n'acceptent que les hachages SHA-256 encodés en hexadécimal.
La longueur du champ country_code n'est pas correcte
country_code doit comporter exactement deux lettres.
Les conditions d'utilisation du suivi avancé des conversions n'ont pas été signées pour la configuration Floodlight
Les conditions d'utilisation du suivi avancé des conversions n'ont pas été acceptées pour l'ID de configuration Floodlight de la demande.
Plus de cinq user_identifiers spécifiés
Une conversion ne peut comporter que cinq identifiants utilisateur au maximum.

Questions fréquentes

Pourquoi l'ID de correspondance est-il recommandé ?
Les modifications basées sur l'ID de clic excluent les conversions qui ne sont pas précédées d'un clic et limitent la valeur de l'intégration des conversions avancées.
Pourquoi enregistrer la quantité et la valeur ?
L'API CM360 Offline Conversions exige que la quantité et la valeur soient spécifiées.
Dois-je obtenir le code temporel exact enregistré par Google pour modifier une conversion en ligne basée sur une balise ?
Pour les modifications basées sur l'ID de match, l'API accepte désormais une modification tant que le code temporel fourni dans la requête se situe à moins d'une minute du code temporel enregistré par Google.
Pourquoi dois-je attendre 90 minutes après qu'une conversion a été enregistrée par une balise en ligne avant de l'améliorer ?
L'indexation de la conversion en ligne par l'API et sa disponibilité pour modification peuvent prendre jusqu'à 90 minutes.
À quoi dois-je faire attention dans la réponse de l'API ?
Même si l'API CM360 Conversion renvoie une réponse positive, il est possible que l'importation ou la mise à jour de certaines conversions individuelles aient échoué. Inspectez les champs ConversionStatus individuels pour détecter les échecs :
  • Les échecs NOT_FOUND peuvent et doivent être réessayés jusqu'à six heures, en cas de retard plus long que d'habitude dans le traitement des conversions. Consultez également les questions fréquentes pour savoir pourquoi les erreurs NOT_FOUND peuvent persister au-delà de six heures.
  • Nous vous recommandons de ne pas réessayer en cas d'erreurs INVALID_ARGUMENT et PERMISSION_DENIED.