إدارة الإحالات الناجحة الناتجة عن النقرات على الإنترنت

يمكنك استخدام Google Ads API لإدارة الإحالات الناجحة الناتجة عن النقرات على الإنترنت في "إعلانات Google". تساعدك الإحالات الناجحة الناتجة عن النقرات على الإنترنت في تتبُّع الإعلانات التي أدّت إلى تحقيق مبيعات على الإنترنت، مثل المبيعات التي تتم من خلال موقع إلكتروني.

يتم تتبُّع الإحالات الناجحة على الإنترنت باستخدام علامة تتبُّع من Google، ولكن يمكنك تعديلها أو تحسينها باستخدام Google Ads API.

إذا سبق لك إعداد علامة التتبُّع من Google وأردت تعديل إحالاتك الناجحة على الإنترنت، اطّلِع على صفحة تعديلات الإحالات الناجحة. إذا كنت قد أعددت علامة التتبُّع من Google وأردت تحسين إحالاتك الناجحة على الإنترنت باستخدام البيانات المقدَّمة من المستخدم، والمعروفة أيضًا باسم الإحالات الناجحة المحسّنة للويب، يُرجى مواصلة القراءة.

الإحالات الناجحة المحسّنة للويب

يشرح القسم التالي كيفية تحسين الإحالات الناجحة الناتجة عن النقرات على الإنترنت، والتي تُعرف أيضًا باسم الإحالات الناجحة المحسّنة للويب.

تتطلّب ميزة "الإحالات الناجحة المحسّنة للويب" إعداد علامة ترسل تلقائيًا معرّف نقرة، مثل GCLID، ومعرّف طلب إلى "إعلانات Google" عندما يُجري المستخدم إحالة ناجحة. يمكنك إعداد ميزة "الإحالات الناجحة المحسّنة" من خلال Google Tag Manager أو علامة التتبُّع من Google أو Google Ads API. يمنحك استخدام Google Ads API ميزة إرسال بيانات الإحالات الناجحة للطرف الأول في غضون 24 ساعة من حدث الإحالة الناجحة، بدلاً من إرسالها في الوقت نفسه. ويتيح ذلك تحديد موقع بيانات الطرف الأول من مجموعة متنوعة من المصادر، مثل قاعدة بيانات العملاء أو نظام إدارة علاقات العملاء.

طريقة عمل ميزة "الإحالات الناجحة المحسّنة للويب"

تُكمّل ميزة "الإحالات الناجحة المحسّنة للويب" في Google Ads API الخطوة 3 في المخطّط البياني التالي. بدلاً من إرسال معلومات المستخدم المجزّأة عندما يُجري المستخدم إحالة ناجحة، ترسل العلامة معرّف النقرة من Google ومعرّف الطلب فقط، وترسل أنت معلومات المستخدم المجزّأة لاحقًا عن طريق استيراد معرّف الطلب مع البيانات المجزّأة. لمزيد من المعلومات عن ميزة "الإحالات الناجحة المحسّنة للويب"، يُرجى الاطّلاع على مقالة لمحة عن "الإحالات الناجحة المحسّنة".

الإحالات الناجحة المحسّنة للويب

المتطلبات الأساسية

يجب قبول أحكام بيانات العملاء قبل أن تتمكّن من استخدام ميزة "الإحالات الناجحة المحسّنة للويب". يمكنك التحقّق مما إذا تم قبول أحكام بيانات العملاء من خلال إرسال طلب البحث التالي إلى عميل الإحالة الناجحة في "إعلانات Google":

SELECT
  customer.id,
  customer.conversion_tracking_setting.accepted_customer_data_terms
FROM customer

إذا كانت قيمة accepted_customer_data_terms هي false، اتّبِع التعليمات الواردة في مقالة إعداد ميزة "الإحالات الناجحة المحسّنة للويب" لإكمال هذا الشرط الأساسي.

ضبط الإشارات

اضبط وضع العلامات لموقعك الإلكتروني باتّباع التعليمات الواردة في المقالة إعداد ميزة "الإحالات الناجحة المحسّنة للويب" باستخدام Google Ads API. عند استخدام Google Ads API لميزة "الإحالات الناجحة المحسّنة للويب"، عليك أيضًا إضافة معرّفات المعاملات (معرّفات الطلبات) إلى علامة تتبُّع الإحالات الناجحة على الموقع الإلكتروني. تستخدم "إعلانات Google" معرّف المعاملة لمطابقة حقل order_id لكل تحسين في واجهة برمجة التطبيقات مع حدث الإحالة الناجحة المقابل.

تنفيذ واجهة برمجة التطبيقات

في ما يلي العملية الإجمالية لاستيراد الإحالات الناجحة المحسّنة للويب في Google Ads API.

  1. تسوية البيانات المقدَّمة من المستخدم وتجزئتها، مثل عنوان البريد الإلكتروني ورقم الهاتف والعنوان البريدي

  2. املأ عناصر ConversionAdjustment ببيانات مقدَّمة من المستخدم بعد تسويتها وتجزئتها.

  3. استورِد عناصر ConversionAdjustment إلى ConversionAdjustmentUploadService.

  4. راجِع عمليات الاستيراد.

تسوية البيانات المقدَّمة من المستخدم وتجزئتها

لمراعاة اعتبارات الخصوصية، يجب تجزئة البيانات التالية باستخدام SHA-256 قبل استيرادها:

  • عنوان البريد الإلكتروني
  • رقم الهاتف
  • الاسم الأول
  • اسم العائلة
  • عنوان الشارع

يجب عدم تجزئة البيانات التالية:

  • البلد (country_code، بتنسيق رمز ISO 3166-1 alpha-2 المكوّن من حرفَين)
  • الولاية (state)
  • المدينة (city)
  • الرمز البريدي (postal_code)

لتوحيد نتائج التجزئة، عليك إجراء ما يلي قبل تجزئة إحدى هذه القيم:

  • إزالة المسافات البيضاء البادئة واللاحقة
  • تحويل النص إلى أحرف لاتينية صغيرة
  • تنسيق أرقام الهواتف وفقًا لمعيار E.164

تنسيق عنوان البريد الإلكتروني لميزة "الإحالات الناجحة المحسّنة"

لضمان أعلى نسب مطابقة للإحالات الناجحة المحسّنة، عليك تنسيق عناوين البريد الإلكتروني وتجزئتها بشكل صحيح باتّباع الخطوات التالية:

  1. تطبيق التسوية العادية (جميع عناوين البريد الإلكتروني):

    • أزِل أي مسافة بيضاء بادئة ولاحقة في ترميز ASCII.
    • حوِّل جميع الأحرف في عنوان البريد الإلكتروني إلى أحرف صغيرة.
  2. تطبيق التسوية الخاصة بالنطاق (gmail.com وgooglemail.com فقط):

    • بعد تحويل عنوان البريد الإلكتروني إلى أحرف صغيرة، تحقَّق مما إذا كان النطاق (بعد الرمز @) هو gmail.com أو googlemail.com.
    • إزالة النقاط (.): من جزء اسم المستخدم (قبل الرمز @)، أزِل جميع أحرف النقاط.
    • إزالة اللاحقات التي تبدأ بعلامة الجمع (+): من جزء اسم المستخدم، تتم إزالة علامة الجمع الأولى (+) وجميع الأحرف اللاحقة حتى الرمز @.
      • مثال: يصبح Jane.Doe+Shopping@googlemail.com أولاً jane.doe+shopping@googlemail.com (أحرف صغيرة)، ثم janedoe@googlemail.com (قواعد Gmail وGooglemail).
    • النطاقات الأخرى: بالنسبة إلى أي نطاق غير gmail.com أو googlemail.com، لا تُزِل النقاط أو اللاحقات التي تتضمّن علامة الجمع من اسم المستخدم. لا تطبِّق سوى التسوية العادية (اقتطاع المسافات البيضاء والتحويل إلى أحرف صغيرة).
      • مثال: تتم تسوية user.name+NYC@Example.com إلى user.name+nyc@example.com.
  3. تجزئة عنوان البريد الإلكتروني الذي تمّت تسويته:

    • ترميز سلسلة عنوان البريد الإلكتروني الذي تمّت تسويته على أنّه وحدات بايت UTF-8
    • جزِّئ وحدات البايت بترميز UTF-8 باستخدام خوارزمية SHA-256.
    • يجب تنسيق الملخّص الناتج على شكل سلسلة سداسية عشرية بأحرف صغيرة (64 حرفًا).
import hashlib
import re


