Как управлять офлайн-конверсиями

С помощью Google Ads API можно импортировать офлайн-конверсии в Google Рекламу, чтобы отслеживать объявления, которые привели к продажам вне интернета, например по телефону или через представителя отдела продаж.

Чтобы в полной мере воспользоваться преимуществами импорта данных о конверсиях, рекомендуем настроить расширенное отслеживание конверсий потенциальных клиентов, которое использует GCLID и данные, предоставленные пользователями, для повышения надежности и эффективности.

Расширенное отслеживание конверсий

Расширенное отслеживание конверсий позволяет повысить точность собираемых данных благодаря передаче собственных данных о конверсиях, таких как адрес электронной почты, номер телефона и почтовый адрес.

Существует два типа расширенного отслеживания конверсий. Подробнее о расширенном отслеживании конверсий…

В этом разделе рассказывается, как улучшить офлайн-конверсии (эта функция также называется расширенным отслеживанием конверсий лидов).

Что такое расширенное отслеживание конверсий лидов?

Расширенное отслеживание конверсий потенциальных клиентов – это улучшенная версия импорта офлайн-конверсий, которая обеспечивает более точный их учет и повышает эффективность назначения ставок за счет дополнительных данных (например, адресов электронной почты), предоставленных пользователями. При импорте офлайн-конверсий предоставленные хешированные данные клиентов сопоставляются с информацией, собранной на вашем сайте (например, через форму для потенциальных клиентов), и сведениями о вошедших в аккаунт клиентах, которые взаимодействовали с вашим объявлением. Это позволяет связывать конверсии с определенной кампанией Google Рекламы. Подробнее о расширенном отслеживании конверсий лидов…

Реализовать расширенное отслеживание конверсий лидов можно двумя способами в зависимости от того, используете ли вы тег Google для отслеживания событий отправки формы на веб-странице. Для наилучшей производительности и долговечности мы рекомендуем использовать тег Google для расширенного отслеживания конверсий лидов.

Требования

Сначала убедитесь, что вы выполнили все действия, описанные в разделе Начало работы.

Чтобы использовать расширенное отслеживание конверсий лидов, необходимо включить эту функцию и принять условия использования данных клиентов. Чтобы проверить, выполнены ли эти условия, отправьте следующий запрос клиенту Google Рекламы, у которого настроено отслеживание конверсий:

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

Если accepted_customer_data_terms – false или если enablement_setting (или effective_enablement_setting при использовании отслеживания конверсий в управляющем аккаунте) не ON, выполните инструкции из статьи Как создать действие-конверсию.

Настройка тегов

Чтобы включить расширенное отслеживание конверсий лидов, настройте тег Google, следуя инструкциям. Чтобы настроить расширенное отслеживание конверсий лидов с помощью Google Менеджера тегов, следуйте этим инструкциям.

Реализация API

Ниже описан общий процесс импорта данных расширенного отслеживания конверсий лидов с помощью Google Ads API.

  1. Нормализуйте и хешируйте данные, предоставленные пользователями, например адрес электронной почты, номер телефона и почтовый адрес.

  2. Заполните объекты ClickConversion нормализованными и хешированными данными, предоставленными пользователями.

  3. Импортируйте объекты ClickConversion в Google Ads API с помощью ConversionUploadService. Подробнее: UploadClickConversions.

  4. Проверьте импортированные данные.

Сводные данные о схемах Request и ClickConversion

В таблице ниже перечислены основные поля UploadClickConversionsRequest и ClickConversion для расширенного отслеживания конверсий потенциальных клиентов. Полную информацию о полях можно найти в разделах Заполнение объектов ClickConversion и Создание запроса.

Путь к полю Требования Формат и ограничения
customer_id Обязательно Укажите идентификатор клиента конверсии Google Рекламы (google_ads_conversion_customer в customer.conversion_tracking_setting) без дефисов.
partial_failure Обязательно Необходимо задать значение true, чтобы импортировались действительные конверсии, а ошибки на уровне строк возвращались в partial_failure_error.
validate_only Необязательно Если задано значение true, запрос проверяется без импорта конверсий (возвращаются все ошибки проверки в partial_failure_error).
job_id Необязательно Неотрицательное значение int32 (от 0 до 2^31 - 1), позволяющее сгруппировать несколько запросов в одно логическое задание в job_summaries.
conversions[].conversion_action Обязательно Название ресурса (customers/{conversion_customer_id}/conversionActions/{action_id}) действия-конверсии ENABLED с type = UPLOAD_CLICKS.
conversions[].conversion_date_time Обязательно Время конверсии должно быть позже времени клика и включать часовой пояс: yyyy-mm-dd hh:mm:ss+|-hh:mm (например, 2026-06-01 14:30:00-04:00).
conversions[].conversion_value и currency_code Рекомендуется Числовое значение ценности конверсии (double) и трехзначный код валюты по стандарту ISO 4217 (например, USD).
conversions[].order_id Рекомендуется Уникальный идентификатор транзакции для каждого действия-конверсии, чтобы предотвратить дублирование импорта и поддерживать будущие корректировки.
conversions[].gclid/gbraid/wbraid Рекомендуется, если доступно Идентификатор клика, полученный из URL целевой страницы. Добавляйте его вместе с атрибутом user_identifiers, когда это возможно.
conversions[].user_identifiers[] Требуется для расширенного отслеживания конверсий лидов От одного до пяти объектов UserIdentifier на конверсию. Задайте необязательные параметры user_identifier_source (например, FIRST_PARTY) и hashed_email (обрезанный, в нижнем регистре, точки и суффиксы + перед @ удалены для gmail.com и googlemail.com, шестнадцатеричное значение SHA-256) или hashed_phone_number (формат E.164, шестнадцатеричное значение SHA-256); подробнее о том, как нормализовать и хешировать данные… address_info не поддерживается.
conversions[].consent.ad_user_data Рекомендуется Задайте значение GRANTED или DENIED в Consent. (ad_personalization поддерживается только в OfflineUserDataJobService и UserDataService).
conversions[].custom_variables и external_attribution_data Не устанавливать с помощью user_identifiers Конверсии, содержащие user_identifiers, не должны задавать custom_variables или external_attribution_data, иначе они будут отклонены.

Как получить название ресурса действия-конверсии

Чтобы загрузить конверсии, необходимо указать название ресурса ConversionAction, которое вы задали в Google Рекламе для импорта конверсий по кликам. Чтобы найти название ресурса, отправьте запрос к ресурсу conversion_action, используя следующий запрос GAQL:

