CM360 offline conversion API תומך בהעשרת המרות מבוססות תגים באתרים במזהי משתמשים.

ההגדרה המומלצת
- מאשרים את התנאים וההגבלות של ההמרות המשופרות בהגדרות Floodlight ב-CM360.
- מטמיעים באתרים את מזהה ההתאמה.
- תיעוד של המרות מ-Floodlight שמתרחשות באתר. חשוב לתעד את כל הפרטים הבאים, כי הם שדות חובה בקריאות הבאות ל-API:
matchIdordinaltimestampMicrosfloodlightActivityIdfloodlightConfigurationIdquantityvalue
- אחרי 90 דקות מאז שהתג באינטרנט תיעד את ההמרה, צריך להתקשר אל
conversions.batchupdateכדי לשפר את ההמרות האלה באמצעות מזהי משתמשים.- צריך לעצב ולגבב את מזהי המשתמשים ולהוסיף אותם לשדה
userIdentifiersבאובייקטים של המרות. - חובה לציין כמות וערך.
אפשר גם לשנות את הכמות והערך של ההמרה באותה קריאה
conversions.batchupdateאו לספק את הכמות והערך המקוריים. - כל אצווה של הוספות ועדכונים יכולה לכלול שילוב של הצלחות וכישלונות. אם יש כשלים בהעלאה
NOT_FOUND, צריך לנסות שוב אם יש עיכוב ארוך מהרגיל בעיבוד ההמרות, עד 6 שעות. - צריך להוסיף מזהי משתמשים להמרות תוך 24 שעות אחרי שהתגים באינטרנט מתעדים אותן.
- צריך לעצב ולגבב את מזהי המשתמשים ולהוסיף אותם לשדה
נירמול וגיבוב (hashing)
כדי להגן על הפרטיות, צריך לבצע גיבוב של כתובות אימייל, מספרי טלפון, שמות פרטיים, שמות משפחה וכתובות רחוב באמצעות האלגוריתם 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()
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 לא עבר גיבוב (hash) תקין באלגוריתם SHA-256
- כל השדות שמופיע לפניהם הגיבוב מקבלים רק גיבובים מסוג SHA-256 שמקודדים בשיטה הקסדצימלית.
- האורך של השדה country_code שגוי
country_codeחייב להיות בן 2 אותיות בדיוק.- לא נחתמו התנאים וההגבלות של ההמרות המשופרות בהגדרת Floodlight
- התנאים וההגבלות של ההמרות המשופרות לא אושרו עבור מזהה ההגדרה ב-Floodlight של הבקשה.
- יותר מחמישה מזהי משתמשים צוינו
- להמרה יכולים להיות עד 5 מזהי משתמשים.
שאלות נפוצות
- למה מומלץ להשתמש במזהה התאמה?
- עריכות שמבוססות על מזהה קליק לא כוללות המרות שלא קדמו להן קליקים, ומגבילות את הערך של שילוב המרות משופרות.
- למה חשוב לתעד את הכמות והערך?
- ב-CM360 Offline Conversions API צריך לציין כמות וערך.
- האם צריך לקבל את חותמת הזמן המדויקת במיקרו-שנייה שמתועדת על ידי Google כדי לערוך המרה אונליין שמבוססת על תג?
- במקרה של עריכות שמבוססות על מזהה התאמה, ה-API מקבל עריכה כל עוד חותמת הזמן שצוינה בבקשה היא בטווח של דקה אחת מחותמת הזמן שנרשמה ב-Google.
- למה צריך לחכות 90 דקות אחרי שתג אונליין מתעד המרה לפני שמשפרים אותה?
- יכול להיות שיעברו עד 90 דקות עד שה-API יבצע אינדוקס של ההמרה אונליין והיא תהיה זמינה לעריכה.
- מה חשוב לשים לב בתגובת ה-API?
- גם אם CM360 Conversion API מחזיר תגובה של הצלחה, יכול להיות שחלק מההמרות הספציפיות לא הועלו או לא עודכנו. בודקים את השדות
ConversionStatusבנפרד כדי לראות אם יש כשלים:- אפשר ומומלץ לנסות שוב לבצע פעולות שנכשלו מסוג
NOT_FOUND, עד 6 שעות, במקרה של עיכוב ארוך מהרגיל בעיבוד ההמרה. אפשר גם לעיין בשאלות הנפוצות כדי להבין למה שגיאותNOT_FOUNDעשויות להימשך יותר מ-6 שעות. - אין לנסות שוב שגיאות
INVALID_ARGUMENTו-PERMISSION_DENIED.
- אפשר ומומלץ לנסות שוב לבצע פעולות שנכשלו מסוג