def normalize_and_hash_email(email: str) -> str:
    """Normalizes and SHA-256 hashes an email address for enhanced conversions."""
    normalized = email.strip().lower()
    parts = normalized.split("@")
    if len(parts) != 2:
        raise ValueError("Invalid email address format.")
    username, domain = parts
    if domain in ("gmail.com", "googlemail.com"):
        username = username.replace(".", "")
        username = re.sub(r"\+.*$", "", username)
    normalized = f"{username}@{domain}"
    return hashlib.sha256(normalized.encode("utf-8")).hexdigest()

مثال على الرمز

يوضّح هذا المثال كيفية تسوية البيانات المقدَّمة من المستخدم وتجزئتها.

جافا

private String normalizeAndHash(MessageDigest digest, String s, boolean trimIntermediateSpaces)
    throws UnsupportedEncodingException {
  // Normalizes by first converting all characters to lowercase, then trimming spaces.
  String normalized = s.toLowerCase();
  if (trimIntermediateSpaces) {
    // Removes leading, trailing, and intermediate spaces.
    normalized = normalized.replaceAll("\\s+", "");
  } else {
    // Removes only leading and trailing spaces.
    normalized = normalized.trim();
  }
  // 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, Google Ads
 * requires removal of any '.' characters or trailing '+' and characters that follow it from the
 * username portion of the email address if the domain is {@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 {
  // Removes all whitespace (leading, trailing, and intermediate) from the email address.
  String normalizedEmail = emailAddress.toLowerCase().replaceAll("\\s+", "");
  String[] emailParts = normalizedEmail.split("@", 2);
  if (emailParts.length == 2 && emailParts[1].matches("^(gmail|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].replaceAll("\\.", "");
    // Removes any '+' and all characters that follow it 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, true);
}

/**
 * Returns the result of normalizing and hashing a phone number. For this use case, Google Ads
 * requires phone numbers to be in E.164 format.
 *
 * @param digest the digest to use to hash the normalized string.
 * @param phoneNumber the phone number to normalize and hash.
 */
private String normalizeAndHashPhoneNumber(MessageDigest digest, String phoneNumber)
    throws UnsupportedEncodingException {
  // Removes non-digit characters and prepends a leading '+' sign.
  String digitsOnly = phoneNumber.replaceAll("[^0-9]", "");
  String formattedPhone = "+" + digitsOnly;
  if (!formattedPhone.matches("^\\+[1-9]\\d{6,14}$")) {
    throw new IllegalArgumentException("Phone number must be in E.164 format: " + phoneNumber);
  }
  return normalizeAndHash(digest, formattedPhone, true);
}
      

#C

/// <summary>
/// Normalizes the email address and hashes it. For this use case, Google Ads 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();
}
      

PHP

private static function normalizeAndHash(
    string $hashAlgorithm,
    string $value,
    bool $trimIntermediateSpaces
): string {
    // Normalizes by first converting all characters to lowercase, then trimming spaces.
    $normalized = strtolower($value);
    if ($trimIntermediateSpaces === true) {
        // Removes leading, trailing, and intermediate spaces.
        $normalized = str_replace(' ', '', $normalized);
    } else {
        // Removes only leading and trailing spaces.
        $normalized = trim($normalized);
    }
    return hash($hashAlgorithm, strtolower(trim($normalized)));
}

/**
 * Returns the result of normalizing and hashing an email address. For this use case, Google
 * Ads 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, true);
}
      

Python

def normalize_and_hash_email_address(email_address):
    """Returns the result of normalizing and hashing an email address.

    For this use case, Google Ads 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.strip().lower()
    email_parts = normalized_email.split("@")

    # Check that there are at least two segments
    if len(email_parts) > 1:
        # Removes any '.' and '+' characters from the portion of the email address
        # before the domain
        chars_to_remove = ".+"
        translation_table = str.maketrans("", "", chars_to_remove)
        email_parts[0] = email_parts[0].translate(translation_table)
        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/9888656

    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/9888656.
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, Google Ads 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
      

Perl

sub normalize_and_hash {
  my $value                    = shift;
  my $trim_intermediate_spaces = shift;

  if ($trim_intermediate_spaces) {
    $value =~ s/\s+//g;
  } else {
    $value =~ s/^\s+|\s+$//g;
  }
  return sha256_hex(lc $value);
}

# Returns the result of normalizing and hashing an email address. For this use
# case, Google Ads requires removal of any '.' characters preceding 'gmail.com'
# or 'googlemail.com'.
sub normalize_and_hash_email_address {
  my $email_address = shift;

  my $normalized_email = lc $email_address;
  my @email_parts      = split('@', $normalized_email);
  if (scalar @email_parts > 1
    && $email_parts[1] =~ /^(gmail|googlemail)\.com\s*/)
  {
    # Remove any '.' characters from the portion of the email address before the
    # domain if the domain is 'gmail.com' or 'googlemail.com'.
    $email_parts[0] =~ s/\.//g;
    $normalized_email = sprintf '%s@%s', $email_parts[0], $email_parts[1];
  }
  return normalize_and_hash($normalized_email, 1);
}
      

curl

تعبئة عناصر ConversionAdjustment

يوضّح القسم التالي كيفية إنشاء تعديل تحسين يتضمّن معرّف طلب، بالإضافة إلى معرّفات لعنوان البريد الإلكتروني ورقم الهاتف والعنوان الجغرافي، مع تطبيق التوحيد والتجزئة على النحو المطلوب. كأفضل ممارسة، يمكنك تضمين gclid في التعديل إذا كان متاحًا.

تتطابق هذه الخطوة تقريبًا مع دليل استيراد تعديلات قيم الإحالات الناجحة، مع بعض التحذيرات:

  • املأ الحقل user_identifiers ببيانات المستخدمين التي تمّت تسويتها وتجزئتها. إذا كان لديك عدة معرّفات مستخدمين متاحة، أنشئ عنصر UserIdentifier منفصلاً لكل معرّف، بحد أقصى خمسة معرّفات. لتضمين عنوان جغرافي في الحقل address_info، يجب ملء الحقول الأربعة المطلوبة (hashed_first_name وhashed_last_name وcountry_code وpostal_code). إذا لم يتوفّر أيّ من هذه الحقول الأربعة (على سبيل المثال، عندما يكون لديك الاسم الأول واسم العائلة للمستخدم فقط)، يجب حذف العنصر UserIdentifier من الحقل address_info.

جافا

// Creates a builder for constructing the enhancement adjustment.
ConversionAdjustment.Builder enhancementBuilder =
    ConversionAdjustment.newBuilder().setAdjustmentType(ConversionAdjustmentType.ENHANCEMENT);

// Extracts user email, phone, and address info from the raw data, normalizes and hashes it,
// then wraps it in UserIdentifier objects.
// Creates a separate UserIdentifier object for each. The data in this example is hardcoded, but
// in your application you might read the raw data from an input file.

// IMPORTANT: Since the identifier attribute of UserIdentifier
// (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier) is a
// oneof
// (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must set only ONE of
// hashedEmail, hashedPhoneNumber, mobileId, thirdPartyUserId, or addressInfo. Setting more
// than one of these attributes on the same UserIdentifier will clear all the other members
// of the oneof. For example, the following code is INCORRECT and will result in a
// UserIdentifier with ONLY a hashedPhoneNumber.
//
// UserIdentifier incorrectlyPopulatedUserIdentifier =
//     UserIdentifier.newBuilder()
//         .setHashedEmail("...")
//         .setHashedPhoneNumber("...")
//         .build();

ImmutableMap.Builder<String, String> rawRecordBuilder =
    ImmutableMap.<String, String>builder()
        // Email address that includes a period (.) and plus (+) suffix before the Gmail domain.
        .put("email", "alex.2+myalias@gmail.com")
        // Address that includes all four required elements: first name, last name, country
        // code, and postal code.
        .put("firstName", "Alex")
        .put("lastName", "Quinn")
        .put("countryCode", "US")
        .put("postalCode", "94045")
        // Phone number to be converted to E.164 format, with a leading '+' as required.
        .put("phone", "+1 800-555-0102")
        // This example lets you put conversion details as arguments, but in reality you might
        // store this data alongside other user data, so we include it in this sample user
        // record.
        .put("orderId", orderId)
        .put("conversionActionId", Long.toString(conversionActionId))
        .put("currencyCode", "USD");

// Adds entries for the optional fields.
if (conversionDateTime != null) {
  rawRecordBuilder.put("conversionDateTime", conversionDateTime);
}
if (userAgent != null) {
  rawRecordBuilder.put("userAgent", userAgent);
}

// Builds the map representing the record.
Map<String, String> rawRecord = rawRecordBuilder.build();

// Creates a SHA256 message digest for hashing user identifiers in a privacy-safe way, as
// described at https://support.google.com/google-ads/answer/9888656.
MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256");

// Creates a list for the user identifiers.
List<UserIdentifier> userIdentifiers = new ArrayList<>();

// Creates a user identifier using the hashed email address, using the normalize and hash method
// specifically for email addresses.
UserIdentifier emailIdentifier =
    UserIdentifier.newBuilder()
        // Optional: specify the user identifier source.
        .setUserIdentifierSource(UserIdentifierSource.FIRST_PARTY)
        // Uses the normalize and hash method specifically for email addresses.
        .setHashedEmail(normalizeAndHashEmailAddress(sha256Digest, rawRecord.get("email")))
        .build();
userIdentifiers.add(emailIdentifier);

// Checks if the record has a phone number, and if so, adds a UserIdentifier for it.
if (rawRecord.containsKey("phone")) {
  UserIdentifier hashedPhoneNumberIdentifier =
      UserIdentifier.newBuilder()
          .setHashedPhoneNumber(
              normalizeAndHashPhoneNumber(sha256Digest, rawRecord.get("phone")))
          .build();
  // Adds the hashed phone number identifier to the UserData object's list.
  userIdentifiers.add(hashedPhoneNumberIdentifier);
}

// Checks if the record has all the required mailing address elements, and if so, adds a
// UserIdentifier for the mailing address.
if (rawRecord.containsKey("firstName")) {
  // Checks if the record contains all the other required elements of a mailing address.
  Set<String> missingAddressKeys = new HashSet<>();
  for (String addressKey : new String[] {"lastName", "countryCode", "postalCode"}) {
    if (!rawRecord.containsKey(addressKey)) {
      missingAddressKeys.add(addressKey);
    }
  }

  if (!missingAddressKeys.isEmpty()) {
    System.out.printf(
        "Skipping addition of mailing address information because the following required keys"
            + " are missing: %s%n",
        missingAddressKeys);
  } else {
    // Creates an OfflineUserAddressInfo object that contains all the required elements of a
    // mailing address.
    OfflineUserAddressInfo addressInfo =
        OfflineUserAddressInfo.newBuilder()
            .setHashedFirstName(
                normalizeAndHash(sha256Digest, rawRecord.get("firstName"), false))
            .setHashedLastName(normalizeAndHash(sha256Digest, rawRecord.get("lastName"), false))
            .setCountryCode(rawRecord.get("countryCode"))
            .setPostalCode(rawRecord.get("postalCode"))
            .build();
    UserIdentifier addressIdentifier =
        UserIdentifier.newBuilder().setAddressInfo(addressInfo).build();
    // Adds the address identifier to the UserData object's list.
    userIdentifiers.add(addressIdentifier);
  }
}

// Adds the user identifiers to the enhancement adjustment.
enhancementBuilder.addAllUserIdentifiers(userIdentifiers);
      

#C

// Normalize and hash the raw data, then wrap it in UserIdentifier objects.
// Create a separate UserIdentifier object for each. The data in this example is
// hardcoded, but in your application you might read the raw data from an input file.
//
// IMPORTANT: Since the identifier attribute of UserIdentifier
// (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier)
// is a oneof
// (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must set
// only ONE of hashed_email, hashed_phone_number, mobile_id, third_party_user_id,
// or address-info. Setting more than one of these attributes on the same UserIdentifier
// will clear all the other members of the oneof. For example, the following code is
// INCORRECT and will result in a UserIdentifier with ONLY a hashed_phone_number:
// UserIdentifier incorrectlyPopulatedUserIdentifier = new UserIdentifier()
// {
//         HashedEmail = "..."
//         HashedPhoneNumber = "..."
// }
UserIdentifier addressIdentifier = new UserIdentifier()
{
    AddressInfo = new OfflineUserAddressInfo()
    {
        HashedFirstName = NormalizeAndHash("Dana"),
        HashedLastName = NormalizeAndHash("Quinn"),
        HashedStreetAddress = NormalizeAndHash("1600 Amphitheatre Pkwy"),
        City = "Mountain View",
        State = "CA",
        PostalCode = "94043",
        CountryCode = "US"
    },
    // Optional: Specifies the user identifier source.
    UserIdentifierSource = UserIdentifierSource.FirstParty
};

// Creates a user identifier using the hashed email address.
UserIdentifier emailIdentifier = new UserIdentifier()
{
    UserIdentifierSource = UserIdentifierSource.FirstParty,
    // Uses the normalize and hash method specifically for email addresses.
    HashedEmail = NormalizeAndHashEmailAddress("dana@example.com")
};

// Adds the user identifiers to the enhancement adjustment.
enhancement.UserIdentifiers.AddRange(new[] { addressIdentifier, emailIdentifier });
      

PHP

// Creates the conversion enhancement.
$enhancement =
    new ConversionAdjustment(['adjustment_type' => ConversionAdjustmentType::ENHANCEMENT]);

// Extracts user email, phone, and address info from the raw data, normalizes and hashes it,
// then wraps it in UserIdentifier objects.
// Creates a separate UserIdentifier object for each. The data in this example is hardcoded,
// but in your application you might read the raw data from an input file.

// IMPORTANT: Since the identifier attribute of UserIdentifier
// (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier) is a
// oneof
// (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must set only ONE
// of hashedEmail, hashedPhoneNumber, mobileId, thirdPartyUserId, or addressInfo. Setting
// more than one of these attributes on the same UserIdentifier will clear all the other
// members of the oneof. For example, the following code is INCORRECT and will result in a
// UserIdentifier with ONLY a hashedPhoneNumber.
//
// $incorrectlyPopulatedUserIdentifier = new UserIdentifier([
//    'hashed_email' => '...',
//    'hashed_phone_number' => '...'
// ]);

$rawRecord = [
    // Email address that includes a period (.) before the Gmail domain.
    'email' => 'alex.2@example.com',
    // Address that includes all four required elements: first name, last name, country
    // code, and postal code.
    'firstName' => 'Alex',
    'lastName' => 'Quinn',
    'countryCode' => 'US',
    'postalCode' => '94045',
    // Phone number to be converted to E.164 format, with a leading '+' as required.
    'phone' => '+1 800 5550102',
    // This example lets you input conversion details as arguments, but in reality you might
    // store this data alongside other user data, so we include it in this sample user
    // record.
    'orderId' => $orderId,
    'conversionActionId' => $conversionActionId,
    'conversionDateTime' => $conversionDateTime,
    'currencyCode' => 'USD'
];

// Creates a list for the user identifiers.
$userIdentifiers = [];

// Uses the SHA-256 hash algorithm for hashing user identifiers in a privacy-safe way, as
// described at https://support.google.com/google-ads/answer/9888656.
$hashAlgorithm = "sha256";

// Creates a user identifier using the hashed email address, using the normalize and hash
// method specifically for email addresses.
$emailIdentifier = new UserIdentifier(
    [
    // Uses the normalize and hash method specifically for email addresses.
    'hashed_email' => self::normalizeAndHashEmailAddress(
        $hashAlgorithm,
        $rawRecord['email']
    ),
    // Optional: Specifies the user identifier source.
    'user_identifier_source' => UserIdentifierSource::FIRST_PARTY
    ]
);
$userIdentifiers[] = $emailIdentifier;

// Checks if the record has a phone number, and if so, adds a UserIdentifier for it.
if (array_key_exists('phone', $rawRecord)) {
    $hashedPhoneNumberIdentifier = new UserIdentifier(
        [
        'hashed_phone_number' => self::normalizeAndHash(
            $hashAlgorithm,
            $rawRecord['phone'],
            true
        )
        ]
    );
    // Adds the hashed email identifier to the user identifiers list.
    $userIdentifiers[] = $hashedPhoneNumberIdentifier;
}

// Checks if the record has all the required mailing address elements, and if so, adds a
// UserIdentifier for the mailing address.
if (array_key_exists('firstName', $rawRecord)) {
    // Checks if the record contains all the other required elements of a mailing
    // address.
    $missingAddressKeys = [];
    foreach (['lastName', 'countryCode', 'postalCode'] as $addressKey) {
        if (!array_key_exists($addressKey, $rawRecord)) {
            $missingAddressKeys[] = $addressKey;
        }
    }
    if (!empty($missingAddressKeys)) {
        printf(
            "Skipping addition of mailing address information because the "
            . "following required keys are missing: %s%s",
            json_encode($missingAddressKeys),
            PHP_EOL
        );
    } else {
        // Creates an OfflineUserAddressInfo object that contains all the required
        // elements of a mailing address.
        $addressIdentifier = new UserIdentifier(
            [
            'address_info' => new OfflineUserAddressInfo(
                [
                'hashed_first_name' => self::normalizeAndHash(
                    $hashAlgorithm,
                    $rawRecord['firstName'],
                    false
                ),
                'hashed_last_name' => self::normalizeAndHash(
                    $hashAlgorithm,
                    $rawRecord['lastName'],
                    false
                ),
                'country_code' => $rawRecord['countryCode'],
                'postal_code' => $rawRecord['postalCode']
                ]
            )
            ]
        );
        // Adds the address identifier to the user identifiers list.
        $userIdentifiers[] = $addressIdentifier;
    }
}

// Adds the user identifiers to the conversion.
$enhancement->setUserIdentifiers($userIdentifiers);
      

Python

# Extracts user email, phone, and address info from the raw data, normalizes
# and hashes it, then wraps it in UserIdentifier objects. Creates a separate
# UserIdentifier object for each. The data in this example is hardcoded, but
# in your application you might read the raw data from an input file.

# IMPORTANT: Since the identifier attribute of UserIdentifier
# (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier)
# is a oneof
# (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must
# set only ONE of hashed_email, hashed_phone_number, mobile_id,
# third_party_user_id, or address_info. Setting more than one of these
# attributes on the same UserIdentifier will clear all the other members of
# the oneof. For example, the following code is INCORRECT and will result in
# a UserIdentifier with ONLY a hashed_phone_number:
#
# incorrectly_populated_user_identifier = client.get_type("UserIdentifier")
# incorrectly_populated_user_identifier.hashed_email = "...""
# incorrectly_populated_user_identifier.hashed_phone_number = "...""

raw_record = {
    # Email address that includes a period (.) before the Gmail domain.
    "email": "alex.2@example.com",
    # Address that includes all four required elements: first name, last
    # name, country code, and postal code.
    "first_name": "Alex",
    "last_name": "Quinn",
    "country_code": "US",
    "postal_code": "94045",
    # Phone number to be converted to E.164 format, with a leading '+' as
    # required.
    "phone": "+1 800 5550102",
    # This example lets you input conversion details as arguments, but in
    # reality you might store this data alongside other user data, so we
    # include it in this sample user record.
    "order_id": order_id,
    "conversion_action_id": conversion_action_id,
    "conversion_date_time": conversion_date_time,
    "currency_code": "USD",
    "user_agent": user_agent,
}

# Constructs the enhancement adjustment.
conversion_adjustment = client.get_type("ConversionAdjustment")
conversion_adjustment.adjustment_type = (
    client.enums.ConversionAdjustmentTypeEnum.ENHANCEMENT
)

# Creates a user identifier using the hashed email address, using the
# normalize and hash method specifically for email addresses.
email_identifier = client.get_type("UserIdentifier")
# Optional: Specifies the user identifier source.
email_identifier.user_identifier_source = (
    client.enums.UserIdentifierSourceEnum.FIRST_PARTY
)
# Uses the normalize and hash method specifically for email addresses.
email_identifier.hashed_email = normalize_and_hash_email_address(
    raw_record["email"]
)
# Adds the email identifier to the conversion adjustment.
conversion_adjustment.user_identifiers.append(email_identifier)

# Checks if the record has a phone number, and if so, adds a UserIdentifier
# for it.
if raw_record.get("phone") is not None:
    phone_identifier = client.get_type("UserIdentifier")
    phone_identifier.hashed_phone_number = normalize_and_hash(
        raw_record["phone"]
    )
    # Adds the phone identifier to the conversion adjustment.
    conversion_adjustment.user_identifiers.append(phone_identifier)

# Checks if the record has all the required mailing address elements, and if
# so, adds a UserIdentifier for the mailing address.
if raw_record.get("first_name") is not None:
    # Checks if the record contains all the other required elements of a
    # mailing address.
    required_keys = ["last_name", "country_code", "postal_code"]
    # Builds a new list of the required keys that are missing from
    # raw_record.
    missing_keys = [
        key for key in required_keys if key not in raw_record.keys()
    ]
    if len(missing_keys) > 0:
        print(
            "Skipping addition of mailing address information because the"
            f"following required keys are missing: {missing_keys}"
        )
    else:
        # Creates a user identifier using sample values for the user address,
        # hashing where required.
        address_identifier = client.get_type("UserIdentifier")
        address_info = address_identifier.address_info
        address_info.hashed_first_name = normalize_and_hash(
            raw_record["first_name"]
        )
        address_info.hashed_last_name = normalize_and_hash(
            raw_record["last_name"]
        )
        address_info.country_code = raw_record["country_code"]
        address_info.postal_code = raw_record["postal_code"]
        # Adds the address identifier to the conversion adjustment.
        conversion_adjustment.user_identifiers.append(address_identifier)
      

Ruby

# Extracts user email, phone, and address info from the raw data, normalizes
# and hashes it, then wraps it in UserIdentifier objects. Creates a separate
# UserIdentifier object for each. The data in this example is hardcoded, but
# in your application you might read the raw data from an input file.

# IMPORTANT: Since the identifier attribute of UserIdentifier
# (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier)
# is a oneof
# (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must
# set only ONE of hashed_email, hashed_phone_number, mobile_id,
# third_party_user_id, or address_info. Setting more than one of these
# attributes on the same UserIdentifier will clear all the other members of
# the oneof. For example, the following code is INCORRECT and will result in
# a UserIdentifier with ONLY a hashed_phone_number:
#
# incorrectly_populated_user_identifier.hashed_email = "...""
# incorrectly_populated_user_identifier.hashed_phone_number = "...""

raw_record = {
    # Email address that includes a period (.) before the Gmail domain.
    "email" => "alex.2@example.com",
    # Address that includes all four required elements: first name, last
    # name, country code, and postal code.
    "first_name" => "Alex",
    "last_name" => "Quinn",
    "country_code" => "US",
    "postal_code" => "94045",
    # Phone number to be converted to E.164 format, with a leading '+' as
    # required.
    "phone" => "+1 800 5550102",
    # This example lets you input conversion details as arguments, but in
    # reality you might store this data alongside other user data, so we
    # include it in this sample user record.
    "order_id" => order_id,
    "conversion_action_id" => conversion_action_id,
    "conversion_date_time" => conversion_date_time,
    "currency_code" => "USD",
    "user_agent" => user_agent,
}

enhancement = client.resource.conversion_adjustment do |ca|
  ca.conversion_action = client.path.conversion_action(customer_id, conversion_action_id)
  ca.adjustment_type = :ENHANCEMENT
  ca.order_id = order_id

  # Sets the conversion date and time if provided. Providing this value is
  # optional but recommended.
  unless conversion_date_time.nil?
    ca.gclid_date_time_pair = client.resource.gclid_date_time_pair do |pair|
      pair.conversion_date_time = conversion_date_time
    end
  end

  # Creates a user identifier using the hashed email address, using the
  # normalize and hash method specifically for email addresses.
  ca.user_identifiers << client.resource.user_identifier do |ui|
    # Uses the normalize and hash method specifically for email addresses.
    ui.hashed_email = normalize_and_hash_email(raw_record["email"])
    # Optional: Specifies the user identifier source.
    ui.user_identifier_source = :FIRST_PARTY
  end

  # Checks if the record has a phone number, and if so, adds a UserIdentifier
  # for it.
  unless raw_record["phone"].nil?
    ca.user_identifiers << client.resource.user_identifier do |ui|
      ui.hashed_phone_number = normalize_and_hash_email(raw_record["phone"])
    end
  end

  # Checks if the record has all the required mailing address elements, and if
  # so, adds a UserIdentifier for the mailing address.
  unless raw_record["first_name"].nil?
    # Checks if the record contains all the other required elements of a
    # mailing address.
    required_keys = ["last_name", "country_code", "postal_code"]
    # Builds a new list of the required keys that are missing from
    # raw_record.
    missing_keys = required_keys - raw_record.keys
    if missing_keys
        puts(
            "Skipping addition of mailing address information because the" \
            "following required keys are missing: #{missing_keys}"
        )
    else
      ca.user_identifiers << client.resource.user_identifier do |ui|
        ui.address_info = client.resource.offline_user_address_info do |info|
          # Certain fields must be hashed using SHA256 in order to handle
          # identifiers in a privacy-safe way, as described at
          # https://support.google.com/google-ads/answer/9888656.
          info.hashed_first_name = normalize_and_hash( raw_record["first_name"])
          info.hashed_last_name = normalize_and_hash( raw_record["last_name"])
          info.postal_code = normalize_and_hash(raw_record["country_code"])
          info.country_code = normalize_and_hash(raw_record["postal_code"])
        end
      end
    end
  end
      

Perl

# Construct the enhancement adjustment.
my $enhancement =
  Google::Ads::GoogleAds::V26::Services::ConversionAdjustmentUploadService::ConversionAdjustment
  ->new({
    adjustmentType => ENHANCEMENT
  });

# Extract user email, phone, and address info from the raw data,
# normalize and hash it, then wrap it in UserIdentifier objects.
# Create a separate UserIdentifier object for each.
# The data in this example is hardcoded, but in your application
# you might read the raw data from an input file.
#
# IMPORTANT: Since the identifier attribute of UserIdentifier
# (https://developers.google.com/google-ads/api/reference/rpc/latest/UserIdentifier)
# is a oneof
# (https://protobuf.dev/programming-guides/proto3/#oneof-features), you must set
# only ONE of hashed_email, hashed_phone_number, mobile_id, third_party_user_id,
# or address-info. Setting more than one of these attributes on the same UserIdentifier
# will clear all the other members of the oneof. For example, the following code is
# INCORRECT and will result in a UserIdentifier with ONLY a hashed_phone_number:
#
# my $incorrect_user_identifier = Google::Ads::GoogleAds::V26::Common::UserIdentifier->new({
#   hashedEmail => '...',
#   hashedPhoneNumber => '...',
# });
my $raw_record = {
  # Email address that includes a period (.) before the Gmail domain.
  email => 'alex.2@example.com',
  # Address that includes all four required elements: first name, last
  # name, country code, and postal code.
  firstName   => 'Alex',
  lastName    => 'Quinn',
  countryCode => 'US',
  postalCode  => '94045',
  # Phone number to be converted to E.164 format, with a leading '+' as
  # required.
  phone => '+1 800 5550102',
  # This example lets you input conversion details as arguments,
  # but in reality you might store this data alongside other user data,
  # so we include it in this sample user record.
  orderId            => $order_id,
  conversionActionId => $conversion_action_id,
  conversionDateTime => $conversion_date_time,
  currencyCode       => "USD",
  userAgent          => $user_agent,
};
my $user_identifiers = [];

# Create a user identifier using the hashed email address, using the normalize
# and hash method specifically for email addresses.
my $hashed_email = normalize_and_hash_email_address($raw_record->{email});
push(
  @$user_identifiers,
  Google::Ads::GoogleAds::V26::Common::UserIdentifier->new({
      hashedEmail => $hashed_email,
      # Optional: Specify the user identifier source.
      userIdentifierSource => FIRST_PARTY
    }));

# Check if the record has a phone number, and if so, add a UserIdentifier for it.
if (defined $raw_record->{phone}) {
  # Add the hashed phone number identifier to the list of UserIdentifiers.
  push(
    @$user_identifiers,
    Google::Ads::GoogleAds::V26::Common::UserIdentifier->new({
        hashedPhoneNumber => normalize_and_hash($raw_record->{phone}, 1)}));
}

# Confirm the record has all the required mailing address elements, and if so, add
# a UserIdentifier for the mailing address.
if (defined $raw_record->{firstName}) {
  my $required_keys = ["lastName", "countryCode", "postalCode"];
  my $missing_keys  = [];

  foreach my $key (@$required_keys) {
    if (!defined $raw_record->{$key}) {
      push(@$missing_keys, $key);
    }
  }

  if (@$missing_keys) {
    print
      "Skipping addition of mailing address information because the following"
      . "keys are missing: "
      . join(",", @$missing_keys);
  } else {
    push(
      @$user_identifiers,
      Google::Ads::GoogleAds::V26::Common::UserIdentifier->new({
          addressInfo =>
            Google::Ads::GoogleAds::V26::Common::OfflineUserAddressInfo->new({
              # First and last name must be normalized and hashed.
              hashedFirstName => normalize_and_hash($raw_record->{firstName}),
              hashedLastName  => normalize_and_hash($raw_record->{lastName}),
              # Country code and zip code are sent in plain text.
              countryCode => $raw_record->{countryCode},
              postalCode  => $raw_record->{postalCode},
            })}));
  }
}

# Add the user identifiers to the enhancement adjustment.
$enhancement->{userIdentifiers} = $user_identifiers;
      

curl

جافا

// Sets the conversion action.
enhancementBuilder.setConversionAction(
    ResourceNames.conversionAction(
        customerId, Long.parseLong(rawRecord.get("conversionActionId"))));

// Sets the order ID. Enhancements MUST use order ID instead of GCLID date/time pair.
enhancementBuilder.setOrderId(rawRecord.get("orderId"));

// Sets the conversion date and time if provided. Providing this value is optional but
// recommended.
if (rawRecord.containsKey("conversionDateTime")) {
  enhancementBuilder.setGclidDateTimePair(
      GclidDateTimePair.newBuilder()
          .setConversionDateTime(rawRecord.get("conversionDateTime")));
}

// Sets the user agent if provided. This should match the user agent of the request that sent
// the original conversion so the conversion and its enhancement are either both attributed as
// same-device or both attributed as cross-device.
if (rawRecord.containsKey("userAgent")) {
  enhancementBuilder.setUserAgent(rawRecord.get("userAgent"));
}
      

#C

// Set the conversion action.
enhancement.ConversionAction =
    ResourceNames.ConversionAction(customerId, conversionActionId);

// Set the order ID. Enhancements MUST use order ID instead of GCLID date/time pair.
enhancement.OrderId = orderId;

// Sets the conversion date and time if provided. Providing this value is optional but
// recommended.
if (string.IsNullOrEmpty(conversionDateTime))
{
    enhancement.GclidDateTimePair = new GclidDateTimePair()
    {
        ConversionDateTime = conversionDateTime
    };
}

// Sets optional fields where a value was provided.
if (!string.IsNullOrEmpty(userAgent))
{
    // Sets the user agent. This should match the user agent of the request that
    // sent the original conversion so the conversion and its enhancement are either
    // both attributed as same-device or both attributed as cross-device.
    enhancement.UserAgent = userAgent;
}

      

PHP

// Sets the conversion action.
$enhancement->setConversionAction(
    ResourceNames::forConversionAction($customerId, $rawRecord['conversionActionId'])
);

// Sets the order ID. Enhancements MUST use order ID instead of GCLID date/time pair.
if (!empty($rawRecord['orderId'])) {
    $enhancement->setOrderId($rawRecord['orderId']);
}

// Sets the conversion date and time if provided. Providing this value is optional but
// recommended.
if (!empty($rawRecord['conversionDateTime'])) {
    // Sets the conversion date and time if provided. Providing this value is optional but
    // recommended.
    $enhancement->setGclidDateTimePair(
        new GclidDateTimePair(
            [
            'conversion_date_time' => $rawRecord['conversionDateTime']
            ]
        )
    );
}

// Sets the user agent if provided. This should match the user agent of the request that
// sent the original conversion so the conversion and its enhancement are either both
// attributed as same-device or both attributed as cross-device.
if (!empty($rawRecord['userAgent'])) {
    $enhancement->setUserAgent($rawRecord['userAgent']);
}
      

Python

conversion_action_service = client.get_service("ConversionActionService")
# Sets the conversion action.
conversion_adjustment.conversion_action = (
    conversion_action_service.conversion_action_path(
        customer_id, raw_record["conversion_action_id"]
    )
)

# Sets the order ID. Enhancements MUST use order ID instead of GCLID
# date/time pair.
conversion_adjustment.order_id = order_id

# Sets the conversion date and time if provided. Providing this value is
# optional but recommended.
if raw_record.get("conversion_date_time"):
    conversion_adjustment.gclid_date_time_pair.conversion_date_time = (
        raw_record["conversion_date_time"]
    )

# Sets optional fields where a value was provided
if raw_record.get("user_agent"):
    # Sets the user agent. This should match the user agent of the request
    # that sent the original conversion so the conversion and its
    # enhancement are either both attributed as same-device or both
    # attributed as cross-device.
    conversion_adjustment.user_agent = user_agent
      

Ruby

ca.conversion_action = client.path.conversion_action(customer_id, conversion_action_id)
ca.adjustment_type = :ENHANCEMENT
ca.order_id = order_id

# Sets the conversion date and time if provided. Providing this value is
# optional but recommended.
unless conversion_date_time.nil?
  ca.gclid_date_time_pair = client.resource.gclid_date_time_pair do |pair|
    pair.conversion_date_time = conversion_date_time
  end
end

# Creates a user identifier using the hashed email address, using the
# normalize and hash method specifically for email addresses.
ca.user_identifiers << client.resource.user_identifier do |ui|
  # Uses the normalize and hash method specifically for email addresses.
  ui.hashed_email = normalize_and_hash_email(raw_record["email"])
  # Optional: Specifies the user identifier source.
  ui.user_identifier_source = :FIRST_PARTY
end

# Checks if the record has a phone number, and if so, adds a UserIdentifier
# for it.
unless raw_record["phone"].nil?
  ca.user_identifiers << client.resource.user_identifier do |ui|
    ui.hashed_phone_number = normalize_and_hash_email(raw_record["phone"])
  end
end

# Checks if the record has all the required mailing address elements, and if
# so, adds a UserIdentifier for the mailing address.
unless raw_record["first_name"].nil?
  # Checks if the record contains all the other required elements of a
  # mailing address.
  required_keys = ["last_name", "country_code", "postal_code"]
  # Builds a new list of the required keys that are missing from
  # raw_record.
  missing_keys = required_keys - raw_record.keys
  if missing_keys
      puts(
          "Skipping addition of mailing address information because the" \
          "following required keys are missing: #{missing_keys}"
      )
  else
    ca.user_identifiers << client.resource.user_identifier do |ui|
      ui.address_info = client.resource.offline_user_address_info do |info|
        # Certain fields must be hashed using SHA256 in order to handle
        # identifiers in a privacy-safe way, as described at
        # https://support.google.com/google-ads/answer/9888656.
        info.hashed_first_name = normalize_and_hash( raw_record["first_name"])
        info.hashed_last_name = normalize_and_hash( raw_record["last_name"])
        info.postal_code = normalize_and_hash(raw_record["country_code"])
        info.country_code = normalize_and_hash(raw_record["postal_code"])
      end
    end
  end
end

# Sets optional fields where a value was provided.
unless user_agent.nil?
  # Sets the user agent. This should match the user agent of the request
  # that sent the original conversion so the conversion and its enhancement
  # are either both attributed as same-device or both attributed as
  # cross-device.
  ca.user_agent = user_agent
end
      

Perl

# Set the conversion action.
$enhancement->{conversionAction} =
  Google::Ads::GoogleAds::V26::Utils::ResourceNames::conversion_action(
  $customer_id, $raw_record->{conversionActionId});

# Set the order ID. Enhancements MUST use order ID instead of GCLID date/time pair.
$enhancement->{orderId} = $raw_record->{orderId};

# Set the conversion date and time if provided. Providing this value is optional
# but recommended.
if (defined $raw_record->{conversionDateTime}) {
  $enhancement->{gclidDateTimePair} =
    Google::Ads::GoogleAds::V26::Services::ConversionAdjustmentUploadService::GclidDateTimePair
    ->new({
      conversionDateTime => $raw_record->{conversionDateTime}});
}

# Set the user agent if provided. This should match the user agent of the
# request that sent the original conversion so the conversion and its enhancement
# are either both attributed as same-device or both attributed as cross-device.
if (defined $raw_record->{userAgent}) {
  $enhancement->{userAgent} = $raw_record->{userAgent};
}
      

curl

ملخّص مخططَي Request وConversionAdjustment

تلخّص الجداول التالية الحقول ذات المستوى الأعلى في UploadConversionAdjustmentsRequest والحقول لكل عنصر في ConversionAdjustment (conversion_adjustments[]) عند تحميل الإحالات الناجحة المحسّنة للويب باستخدام ConversionAdjustmentUploadService.UploadConversionAdjustments:

حقل الطلب المتطلبات التنسيق والقيود
customer_id مطلوب يجب ضبطه على رقم تعريف عميل الإحالة الناجحة في "إعلانات Google" (google_ads_conversion_customer في customer.conversion_tracking_setting)، بدون واصلات.
conversion_adjustments[] مطلوب ما يصل إلى 2,000 إدخال ConversionAdjustment لكل طلب (TOO_MANY_ADJUSTMENTS_IN_REQUEST).
partial_failure مطلوب يجب ضبطها على true لتتم معالجة التعديلات الصالحة وعرض الأخطاء على مستوى الصف في partial_failure_error.
validate_only اختياري عندما تكون القيمة true، يتم التحقّق من صحة الطلب بدون تنفيذ التعديلات.
job_id اختياري يجب أن تكون القيمة موجبة int32 (من 1 إلى 2^31 - 1، و0 هي القيمة الافتراضية التي تشير إلى عدم الضبط، وتُرجع INVALID_JOB_ID إذا تم تحديدها) لتجميع طلبات متعددة ضمن مهمة منطقية واحدة في job_summaries.

يتيح كل ConversionAdjustment في conversion_adjustments[] (ما يصل إلى 2,000 تعديل لكل طلب) الحقول التالية:

حقل واحد (ConversionAdjustment) المتطلبات التنسيق والقيود
adjustment_type مطلوب يجب ضبط الحقل على ENHANCEMENT (ConversionAdjustmentType).
conversion_action مطلوب اسم المورد (customers/{conversion_customer_id}/conversionActions/{action_id}) لإجراء إحالة ناجحة من النوع ENABLED يتضمّن type = WEBPAGE تم إنشاؤه قبل 6 ساعات على الأقل من التحميل (TOO_RECENT_CONVERSION_ACTION).
order_id مطلوب معرّف المعاملة للإحالة الناجحة المطلوب تحسينها، ويجب أن يتطابق مع معرّف الطلب الذي ترسله علامة تتبُّع الإحالات الناجحة على الموقع الإلكتروني.
user_identifiers[] مطلوب من عنصر واحد إلى خمسة عناصر UserIdentifier لكل تحسين اضبط حقل user_identifier_source الاختياري (مثل FIRST_PARTY) وحقل معرّف واحد لكل إدخال:
  • ‫hashed_email: سلسلة سداسية عشرية بتنسيق SHA-256
  • ‫hashed_phone_number: سلسلة سداسية عشرية بتنسيق E.164 وخوارزمية SHA-256
  • ‫address_info: عنصر OfflineUserAddressInfo يجب توفّر hashed_first_name وhashed_last_name (سلاسل سداسية عشرية SHA-256) وcountry_code (رمز ISO 3166-1 alpha-2 غير مجزّأ مكوّن من حرفَين) وpostal_code (غير مجزّأ) في الإدخال نفسه. تكون الحقول hashed_street_address (سلسلة سداسية عشرية SHA-256) وcity (غير مجزّأة) وstate (غير مجزّأة) اختيارية. إذا لم يتوفّر أيّ من الحقول الأربعة المطلوبة، يمكنك حذف الحقل address_info. تقبل واجهة برمجة التطبيقات العناوين الجزئية غير الفارغة بدون عرض خطأ في الحقل partial_failure_error، ولكن يتم تجاهلها في عملية المطابقة اللاحقة.
gclid_date_time_pair اختياري (يُنصح به) عنصر GclidDateTimePair يحتوي على حقلَي gclid وconversion_date_time للإحالة الناجحة الأصلية، بتنسيق yyyy-mm-dd HH:mm:ss+|-HH:mm (على سبيل المثال، 2026-06-01 14:30:00-04:00). يجب تحميل التحسينات خلال 24 ساعة من حدث الإحالة الناجحة. تقبل الرسالة GclidDateTimePair الحقل gclid فقط. لا تتيح "إعلانات Google" ميزة "الإحالات الناجحة المحسّنة للويب" عندما تملأ نقرة المَعلمة gbraid أو wbraid بدلاً من المَعلمة gclid.
adjustment_date_time اختياري الطابع الزمني لوقت إجراء التعديل، بتنسيق yyyy-mm-dd HH:mm:ss+|-HH:mm في حال ضبط هذا الطابع الزمني، يجب أن يكون بعد قيمة conversion_date_time وليس في المستقبل.
user_agent اختياري سلسلة عنوان HTTP الخاص بـ User-Agent من طلب الإحالة الناجحة الأصلي لكي تتشارك الإحالة الناجحة والتحسين في تحديد مصدر الجهاز نفسه (same-device أو cross-device).
restatement_value عدم الضبط على "ENHANCEMENT" يتم تجاهل هذه السياسة عندما تكون قيمة adjustment_type هي ENHANCEMENT. أرسِل عملية منفصلة باستخدام adjustment_type = RESTATEMENT لتغيير قيمة إحالة ناجحة.

تحسينات على استيراد الإحالات الناجحة

جافا

// Creates the conversion adjustment upload service client.
try (ConversionAdjustmentUploadServiceClient conversionUploadServiceClient =
    googleAdsClient.getLatestVersion().createConversionAdjustmentUploadServiceClient()) {
  // Uploads the enhancement adjustment. Partial failure should always be set to true.

  // NOTE: This request contains a single adjustment as a demonstration. However, if you have
  // multiple adjustments to upload, it's best to upload multiple adjustments per request
  // instead of sending a separate request per adjustment. See the following for per-request
  // limits:
  // https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_adjustment_upload_service
  UploadConversionAdjustmentsResponse response =
      conversionUploadServiceClient.uploadConversionAdjustments(
          UploadConversionAdjustmentsRequest.newBuilder()
              .setCustomerId(Long.toString(customerId))
              .addConversionAdjustments(enhancementBuilder)
              // Enables partial failure (must be true).
              .setPartialFailure(true)
              .build());
      

#C

// Uploads the enhancement adjustment. Partial failure should always be set to true.
//
// NOTE: This request contains a single adjustment as a demonstration.
// However, if you have multiple adjustments to upload, it's best to upload
// multiple adjustmenst per request instead of sending a separate request per
// adjustment. See the following for per-request limits:
// https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_adjust
UploadConversionAdjustmentsResponse response =
    conversionAdjustmentUploadService.UploadConversionAdjustments(
        new UploadConversionAdjustmentsRequest()
        {
            CustomerId = customerId.ToString(),
            ConversionAdjustments = { enhancement },
            // Enables partial failure (must be true).
            PartialFailure = true,
        });
      

PHP

// Issues a request to upload the conversion enhancement.
$conversionAdjustmentUploadServiceClient =
    $googleAdsClient->getConversionAdjustmentUploadServiceClient();
// NOTE: This request contains a single adjustment as a demonstration. However, if you have
// multiple adjustments to upload, it's best to upload multiple adjustments per request
// instead of sending a separate request per adjustment. See the following for per-request
// limits:
// https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_adjustment_upload_service
$response = $conversionAdjustmentUploadServiceClient->uploadConversionAdjustments(
    // Enables partial failure (must be true).
    UploadConversionAdjustmentsRequest::build($customerId, [$enhancement], true)
);
      

Python

# Creates the conversion adjustment upload service client.
conversion_adjustment_upload_service = client.get_service(
    "ConversionAdjustmentUploadService"
)
# Uploads the enhancement adjustment. Partial failure should always be set
# to true.
# NOTE: This request only uploads a single conversion, but if you have
# multiple conversions to upload, it's still best to upload them in a single
# request. See the following for per-request limits for reference:
# https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
response = conversion_adjustment_upload_service.upload_conversion_adjustments(
    customer_id=customer_id,
    conversion_adjustments=[conversion_adjustment],
    # Enables partial failure (must be true).
    partial_failure=True,
)
      

Ruby

response = client.service.conversion_adjustment_upload.upload_conversion_adjustments(
  customer_id: customer_id,
  # NOTE: This request only uploads a single conversion, but if you have
  # multiple conversions to upload, it's still best to upload them in a single
  # request. See the following for per-request limits for reference:
  # https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
  conversion_adjustments: [enhancement],
  # Partial failure must be set to true.
  partial_failure: true,
)
      

Perl

# Upload the enhancement adjustment. Partial failure should always be set to true.
#
# NOTE: This request contains a single adjustment as a demonstration.
# However, if you have multiple adjustments to upload, it's best to
# upload multiple adjustments per request instead of sending a separate
# request per adjustment. See the following for per-request limits:
# https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_adjustment_upload_service
my $response =
  $api_client->ConversionAdjustmentUploadService()
  ->upload_conversion_adjustments({
    customerId            => $customer_id,
    conversionAdjustments => [$enhancement],
    # Enable partial failure (must be true).
    partialFailure => "true"
  });
      

curl

بنية طلب REST والاستجابة له

عند استدعاء ConversionAdjustmentUploadService.UploadConversionAdjustments عبر REST، أرسِل طلب POST مع ضبط partialFailure على true:

POST https://googleads.googleapis.com/v26/customers/{customer_id}:uploadConversionAdjustments
{
  "partialFailure": true,
  "jobId": 2001,
  "conversionAdjustments": [
    {
      "conversionAction": "customers/{customer_id}/conversionActions/{conversion_action_id}",
      "adjustmentType": "ENHANCEMENT",
      "orderId": "ORDER-2026-1001",
      "gclidDateTimePair": {
        "gclid": "EAIaIQobChMI...",
        "conversionDateTime": "2026-06-01 14:30:00-04:00"
      },
      "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)",
      "userIdentifiers": [
        {
          "userIdentifierSource": "FIRST_PARTY",
          "hashedEmail": "f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a"
        },
        {
          "userIdentifierSource": "FIRST_PARTY",
          "hashedPhoneNumber": "42975f8f9e46c2e13c1a2294957e5cb8d8e6f4f7341a036c6e595bc9f5e24621"
        },
        {
          "userIdentifierSource": "FIRST_PARTY",
          "addressInfo": {
            "hashedFirstName": "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3",
            "hashedLastName": "b3a8e0e1f9ab1bfe3a36f231f676f78bb30a519d2b21e6c530c0eee8ebb4a5d0",
            "hashedStreetAddress": "35a9e381b1a27567549b5f8a6f783c167ebf809f1c4d6a9e367240484d8ce281",
            "city": "New York",
            "state": "NY",
            "postalCode": "10011",
            "countryCode": "US"
          }
        }
      ]
    },
    {
      "conversionAction": "customers/{customer_id}/conversionActions/{conversion_action_id}",
      "adjustmentType": "ENHANCEMENT",
      "userIdentifiers": [
        {
          "userIdentifierSource": "FIRST_PARTY",
          "hashedEmail": "f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a"
        }
      ]
    }
  ]
}

في هذه الدفعة المكوّنة من تعديلَين حيث يحذف التعديل الثاني orderId، تعرض الصفوف الناجحة إدخالات ConversionAdjustmentResult معبأة في results[]، بينما تعرض الصفوف التي تعذّر تنفيذها عناصر {} فارغة في results[] إلى جانب تفاصيل الخطأ على مستوى الصف في partialFailureError على UploadConversionAdjustmentsResponse:

{
  "results": [
    {
      "gclidDateTimePair": {
        "gclid": "EAIaIQobChMI...",
        "conversionDateTime": "2026-06-01 14:30:00-04:00"
      },
      "orderId": "ORDER-2026-1001",
      "conversionAction": "customers/{customer_id}/conversionActions/{conversion_action_id}",
      "adjustmentType": "ENHANCEMENT"
    },
    {}
  ],
  "jobId": "2001",
  "partialFailureError": {
    "code": 3,
    "message": "The required field was not present., at conversion_adjustments[1].order_id",
    "details": [
      {
        "@type": "type.googleapis.com/google.ads.googleads.v26.errors.GoogleAdsFailure",
        "errors": [
          {
            "errorCode": {
              "fieldError": "REQUIRED"
            },
            "message": "The required field was not present.",
            "location": {
              "fieldPathElements": [
                {
                  "fieldName": "conversion_adjustments",
                  "index": 1
                },
                {
                  "fieldName": "order_id"
                }
              ]
            }
          }
        ]
      }
    ]
  }
}

مراجعة عمليات الاستيراد

ننصحك بمراقبة بيانات التشخيص في واجهة مستخدم "إعلانات Google" وبيانات تشخيص البيانات غير الإلكترونية لأنّ كل أداة تتحقّق من مرحلة مختلفة من المسار:

  • تقرير تشخيصي للإحالات الناجحة المحسّنة (واجهة مستخدم "إعلانات Google"): يتحقّق من المطابقة غير المتزامنة بين أحداث علامات تتبُّع الموقع الإلكتروني وتحسينات واجهة برمجة التطبيقات. يمكنك الاطّلاع على هذه الصفحة لرصد معرّفات المعاملات غير المتوفّرة في العلامات، أو القيم غير المتطابقة بين العلامات وواجهة برمجة التطبيقات (order_id)، أو التغطية المنخفضة لتحسين واجهة برمجة التطبيقات، أو بيانات المستخدمين غير الموحّدة، أو حقول address_info غير المكتملة. لا تؤدي هذه المشاكل إلى ظهور أخطاء في واجهة برمجة التطبيقات أو في بيانات التشخيص غير الإلكترونية. للاطّلاع على خطوات تحديد المشاكل وحلّها، يُرجى مراجعة تنبيهات بيانات التشخيص في واجهة المستخدم بعد التحميل بنجاح من خلال واجهة برمجة التطبيقات.
  • بيانات تشخيص البيانات غير الإلكترونية (Google Ads API): تتبّع سلامة نقل البيانات في واجهة برمجة التطبيقات على مستوى الطلب وأخطاء التحقّق من الصحة، مثل أخطاء INVALID_USER_IDENTIFIER أو CONVERSION_ALREADY_ENHANCED أو FieldError.REQUIRED. تشير الحالة EXCELLENT إلى أنّ واجهة برمجة التطبيقات قد قبلت طلبات ENHANCEMENT فقط، وليس إلى أنّ التحسينات التي تم تحميلها تطابقت مع أحداث علامة الموقع الإلكتروني.

الاستعلام عن بيانات تشخيص التحميل باستخدام GAQL

يمكنك أيضًا فحص حالة التحميل على مستوى الحساب وعدد المهام الأخيرة وتنبيهات الأخطاء آليًا من خلال إرسال طلب بحث إلى offline_conversion_upload_client_summary باستخدام رقم تعريف العميل للإحالة الناجحة:

SELECT
  customer.id,
  offline_conversion_upload_client_summary.client,
  offline_conversion_upload_client_summary.status,
  offline_conversion_upload_client_summary.total_event_count,
  offline_conversion_upload_client_summary.successful_event_count,
  offline_conversion_upload_client_summary.success_rate,
  offline_conversion_upload_client_summary.pending_event_count,
  offline_conversion_upload_client_summary.pending_rate,
  offline_conversion_upload_client_summary.last_upload_date_time,
  offline_conversion_upload_client_summary.alerts,
  offline_conversion_upload_client_summary.daily_summaries,
  offline_conversion_upload_client_summary.job_summaries
FROM offline_conversion_upload_client_summary

عند إعداد تقارير عن مقاييس الإحالات الناجحة لحملاتك، ارجع إلى ربط مقاييس واجهة المستخدم لربط مقاييس واجهة مستخدم "إعلانات Google" بحقول إعداد التقارير في Google Ads API. يمكنك أيضًا الاستعلام عن المورد conversion_action للاطّلاع على إجمالي عدد الإحالات الناجحة وإجمالي قيمة الإحالة الناجحة لإجراء إحالة ناجحة معيّن.

أفضل الممارسات

يُرجى مراعاة أفضل الممارسات التالية عند تنفيذ ميزة "الإحالات الناجحة المحسّنة للويب".

التحقّق من معرّف العميل

عند استيراد الإحالات الناجحة، يجب ضبط رقم تعريف العميل على الحساب الذي يحتوي على إجراء الإحالة الناجحة والذي يتتبّع الإحالات الناجحة. للتحقّق من هذا الإعداد، يمكنك الاستعلام عن مورد Customer في "إعلانات Google" الذي يعرض الإعلانات للحصول على ConversionTrackingSetting. أرسِل طلب البحث التالي باستخدام GoogleAdsService.SearchStream للعثور على قيمة customer.conversion_tracking_setting.google_ads_conversion_customer.

SELECT
  customer.conversion_tracking_setting.google_ads_conversion_customer,
  customer.conversion_tracking_setting.conversion_tracking_status,
  customer.conversion_tracking_setting.conversion_tracking_id,
  customer.conversion_tracking_setting.cross_account_conversion_tracking_id
FROM customer

اضبط customer_id على القيمة google_ads_conversion_customer في طلباتك لاستيراد الإحالات الناجحة.

أدرِج معرّفات متعددة إذا كانت لديك

إذا كانت لديك قيمة gclid لإحالة ناجحة، أرسِلها في حقل gclid_date_time_pair بالإضافة إلى حقل user_identifiers لتحسين الأداء. بما أنّ رسالة GclidDateTimePair لا تقبل سوى حقل gclid، لا تتيح "إعلانات Google" استخدام ميزة "الإحالات الناجحة المحسّنة للويب" عندما تملأ نقرة مَعلمة gbraid أو wbraid بدلاً من مَعلمة gclid. إذا كان لديك أكثر من عنصر UserIdentifier واحد للإحالة الناجحة، يجب تضمينها جميعًا في عنصر ConversionAdjustment نفسه لزيادة احتمال حدوث مطابقة.

مراجعة أخطاء الفشل الجزئي عند إعداد عملية الدمج

عند إعداد ميزة "الإحالات الناجحة المحسّنة للويب" لأول مرة، يُرجى مراجعة أي أخطاء جزئية في حقل partial_failure_error في الردّ ومعالجتها. إذا كانت هناك مشاكل في الإعداد، يمكنك فحص هذا الحقل للتحقيق فيها ومعالجتها. لمزيد من التفاصيل والأمثلة المتعلقة بمعالجة أخطاء الفشل الجزئي، يُرجى الانتقال إلى دليل الفشل الجزئي المخصّص.

بعد حلّ أي مشاكل في حقل partial_failure_error وإكمال عملية الدمج، عليك مراقبة كلتا أداتَي التشخيص. اطّلِع على بيانات تشخيص البيانات غير الإلكترونية لمعرفة حالة نقل البيانات عبر واجهة برمجة التطبيقات، وعلى تقرير تشخيصي للإحالات الناجحة المحسّنة في واجهة مستخدم "إعلانات Google" لمعرفة حالة المطابقة بين العلامة وواجهة برمجة التطبيقات.

تجميع تعديلات متعددة في طلب واحد

إذا كانت لديك تعديلات متعددة تريد استيرادها، يمكنك تجميع العمليات (ما يصل إلى 2,000 تعديل للإحالات الناجحة لكل طلب) في UploadConversionAdjustmentsRequest واحد، بدلاً من إرسال طلب استيراد لكل تعديل.

راجِع دليل الحصص لمعرفة الحدود القصوى لعدد التعديلات لكل طلب. إذا أردت أن تجمع بيانات تشخيص البيانات غير الإلكترونية مجموعة من الطلبات ضمن المهمة المنطقية نفسها، اضبط job_id لجميع الطلبات على القيمة نفسها.

تحديد المشاكل وحلّها

استخدِم تقرير تشخيصي للإحالات الناجحة المحسّنة في واجهة مستخدم "إعلانات Google" للتأكّد من أنّ ميزة "الإحالات الناجحة المحسّنة للويب" تعمل على النحو المتوقّع. إذا ظهرت تنبيهات في واجهة المستخدم على الرغم من نجاح عمليات التحميل من خلال واجهة برمجة التطبيقات، يُرجى الاطّلاع على تنبيهات بيانات التشخيص في واجهة المستخدم بعد نجاح عملية التحميل من خلال واجهة برمجة التطبيقات.

تصحيح الأخطاء الشائعة

تساعدك الإرشادات التالية في تشخيص الأخطاء الشائعة وحلّها في ما يتعلّق بميزة "الإحالات الناجحة المحسّنة للويب".

خطأ
CUSTOMER_NOT_ACCEPTED_CUSTOMER_DATA_TERMS لم يتم قبول أحكام وشروط بيانات العملاء في customer_id من الطلب. يمكنك العثور على تعليمات حول ذلك في دليل المتطلبات الأساسية.
CONVERSION_ALREADY_ENHANCED سبق أن تلقّت هذه الإحالة الناجحة تعديلاً من النوع ENHANCEMENT باستخدام الحقلَين order_id وconversion_action المحدّدَين. تأكَّد من تقديم قيمة order_id فريدة لكل إحالة ناجحة.
CONVERSION_ACTION_NOT_ELIGIBLE_FOR_ENHANCEMENT ‫conversion_action المقدَّمة غير مؤهَّلة لاستخدام ميزة "الإحالات الناجحة المحسّنة للويب". في واجهة مستخدم "إعلانات Google"، تأكَّد من وضع علامة في المربّع تفعيل الإحالات الناجحة المحسّنة في إجراء الإحالة الناجحة المُشار إليه في طلبك. يمكنك العثور على تعليمات حول كيفية إجراء ذلك في مركز المساعدة.
INVALID_USER_IDENTIFIER حقل معرّف المستخدم المجزّأ (hashed_email أو hashed_phone_number أو hashed_first_name أو hashed_last_name أو hashed_street_address) ليس ملخّصًا صالحًا لخوارزمية SHA-256 السداسية العشرية المكوّنة من 64 حرفًا. تسوية البيانات المقدَّمة من المستخدم وتجزئتها قبل استيرادها للحصول على التعليمات، يُرجى الاطّلاع على مقالة تسوية البيانات المقدَّمة من المستخدِم وتجزئتها.
CONVERSION_NOT_FOUND

تعذّر على "إعلانات Google" العثور على إحالة ناجحة تتطابق مع الحقل conversion_action ومعرّف الإحالة الناجحة (order_id أو gclid_date_time_pair). ينطبق هذا الخطأ فقط على تعديلات RESTATEMENT وRETRACTION. لمعرفة التفاصيل، يُرجى الاطّلاع على متطلبات استيراد تعديلات قيم الإحالات الناجحة.

بالنسبة إلى تعديلات ENHANCEMENT، تقبل واجهة برمجة التطبيقات الطلب بدون عرض خطأ CONVERSION_NOT_FOUND وتُقيّم مطابقة order_id من العلامة إلى واجهة برمجة التطبيقات بشكل غير متزامن. تؤدي المعدلات المرتفعة لقيم order_id غير المتطابقة إلى ظهور تنبيه بعدم تطابق مُعرّف الطلب في تقرير تشخيصي للإحالات الناجحة المحسّنة في واجهة مستخدم "إعلانات Google". للاطّلاع على خطوات تحديد المشاكل وحلّها، يُرجى مراجعة تنبيهات بيانات التشخيص في واجهة المستخدم بعد التحميل بنجاح من خلال واجهة برمجة التطبيقات.