SELECT
  customer.id,
  conversion_action.id,
  conversion_action.name,
  conversion_action.type,
  conversion_action.resource_name
FROM conversion_action
WHERE conversion_action.type = 'UPLOAD_CLICKS'
  AND conversion_action.status = 'ENABLED'

Нормализация и хеширование данных, предоставленных пользователями

Для защиты конфиденциальности пользователей следующие данные будут хешированы по алгоритму SHA-256 перед импортом:

  • Адрес электронной почты
  • номер телефона;
  • имя;
  • фамилия;
  • почтовый адрес.

Не хешируйте следующие данные:

  • страна;
  • штат;
  • город;
  • Почтовый индекс

Чтобы стандартизировать результаты работы функции хеширования, перед ее запуском выполните следующие действия:

  • Удалите начальные и конечные пробельные символы.
  • Конвертируйте текст в нижний регистр.
  • Отформатируйте номера телефонов по стандарту 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()

Пример кода

В этом примере показано, как нормализовать и хешировать данные, предоставленные пользователями.

Java

private String normalizeAndHash(MessageDigest digest, String s)
    throws UnsupportedEncodingException {
  // Normalizes by first converting all characters to lowercase, then trimming spaces.
  String normalized = s.toLowerCase();
  // Removes leading, trailing, and intermediate spaces.
  normalized = normalized.replaceAll("\\s+", "");
  // 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);
}

/**
 * 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);
}
      

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): string
{
    // Normalizes by first converting all characters to lowercase, then trimming spaces.
    $normalized = strtolower($value);
    // Removes leading, trailing, and intermediate spaces.
    $normalized = str_replace(' ', '', $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);
}
      

Python

def normalize_and_hash_email_address(email_address: str) -> str:
    """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: str = email_address.strip().lower()
    email_parts: list[str] = 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: str) -> str:
    """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 hashing.
  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;

  # Removes leading, trailing, and intermediate spaces.
  $value =~ 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);
}
      

curl

Заполнение объектов ClickConversion

Набор объектов ClickConversion в вашем файле UploadClickConversionsRequest представляет собой набор конверсий, которые вы хотите импортировать. При создании объектов ClickConversion учитывайте следующее:

gclid

GCLID – это идентификаторы, которые извлекаются из параметров URL, когда пользователь нажимает на объявление и переходит на ваш сайт.

gbraid

gbraid – это параметр URL, который присутствует, когда пользователь нажимает на объявление в интернете и переходит в ваше приложение для iOS.

wbraid

wbraid – это параметр URL, который появляется, когда пользователь нажимает на объявление в приложении для iOS и переходит на вашу веб-страницу.

cart_data

Сведения о конверсии на уровне товара. Заполните поле cart_data, чтобы получать данные корзины, например сведения о купленных товарах, их цене и количестве, в интерфейсе Google Рекламы. Определение объекта CartData, в котором указана необходимая структура, и другие сведения вы найдете в статье Отслеживание конверсий по данным корзины.

user_identifiers

Если вы используете расширенное отслеживание конверсий потенциальных клиентов, то должны заполнить поле user_identifiers нормализованными и хешированными данными, предоставленными пользователями. Если у вас есть несколько идентификаторов пользователей, создайте для каждого из них отдельный объект UserIdentifier (не более пяти).

conversion_date_time

Дата и время конверсии.

Значение должно содержать часовой пояс и иметь формат yyyy-mm-dd HH:mm:ss+|-HH:mm, например 2022-01-01 19:32:45-05:00 (без учета летнего времени).

Часовой пояс может быть любым допустимым значением, он не обязательно должен совпадать с часовым поясом аккаунта. Однако если вы планируете сравнивать импортированные данные о конверсиях с данными в интерфейсе Google Рекламы, рекомендуем использовать тот же часовой пояс, что и в аккаунте Google Рекламы, чтобы количество конверсий совпадало. Подробную информацию и примеры вы найдете в статье Как подготовить данные для импорта. Список допустимых идентификаторов часовых поясов приведен в статье Коды и форматы.

conversion_action

Название ресурса ConversionAction для офлайн-конверсии.

У действия-конверсии должен быть type UPLOAD_CLICKS, и оно должно существовать в аккаунте Google Рекламы, связанном с кликом.

conversion_value

Ценность конверсии.

currency_code

Код валюты для conversion_value.

consent

Настоятельно рекомендуем заполнять поле consent объекта ClickConversion. Если не задать этот параметр, конверсии могут не регистрироваться.

order_id

Также называется идентификатором транзакции для конверсии. Это поле не является обязательным, но мы настоятельно рекомендуем его заполнить, поскольку оно упрощает корректировку импортированных конверсий. Если значение задано во время импорта, то нужно использовать его для любых корректировок. Подробнее о том, как избежать повторной регистрации конверсий с помощью идентификатора транзакции…

custom_variables

Значения пользовательских переменных конверсий. Google Реклама не поддерживает пользовательские переменные конверсий в сочетании с wbraid или gbraid.

conversion_environment

Указывает среду, в которой была зарегистрирована конверсия. Примеры: APP или WEB.

session_attributes_encoded и session_attributes_key_value_pairs

Атрибуты сеанса – это агрегированные идентификаторы, используемые для атрибуции конверсий. Они работают в дополнение к GCLID, параметрам URL (например, GBRAID) и данным, предоставленным пользователями, которые являются основой расширенного отслеживания конверсий потенциальных клиентов. Импортировать атрибуты сеанса можно двумя способами: предоставить закодированный токен, созданный нашим кодом JavaScript в браузере, или указать отдельные пары "ключ-значение" для каждого идентификатора.

Чтобы максимально повысить эффективность кампании, рекомендуем по возможности импортировать идентификаторы кликов, предоставленные пользователями данные и атрибуты сеансов вместе со всеми конверсиями.

Java

// Sets one of the sessionAttributesEncoded or sessionAttributesKeyValuePairs if either is
// provided. The session attribute fields are only available to allowlisted users.
// To include these fields in conversion imports, upgrade to the Data Manager API.
if (rawRecord.containsKey("sessionAttributesEncoded")) {
  clickConversionBuilder.setSessionAttributesEncoded(
      ByteString.copyFromUtf8(rawRecord.get("sessionAttributesEncoded")));
} else if (rawRecord.containsKey("sessionAttributesMap")) {
  List<String> pairings =
      Arrays.stream(rawRecord.get("sessionAttributesMap").split(" "))
          .map(String::trim)
          .collect(Collectors.toList());
  SessionAttributesKeyValuePairs.Builder sessionAttributePairs =
      SessionAttributesKeyValuePairs.newBuilder();
  for (String pair : pairings) {
    String[] parts = pair.split("=", 2);
    if (parts.length != 2) {
      throw new IllegalArgumentException(
          "Failed to read the sessionAttributesMap. SessionAttributesMap must use a"
              + " space-delimited list of session attribute key value pairs. Each pair should"
              + " be separated by an equal sign, for example: 'gad_campaignid=12345"
              + " gad_source=1'");
    }
    sessionAttributePairs.addKeyValuePairs(
        SessionAttributeKeyValuePair.newBuilder()
            .setSessionAttributeKey(parts[0])
            .setSessionAttributeValue(parts[1])
            .build());
  }
  clickConversionBuilder.setSessionAttributesKeyValuePairs(sessionAttributePairs.build());
}
      

C#

// The session attribute fields are only available to allowlisted users. To
// include these fields in conversion imports, upgrade to the Data Manager API.
if (!string.IsNullOrEmpty(sessionAttributesEncoded))
{
    clickConversion.SessionAttributesEncoded =
        ByteString.CopyFrom(sessionAttributesEncoded, Encoding.Unicode);
}
else if (!string.IsNullOrEmpty(sessionAttributes))
{
    IEnumerable<SessionAttributeKeyValuePair> parsedSessionAttributes =
        sessionAttributes.Split(';').Select(pair => {
            string[] split = pair.Split('=');
            return new SessionAttributeKeyValuePair()
            {
                SessionAttributeKey = split[0],
                SessionAttributeValue = split[1]
            };
        });

    clickConversion.SessionAttributesKeyValuePairs =
        new SessionAttributesKeyValuePairs();
    clickConversion.SessionAttributesKeyValuePairs.KeyValuePairs
        .AddRange(parsedSessionAttributes);
}
      

PHP

This example is not yet available in PHP; you can take a look at the other languages.
    

Python

# Set one of the session_attributes_encoded or
# session_attributes_key_value_pairs fields if either are provided.
# The session attribute fields are only available to allowlisted users.
# To include these fields in conversion imports, upgrade to the Data Manager API.
if session_attributes_encoded:
    click_conversion.session_attributes_encoded = session_attributes_encoded
elif session_attributes_dict:
    for key, value in session_attributes_dict.items():
        pair: SessionAttributeKeyValuePair = client.get_type(
            "SessionAttributeKeyValuePair"
        )
        pair.session_attribute_key = key
        pair.session_attribute_value = value
        click_conversion.session_attributes_key_value_pairs.key_value_pairs.append(
            pair
        )
      

Ruby

# Set one of the session_attributes_encoded or
# session_attributes_key_value_pairs fields if either are provided.
# The session attribute fields are only available to allowlisted users.
# To include these fields in conversion imports, upgrade to the Data Manager API.
if session_attributes_encoded != nil
  cc.class.module_eval { attr_accessor :session_attributes_encoded}
  cc.session_attributes_encoded = session_attributes_encoded
elsif session_attributes_hash != nil
  # Add new attribute to click conversion object
  cc.class.module_eval { attr_accessor :session_attributes_key_value_pairs}
  cc.session_attributes_key_value_pairs = ::Google::Ads::GoogleAds::V19::Services::SessionAttributesKeyValuePairs.new

  # Loop thru inputted session_attributes_hash to populate session_attributes_key_value_pairs
  session_attributes_hash.each do |key, value|
    pair = ::Google::Ads::GoogleAds::V19::Services::SessionAttributeKeyValuePair.new
    pair.session_attribute_key = key
    pair.session_attribute_value = value
    cc.session_attributes_key_value_pairs.key_value_pairs << pair
  end
end    
      

Perl

# Set one of the session_attributes_encoded or session_attributes_key_value_pairs
# fields if either are provided.
if (defined $session_attributes_encoded) {
  $click_conversion->{sessionAttributesEncoded} = $session_attributes_encoded;
} elsif (defined $session_attributes_hash) {
  while (my ($key, $value) = each %$session_attributes_hash) {
    my $pair =
      Google::Ads::GoogleAds::V26::Services::ConversionUploadService::SessionAttributeKeyValuePair
      ->new({sessionAttributeKey => $key, sessionAttributeValue => $value});
    push @{$click_conversion->{sessionAttributesKeyValuePairs}{keyValuePairs}
    }, $pair;
  }
}
      

curl

user_ip_address

IP-адрес клиента, когда он перешел на целевую страницу после клика по объявлению и до события-конверсии. Это IP-адрес устройства клиента, а не сервера рекламодателя.

Это поле представляет собой строку, содержащую IP-адрес в формате IPv4 или IPv6. Пример:

  • IPv4: "192.0.2.0"
  • IPv6: "2001:0DB8:1234:5678:9999:1111:0000:0001"

Пример кода

В этом примере показано, как добавить нормализованные и хешированные данные, предоставленные пользователями, в объект ClickConversion.

Java

// Creates an empty builder for constructing the click conversion.
ClickConversion.Builder clickConversionBuilder = ClickConversion.newBuilder();

// Extracts user email and phone 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()
        .put("email", "alex.2+myalias@gmail.com")
        // 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("conversionActionId", Long.toString(conversionActionId))
        .put("conversionDateTime", conversionDateTime)
        .put("conversionValue", Double.toString(conversionValue))
        .put("currencyCode", "USD");

// Adds entries for the optional fields.
if (orderId != null) {
  rawRecordBuilder.put("orderId", orderId);
}
if (gclid != null) {
  rawRecordBuilder.put("gclid", gclid);
}
if (adUserDataConsent != null) {
  rawRecordBuilder.put("adUserDataConsent", adUserDataConsent.name());
}
if (sessionAttributesEncoded != null) {
  rawRecordBuilder.put("sessionAttributesEncoded", sessionAttributesEncoded);
}
if (sessionAttributesMap != null) {
  rawRecordBuilder.put("sessionAttributesMap", sessionAttributesMap);
}

// 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);

// Creates a user identifier using normalized and hashed phone info.
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);

// Adds the user identifiers to the conversion.
clickConversionBuilder.addAllUserIdentifiers(userIdentifiers);
      

C#

// Adds a user identifier using the hashed email address, using the normalize
// and hash method specifically for email addresses.
clickConversion.UserIdentifiers.Add(new UserIdentifier()
{
    HashedEmail = NormalizeAndHashEmailAddress("alex.2@example.com"),
    // Optional: Specifies the user identifier source.
    UserIdentifierSource = UserIdentifierSource.FirstParty
});

// Adds a user identifier using normalized and hashed phone info.
clickConversion.UserIdentifiers.Add(new UserIdentifier()
{
    HashedPhoneNumber = NormalizeAndHash("+1 800 5550102"),
    // Optional: Specifies the user identifier source.
    UserIdentifierSource = UserIdentifierSource.FirstParty
});

// Adds a user identifier with all the required mailing address elements.
clickConversion.UserIdentifiers.Add(new UserIdentifier()
{
    AddressInfo = new OfflineUserAddressInfo()
    {
        // FirstName and LastName must be normalized and hashed.
        HashedFirstName = NormalizeAndHash("Alex"),
        HashedLastName = NormalizeAndHash("Quinn"),
        // CountryCode and PostalCode are sent in plain text.
        CountryCode = "US",
        PostalCode = "94045"
    }
});
      

PHP

// Creates a click conversion with the specified attributes.
$clickConversion = new ClickConversion();

// Extract user email and phone from the raw data, normalize and hash it, then wrap 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',
    // 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,
    'gclid' => $gclid,
    'conversionActionId' => $conversionActionId,
    'conversionDateTime' => $conversionDateTime,
    'conversionValue' => $conversionValue,
    'currencyCode' => 'USD',
    'adUserDataConsent' => $adUserDataConsent,
    'sessionAttributesEncoded' => $sessionAttributesEncoded,
    'sessionAttributesDict' => $sessionAttributesDict
];

// 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;
}

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

Python

# Extract user email and phone 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:
#
# incorrectly_populated_user_identifier = client.get_type("UserIdentifier")
# incorrectly_populated_user_identifier.hashed_email = "...""
# incorrectly_populated_user_identifier.hashed_phone_number = "...""

raw_record: Dict[str, Union[str, float]] = {
    # Email address that includes a period (.) before the Gmail domain.
    "email": "alex.2@example.com",
    # 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,
    "gclid": gclid,
    "conversion_action_id": conversion_action_id,
    "conversion_date_time": conversion_date_time,
    "conversion_value": conversion_value,
    "currency_code": "USD",
    "ad_user_data_consent": ad_user_data_consent,
}

# Constructs the click conversion.
click_conversion: ClickConversion = client.get_type("ClickConversion")
# Creates a user identifier using the hashed email address, using the
# normalize and hash method specifically for email addresses.
email_identifier: UserIdentifier = 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 user identifier to the conversion.
click_conversion.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: UserIdentifier = client.get_type("UserIdentifier")
    phone_identifier.hashed_phone_number = normalize_and_hash(
        raw_record["phone"]
    )
    # Adds the phone identifier to the conversion adjustment.
    click_conversion.user_identifiers.append(phone_identifier)
      

Ruby

# Extract user email and phone 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:
#
# 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",
  # 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,
  "gclid" => gclid,
  "conversion_action_id" => conversion_action_id,
  "conversion_date_time" => conversion_date_time,
  "conversion_value" => conversion_value,
  "currency_code" => "USD",
  "ad_user_data_consent" => ad_user_data_consent,
  "session_attributes_encoded" => session_attributes_encoded,
  "session_attributes_hash" => session_attributes_hash
}

click_conversion = client.resource.click_conversion do |cc|
  cc.conversion_action = client.path.conversion_action(customer_id, conversion_action_id)
  cc.conversion_date_time = conversion_date_time
  cc.conversion_value = conversion_value.to_f
  cc.currency_code = 'USD'

  unless order_id.nil?
    cc.order_id = order_id
  end

  unless raw_record["gclid"].nil?
    cc.gclid = gclid
  end

  # Specifies whether user consent was obtained for the data you are
  # uploading. For more details, see:
  # https://www.google.com/about/company/user-consent-policy
  unless raw_record["ad_user_data_consent"].nil?
    cc.consent = client.resource.consent do |c|
      c.ad_user_data = ad_user_data_consent
    end
  end

  # Set one of the session_attributes_encoded or
  # session_attributes_key_value_pairs fields if either are provided.
  # The session attribute fields are only available to allowlisted users.
  # To include these fields in conversion imports, upgrade to the Data Manager API.
  if session_attributes_encoded != nil
    cc.class.module_eval { attr_accessor :session_attributes_encoded}
    cc.session_attributes_encoded = session_attributes_encoded
  elsif session_attributes_hash != nil
    # Add new attribute to click conversion object
    cc.class.module_eval { attr_accessor :session_attributes_key_value_pairs}
    cc.session_attributes_key_value_pairs = ::Google::Ads::GoogleAds::V19::Services::SessionAttributesKeyValuePairs.new

    # Loop thru inputted session_attributes_hash to populate session_attributes_key_value_pairs
    session_attributes_hash.each do |key, value|
      pair = ::Google::Ads::GoogleAds::V19::Services::SessionAttributeKeyValuePair.new
      pair.session_attribute_key = key
      pair.session_attribute_value = value
      cc.session_attributes_key_value_pairs.key_value_pairs << pair
    end
  end    

  # Creates a user identifier using the hashed email address, using the
  # normalize and hash method specifically for email addresses.
  # If using a phone number, use the normalize_and_hash method instead.
  cc.user_identifiers << client.resource.user_identifier do |ui|
    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?
    cc.user_identifiers << client.resource.user_identifier do |ui|
      ui.hashed_phone_number = normalize_and_hash(raw_record["phone"])
    end
  end
end
      

Perl

# Create an empty click conversion.
my $click_conversion =
  Google::Ads::GoogleAds::V26::Services::ConversionUploadService::ClickConversion
  ->new({});

# Extract user email and phone 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',
  # 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,
  gclid              => $gclid,
  conversionActionId => $conversion_action_id,
  conversionDateTime => $conversion_date_time,
  conversionValue    => $conversion_value,
  currencyCode       => "USD",
  adUserDataConsent  => $ad_user_data_consent
};
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
    }));

# Create a user identifier using normalized and hashed phone info.
my $hashed_phone = normalize_and_hash($raw_record->{phone});
push(
  @$user_identifiers,
  Google::Ads::GoogleAds::V26::Common::UserIdentifier->new({
      hashedPhone => $hashed_phone,
      # Optional: Specify the user identifier source.
      userIdentifierSource => FIRST_PARTY
    }));

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

curl

В этом примере показано, как задать другие необходимые поля объекта ClickConversion.

Java

// Adds details of the conversion.
clickConversionBuilder.setConversionAction(
    ResourceNames.conversionAction(
        customerId, Long.parseLong(rawRecord.get("conversionActionId"))));
clickConversionBuilder.setConversionDateTime(rawRecord.get("conversionDateTime"));
clickConversionBuilder.setConversionValue(Double.parseDouble(rawRecord.get("conversionValue")));
clickConversionBuilder.setCurrencyCode(rawRecord.get("currencyCode"));

// Sets the order ID if provided.
if (rawRecord.containsKey("orderId")) {
  clickConversionBuilder.setOrderId(rawRecord.get("orderId"));
}

// Sets the Google click ID (gclid) if provided.
if (rawRecord.containsKey("gclid")) {
  clickConversionBuilder.setGclid(rawRecord.get("gclid"));
}

// Sets the consent information, if provided.
if (rawRecord.containsKey("adUserDataConsent")) {
  // Specifies whether user consent was obtained for the data you are uploading. See
  // https://www.google.com/about/company/user-consent-policy for details.
  clickConversionBuilder.setConsent(
      Consent.newBuilder()
          .setAdUserData(ConsentStatus.valueOf(rawRecord.get("adUserDataConsent"))));
}

// Sets one of the sessionAttributesEncoded or sessionAttributesKeyValuePairs if either is
// provided. The session attribute fields are only available to allowlisted users.
// To include these fields in conversion imports, upgrade to the Data Manager API.
if (rawRecord.containsKey("sessionAttributesEncoded")) {
  clickConversionBuilder.setSessionAttributesEncoded(
      ByteString.copyFromUtf8(rawRecord.get("sessionAttributesEncoded")));
} else if (rawRecord.containsKey("sessionAttributesMap")) {
  List<String> pairings =
      Arrays.stream(rawRecord.get("sessionAttributesMap").split(" "))
          .map(String::trim)
          .collect(Collectors.toList());
  SessionAttributesKeyValuePairs.Builder sessionAttributePairs =
      SessionAttributesKeyValuePairs.newBuilder();
  for (String pair : pairings) {
    String[] parts = pair.split("=", 2);
    if (parts.length != 2) {
      throw new IllegalArgumentException(
          "Failed to read the sessionAttributesMap. SessionAttributesMap must use a"
              + " space-delimited list of session attribute key value pairs. Each pair should"
              + " be separated by an equal sign, for example: 'gad_campaignid=12345"
              + " gad_source=1'");
    }
    sessionAttributePairs.addKeyValuePairs(
        SessionAttributeKeyValuePair.newBuilder()
            .setSessionAttributeKey(parts[0])
            .setSessionAttributeValue(parts[1])
            .build());
  }
  clickConversionBuilder.setSessionAttributesKeyValuePairs(sessionAttributePairs.build());
}

// Calls build to build the conversion.
ClickConversion clickConversion = clickConversionBuilder.build();
      

C#

// Adds details of the conversion.
clickConversion.ConversionAction =
    ResourceNames.ConversionAction(customerId, conversionActionId);
clickConversion.ConversionDateTime = conversionDateTime;
clickConversion.ConversionValue = conversionValue;
clickConversion.CurrencyCode = "USD";

// Sets the order ID if provided.
if (!string.IsNullOrEmpty(orderId))
{
    clickConversion.OrderId = orderId;
}

// Sets the Google click ID (gclid) if provided.
if (!string.IsNullOrEmpty(gclid))
{
    clickConversion.Gclid = gclid;
}

// The session attribute fields are only available to allowlisted users. To
// include these fields in conversion imports, upgrade to the Data Manager API.
if (!string.IsNullOrEmpty(sessionAttributesEncoded))
{
    clickConversion.SessionAttributesEncoded =
        ByteString.CopyFrom(sessionAttributesEncoded, Encoding.Unicode);
}
else if (!string.IsNullOrEmpty(sessionAttributes))
{
    IEnumerable<SessionAttributeKeyValuePair> parsedSessionAttributes =
        sessionAttributes.Split(';').Select(pair => {
            string[] split = pair.Split('=');
            return new SessionAttributeKeyValuePair()
            {
                SessionAttributeKey = split[0],
                SessionAttributeValue = split[1]
            };
        });

    clickConversion.SessionAttributesKeyValuePairs =
        new SessionAttributesKeyValuePairs();
    clickConversion.SessionAttributesKeyValuePairs.KeyValuePairs
        .AddRange(parsedSessionAttributes);
}

      

PHP

// Adds details of the conversion.
$clickConversion->setConversionAction(
    ResourceNames::forConversionAction($customerId, $rawRecord['conversionActionId'])
);
$clickConversion->setConversionDateTime($rawRecord['conversionDateTime']);
$clickConversion->setConversionValue($rawRecord['conversionValue']);
$clickConversion->setCurrencyCode($rawRecord['currencyCode']);

// Sets the order ID if provided.
if (!empty($rawRecord['orderId'])) {
    $clickConversion->setOrderId($rawRecord['orderId']);
}

// Sets the Google click ID (gclid) if provided.
if (!empty($rawRecord['gclid'])) {
    $clickConversion->setGclid($rawRecord['gclid']);
}

// Sets the ad user data consent if provided.
if (!empty($rawRecord['adUserDataConsent'])) {
    // Specifies whether user consent was obtained for the data you are uploading. See
    // https://www.google.com/about/company/user-consent-policy for details.
    $clickConversion->setConsent(
        new Consent(['ad_user_data' => $rawRecord['adUserDataConsent']])
    );
}

// Set one of the sessionAttributesEncoded or
// SessionAttributeKeyValuePair fields if either are provided. The session attribute
// fields are only available to allowlisted users. To include these fields in conversion
// imports, upgrade to the Data Manager API.
if (!empty($sessionAttributesEncoded)) {
    $clickConversion->setSessionAttributesEncoded($sessionAttributesEncoded);
} elseif (!empty($sessionAttributesDict)) {
    // Create a new container object to hold key-value pairs.
    $sessionAttributesKeyValuePairs = new SessionAttributesKeyValuePairs();
    // Initialize an array to hold individual key-value pair messages.
    $keyValuePairs = [];
    // Append each key-value pair provided to the $keyValuePairs array
    foreach ($sessionAttributesDict as $key => $value) {
        $pair = new SessionAttributeKeyValuePair();
        $pair->setSessionAttributeKey($key);
        $pair->setSessionAttributeValue($value);
        $keyValuePairs[] = $pair;
    }
    // Set the the full list of key-value pairs on the container object.
    $sessionAttributesKeyValuePairs->setKeyValuePairs($keyValuePairs);
    // Attach the container of key-value pairs to the ClickConversion object.
    $clickConversion->setSessionAttributesKeyValuePairs($sessionAttributesKeyValuePairs);
}
      

Python

# Add details of the conversion.
# Gets the conversion action resource name.
conversion_action_service: ConversionActionServiceClient = (
    client.get_service("ConversionActionService")
)
click_conversion.conversion_action = (
    conversion_action_service.conversion_action_path(
        customer_id, raw_record["conversion_action_id"]
    )
)
click_conversion.conversion_date_time = raw_record["conversion_date_time"]
click_conversion.conversion_value = raw_record["conversion_value"]
click_conversion.currency_code = raw_record["currency_code"]

# Sets the order ID if provided.
if raw_record.get("order_id"):
    click_conversion.order_id = raw_record["order_id"]

# Sets the gclid if provided.
if raw_record.get("gclid"):
    click_conversion.gclid = raw_record["gclid"]

# Specifies whether user consent was obtained for the data you are
# uploading. For more details, see:
# https://www.google.com/about/company/user-consent-policy
if raw_record["ad_user_data_consent"]:
    click_conversion.consent.ad_user_data = client.enums.ConsentStatusEnum[
        raw_record["ad_user_data_consent"]
    ]

# Set one of the session_attributes_encoded or
# session_attributes_key_value_pairs fields if either are provided.
# The session attribute fields are only available to allowlisted users.
# To include these fields in conversion imports, upgrade to the Data Manager API.
if session_attributes_encoded:
    click_conversion.session_attributes_encoded = session_attributes_encoded
elif session_attributes_dict:
    for key, value in session_attributes_dict.items():
        pair: SessionAttributeKeyValuePair = client.get_type(
            "SessionAttributeKeyValuePair"
        )
        pair.session_attribute_key = key
        pair.session_attribute_value = value
        click_conversion.session_attributes_key_value_pairs.key_value_pairs.append(
            pair
        )
      

Ruby

cc.conversion_action = client.path.conversion_action(customer_id, conversion_action_id)
cc.conversion_date_time = conversion_date_time
cc.conversion_value = conversion_value.to_f
cc.currency_code = 'USD'

unless order_id.nil?
  cc.order_id = order_id
end

unless raw_record["gclid"].nil?
  cc.gclid = gclid
end

# Specifies whether user consent was obtained for the data you are
# uploading. For more details, see:
# https://www.google.com/about/company/user-consent-policy
unless raw_record["ad_user_data_consent"].nil?
  cc.consent = client.resource.consent do |c|
    c.ad_user_data = ad_user_data_consent
  end
end

# Set one of the session_attributes_encoded or
# session_attributes_key_value_pairs fields if either are provided.
# The session attribute fields are only available to allowlisted users.
# To include these fields in conversion imports, upgrade to the Data Manager API.
if session_attributes_encoded != nil
  cc.class.module_eval { attr_accessor :session_attributes_encoded}
  cc.session_attributes_encoded = session_attributes_encoded
elsif session_attributes_hash != nil
  # Add new attribute to click conversion object
  cc.class.module_eval { attr_accessor :session_attributes_key_value_pairs}
  cc.session_attributes_key_value_pairs = ::Google::Ads::GoogleAds::V19::Services::SessionAttributesKeyValuePairs.new

  # Loop thru inputted session_attributes_hash to populate session_attributes_key_value_pairs
  session_attributes_hash.each do |key, value|
    pair = ::Google::Ads::GoogleAds::V19::Services::SessionAttributeKeyValuePair.new
    pair.session_attribute_key = key
    pair.session_attribute_value = value
    cc.session_attributes_key_value_pairs.key_value_pairs << pair
  end
end    
      

Perl

# Add details of the conversion.
$click_conversion->{conversionAction} =
  Google::Ads::GoogleAds::V26::Utils::ResourceNames::conversion_action(
  $customer_id, $raw_record->{conversionActionId});
$click_conversion->{conversionDateTime} = $raw_record->{conversionDateTime};
$click_conversion->{conversionValue}    = $raw_record->{conversionValue};
$click_conversion->{currencyCode}       = $raw_record->{currencyCode};

# Set the order ID if provided.
if (defined $raw_record->{orderId}) {
  $click_conversion->{orderId} = $raw_record->{orderId};
}

# Set the Google click ID (gclid) if provided.
if (defined $raw_record->{gclid}) {
  $click_conversion->{gclid} = $raw_record->{gclid};
}

# Set the consent information, if provided.
if (defined $raw_record->{adUserDataConsent}) {
  $click_conversion->{consent} =
    Google::Ads::GoogleAds::V26::Common::Consent->new({
      adUserData => $raw_record->{adUserDataConsent}});
}

# Set one of the session_attributes_encoded or session_attributes_key_value_pairs
# fields if either are provided.
if (defined $session_attributes_encoded) {
  $click_conversion->{sessionAttributesEncoded} = $session_attributes_encoded;
} elsif (defined $session_attributes_hash) {
  while (my ($key, $value) = each %$session_attributes_hash) {
    my $pair =
      Google::Ads::GoogleAds::V26::Services::ConversionUploadService::SessionAttributeKeyValuePair
      ->new({sessionAttributeKey => $key, sessionAttributeValue => $value});
    push @{$click_conversion->{sessionAttributesKeyValuePairs}{keyValuePairs}
    }, $pair;
  }
}
      

curl

Как создать запрос

После того как вы настроите объекты ClickConversion и добавите их в поле conversions объекта UploadClickConversionsRequest, задайте значения следующих полей и передайте запрос методу UploadClickConversions в ConversionUploadService.

customer_id
Укажите клиента конверсий Google Рекламы для аккаунта, который является источником кликов. Если вы не знаете, какой аккаунт выбрать, посмотрите на поле customer.conversion_tracking_setting.google_ads_conversion_customer в примере запроса в разделе Начало работы.
job_id

Позволяет связывать запросы на импорт с информацией о заданиях в диагностике офлайн-данных.

Если вы не зададите это поле, Google Ads API присвоит каждому запросу уникальное значение в диапазоне [2^31, 2^63). Если вы хотите объединить несколько запросов в одну логическую задачу, задайте для этого поля одинаковое значение в диапазоне [0, 2^31) для каждого запроса в задаче.

Объект job_id в response содержит идентификатор задания для запроса независимо от того, указали ли вы значение или позволили Google Ads API назначить его.

partial_failure

При импорте конверсий в этом поле должно быть указано значение true. При обработке ответа следуйте рекомендациям по частичным сбоям.

Импортируйте запрос

Заполнив объекты ClickConversion и создав запрос, вы можете отправить импорт.

Java

// Creates the conversion upload service client.
try (ConversionUploadServiceClient conversionUploadServiceClient =
    googleAdsClient.getLatestVersion().createConversionUploadServiceClient()) {
  // Uploads the click conversion. Partial failure should always be set to true.

  // NOTE: This request contains a single conversion as a demonstration.  However, if you have
  // multiple conversions to upload, it's best to upload multiple conversions per request
  // instead of sending a separate request per conversion. See the following for per-request
  // limits:
  // https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload_service
  UploadClickConversionsResponse response =
      conversionUploadServiceClient.uploadClickConversions(
          UploadClickConversionsRequest.newBuilder()
              .setCustomerId(Long.toString(customerId))
              .addConversions(clickConversion)
              // Enables partial failure (must be true).
              .setPartialFailure(true)
              .build());
      

C#

// Uploads the click conversion. Partial failure should always be set to true.
// NOTE: This request contains a single conversion as a demonstration.
// However, if you have multiple conversions to upload, it's best to upload multiple
// conversions per request instead of sending a separate request per conversion.
// See the following for per-request limits:
// https://developers.google.com/google-ads/api/docs/best-practices/quotas#conversion_upload
UploadClickConversionsResponse response =
    conversionUploadService.UploadClickConversions(
        new UploadClickConversionsRequest()
        {
            CustomerId = customerId.ToString(),
            Conversions = { clickConversion },
            // Enables partial failure (must be true).
            PartialFailure = true
        });

      

PHP

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

Python

# Creates the conversion upload service client.
conversion_upload_service: ConversionUploadServiceClient = (
    client.get_service("ConversionUploadService")
)
# Uploads the click conversion. 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 most efficient 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: UploadClickConversionsResponse = (
    conversion_upload_service.upload_click_conversions(
        customer_id=customer_id,
        conversions=[click_conversion],
        # Enables partial failure (must be true).
        partial_failure=True,
    )
)
      

Ruby

response = client.service.conversion_upload.upload_click_conversions(
  customer_id: customer_id,
  conversions: [click_conversion],
  # Partial failure must be true.
  partial_failure: true,
)

if response.partial_failure_error
  puts "Partial failure encountered: #{response.partial_failure_error.message}"
else
  result = response.results.first
  puts "Uploaded click conversion that happened at #{result.conversion_date_time} " \
    "to #{result.conversion_action}."
end
      

Perl

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

curl

Структура запроса и ответа REST

При вызове ConversionUploadService.UploadClickConversions через REST отправьте запрос POST, в котором для partialFailure задано значение true:

POST https://googleads.googleapis.com/v26/customers/{customer_id}:uploadClickConversions
{
  "partialFailure": true,
  "jobId": 1001,
  "conversions": [
    {
      "conversionAction": "customers/{customer_id}/conversionActions/{conversion_action_id}",
      "conversionDateTime": "2026-06-01 14:30:00-04:00",
      "conversionValue": 125.50,
      "currencyCode": "USD",
      "orderId": "ORDER-2026-0001",
      "gclid": "EAIaIQobChMI...",
      "consent": {
        "adUserData": "GRANTED"
      },
      "userIdentifiers": [
        {
          "userIdentifierSource": "FIRST_PARTY",
          "hashedEmail": "f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a"
        },
        {
          "userIdentifierSource": "FIRST_PARTY",
          "hashedPhoneNumber": "42975f8f9e46c2e13c1a2294957e5cb8d8e6f4f7341a036c6e595bc9f5e24621"
        }
      ]
    },
    {
      "conversionAction": "customers/{customer_id}/conversionActions/{conversion_action_id}",
      "conversionDateTime": "2026-06-01 14:35:00-04:00",
      "conversionValue": 80.00,
      "currencyCode": "USD",
      "orderId": "ORDER-2026-0002",
      "gclid": "EAIaIQobChMI_expired...",
      "consent": {
        "adUserData": "GRANTED"
      }
    }
  ]
}

В этом пакете из двух конверсий, где вторая не выполняется, успешные строки возвращают заполненные записи ClickConversionResult в results[], а неудачные строки возвращают пустые объекты {} в results[] вместе с подробностями об ошибке в partialFailureError на UploadClickConversionsResponse:

{
  "results": [
    {
      "conversionAction": "customers/{customer_id}/conversionActions/{conversion_action_id}",
      "conversionDateTime": "2026-06-01 14:30:00-04:00",
      "gclid": "EAIaIQobChMI...",
      "userIdentifiers": [
        {
          "userIdentifierSource": "FIRST_PARTY",
          "hashedEmail": "f660ab912ec121d1b1e928a0bb4bc61b15f5ad44d5efdc4e1c92a25e99b8e44a"
        },
        {
          "userIdentifierSource": "FIRST_PARTY",
          "hashedPhoneNumber": "42975f8f9e46c2e13c1a2294957e5cb8d8e6f4f7341a036c6e595bc9f5e24621"
        }
      ]
    },
    {}
  ],
  "jobId": "1001",
  "partialFailureError": {
    "code": 3,
    "message": "The click associated with the given identifier or iOS URL parameter occurred less recently than the maximum lookback window., at conversions[1].gclid",
    "details": [
      {
        "@type": "type.googleapis.com/google.ads.googleads.v26.errors.GoogleAdsFailure",
        "errors": [
          {
            "errorCode": {
              "conversionUploadError": "EXPIRED_EVENT"
            },
            "message": "The click associated with the given identifier or iOS URL parameter occurred less recently than the maximum lookback window.",
            "location": {
              "fieldPathElements": [
                {
                  "fieldName": "conversions",
                  "index": 1
                },
                {
                  "fieldName": "gclid"
                }
              ]
            }
          }
        ]
      }
    ]
  }
}

Как проверить импортированные данные

Используйте отчет о диагностике расширенного отслеживания конверсий лидов, чтобы проверить, насколько корректно выполнялся импорт в последнее время.

Как запрашивать данные диагностики загрузки с помощью 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

Импортированные конверсии отражаются в отчетах за дату показа, связанного с исходным кликом, а не за дату запроса на импорт или дату conversion_date_time ClickConversion.

Статистика по импортированным конверсиям с атрибуцией по последнему клику появляется в аккаунте Google Рекламы в течение трех часов. Для других моделей атрибуции в поисковой сети это может занять больше трех часов. Подробную информацию вы найдете в руководстве по актуальности данных.

При создании отчетов о показателях конверсий в кампаниях используйте сопоставление показателей пользовательского интерфейса, чтобы соотнести показатели интерфейса Google Рекламы с полями отчетов Google Ads API. Вы также можете запросить ресурс conversion_action, чтобы посмотреть общее количество конверсий и их общую ценность для определенного действия-конверсии.

Рекомендации

При реализации расширенного отслеживания конверсий потенциальных клиентов следуйте приведенным ниже рекомендациям.

Отправлять все данные о конверсиях, независимо от их полноты

Чтобы собирать точные и полные данные о конверсиях, импортируйте все доступные события-конверсии офлайн, включая те, которые не связаны с Google Рекламой. Конверсии, включающие только предоставленные пользователями данные, по-прежнему полезны и могут положительно влиять на оптимизацию кампаний Google Рекламы.

Если вы назначаете конверсии order_id, рекомендуем включить ее. Если у вас есть GCLID для конверсии, рекомендуем отправлять его вместе с user_identifiers, чтобы повысить эффективность. Если у вас есть несколько значений UserIdentifier для конверсии, включите их все в объект ClickConversion, чтобы повысить вероятность совпадения.

Как передать несколько конверсий в одном запросе

Если вам нужно импортировать несколько конверсий, объедините их в один пакет UploadClickConversionsRequest, а не отправляйте запрос на импорт для каждой конверсии.

Ознакомьтесь с руководством по квотам, чтобы узнать об ограничениях на количество конверсий в одном запросе.

Если вы хотите, чтобы диагностика офлайн-данных группировала набор запросов в рамках одного логического задания, задайте для всех запросов одинаковое значение job_id. Это может быть полезно, если у вас есть одно задание или процесс, который импортирует большое количество конверсий с помощью нескольких запросов. Если вы зададите одинаковое значение для атрибута job_id в каждом из этих запросов, то сможете получить информацию о вакансии из job_summaries. Если же вы позволите Google Ads API присваивать каждому запросу сгенерированное системой значение job_id, то в job_summaries будет отдельная запись для каждого запроса, что может усложнить анализ общего состояния задания.

Не использовать данные сторонней атрибуции

При использовании расширенного отслеживания конверсий лидов не задавайте external_attribution_data в ClickConversion и не указывайте conversion_action, в котором используется сторонняя модель атрибуции. Google Реклама не поддерживает конверсии со сторонней атрибуцией для импорта с использованием данных, предоставленных пользователями.

Не включать пользовательские переменные

При использовании расширенного отслеживания конверсий лидов не включайте custom_variables. Google Реклама не поддерживает использование пользовательских переменных с данными, предоставленными пользователями, при импорте конверсий. Если пользовательские переменные включены в конверсии, содержащие данные, предоставленные пользователями, такие конверсии будут считаться недействительными и удаляться.

Устранение неполадок

Диагностика офлайн-данных – это единый ресурс, который позволяет постоянно отслеживать общее состояние импортируемых данных. Однако при реализации вы можете использовать информацию из этого раздела, чтобы изучить ошибки, указанные в поле partial_failure_error ответа.

При импорте действий-конверсий часто возникают ошибки авторизации, например USER_PERMISSION_DENIED. Убедитесь, что в запросе указан идентификатор клиента, который владеет действием-конверсией. Подробнее об этом рассказывается в руководстве по авторизации. Также рекомендуем ознакомиться с руководством по распространенным ошибкам, в котором приведены советы по устранению различных неполадок.

Как устранять распространенные ошибки

Ниже приведены рекомендации, которые помогут вам диагностировать и устранить распространенные ошибки, связанные с расширенным отслеживанием конверсий лидов.

Ошибка
NO_CONVERSION_ACTION_FOUND

Указанное действие-конверсия либо не включено, либо недоступно для клиентского аккаунта, заданного в поле customer_id запроса. Убедитесь, что действие-конверсия, указанное в загружаемом файле, включено и принадлежит клиенту, отправившему запрос на загрузку.

Эта ошибка также может возникнуть, если параметр GCLID в запросе относится к клиентскому аккаунту, у которого нет доступа к действию-конверсии, указанному в запросе. Чтобы проверить, относится ли GCLID к клиентскому аккаунту, используйте ресурс click_view. Отправьте запрос с фильтрацией по click_view.gclid и segments.date, где дата – это дата клика.

INVALID_CONVERSION_ACTION_TYPE Указанное действие-конверсия имеет тип, который не подходит для расширенного отслеживания конверсий потенциальных клиентов. Убедитесь, что устройство ConversionAction, указанное в запросе на загрузку, имеет тип UPLOAD_CLICKS.
CUSTOMER_NOT_ENABLED_ENHANCED_CONVERSIONS_FOR_LEADS Включите расширенное отслеживание конверсий лидов в настройках конверсий. Инструкции приведены в руководстве по предварительным требованиям.
DUPLICATE_ORDER_ID Импортированные события содержат разные конверсии с одинаковым идентификатором заказа. Они не будут обработаны. Задайте уникальные идентификаторы заказов и повторите попытку.
CLICK_NOT_FOUND Не найден клик, соответствующий указанным идентификаторам пользователя.

Если при конверсии появляется такое предупреждение, Google Ads API включает его в successful_event_count диагностики офлайн-данных. В Google Ads API есть запись для CLICK_NOT_FOUND в коллекции alerts, чтобы вы могли отслеживать частоту появления этого предупреждения.

Эта ошибка ожидаема, если клик не связан с кампанией Google Рекламы. Например, это может быть SA360 или DV360. Другие возможные причины:

В редких случаях, когда клиент, загружающий данные, отличается от клиента, отслеживающего конверсии в Google Рекламе, эта ошибка может означать, что клиент, загружающий данные, принял условия использования данных клиентов, а клиент, отслеживающий конверсии, – нет.

Чтобы узнать, приняты ли в аккаунте условия в отношении данных клиентов, отправьте запрос к ресурсу customer и проверьте поле customer.conversion_tracking_setting.accepted_customer_data_terms.