Чем мы можем помочь?

Интегрируйте Web SDK от AppsFlyer

  • Обновлено

Кратко: Установите AppsFlyer Web SDK (также известный как пиксель) на своем сайте, чтобы передавать в AppsFlyer данные о посещениях и событиях пользователей, и задайте постоянный идентификатор пользователя (CUID), чтобы объединить пути пользователей на разных платформах.

Обзор

Web SDK позволяет фиксировать, как посетители взаимодействуют с вашим сайтом, и отправляет эту информацию в AppsFlyer. Это подключаемый модуль размером 40–60 КБ, который передает на платформу AppsFlyer данные о посещениях и действиях пользователей на вашем сайте.

Интегрируйте SDK вручную

 Следуйте приведенным ниже шагам, чтобы завершить интеграцию Web SDK от установки до валидации и настройки конфиденциальности.

  1. Получите свои ключи. Получите идентификатор Web SDK (также известный как Web Dev Key).
  2. Выберите фрагмент кода. Выберите фрагмент, который соответствует вашему типу интеграции и требованиям безопасности.
  3. Разверните Web SDK. Разверните SDK с помощью нативного фрагмента кода, Google Tag Manager или Adobe Launch Tag Manager.
  4. Убедитесь, что SDK работает. Проверьте, что SDK отправляет запросы, проверив сетевые обращения в инструментах разработчика браузера.
  5. Настройте и записывайте события. Определите и отправляйте пользовательские события при загрузке страницы или взаимодействии пользователя с помощью нативного JavaScript или Google Tag Manager.
  6. Задайте идентификатор пользователя. Установите постоянный CUID для унификации веб-активности с другими платформами.
  7. Управление конфиденциальностью. Управляйте согласием или отказом от измерения, а также настройте параметры безопасности и фильтрации данных (политику безопасности контента и удаление параметров запроса).
  8. Справочник по файлам cookie Web SDK. Просмотрите файлы cookie, которые устанавливает или использует Web SDK, включая их назначение, срок действия и область применения.

Интегрируйте SDK с помощью ИИ-агента для написания кода.

Вместо ручной интеграции Web SDK (см. шаги ниже) используйте ИИ-инструмент для написания кода (Cursor, Claude Code, Codex, Copilot), чтобы он выполнил всю интеграцию за вас. Скопируйте промпт, замените два плейсхолдера и вставьте его в свой ИИ-инструмент для написания кода.

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

Перед копированием промпта замените:

  • <WEB_SDK_ID>: В AppsFlyer перейдите в App Settings, выберите свое веб-приложение (домен вашего сайта с префиксом "website-"), затем скопируйте Web SDK ID из раздела Аутентификация SDK..
  • <PRODUCTION_URL>: URL-адрес вашего рабочего сайта, который используется для проверки после развертывания.

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

Промпт для ИИ-внедрения
# **AppsFlyer Web SDK — промпт для ИИ-внедрения**

Скопируйте промпт ниже в ИИ-инструмент для написания кода, который может редактировать ваш проект (Cursor, Claude Code, Codex, Copilot). Перед копированием замените два плейсхолдера:

  - <WEB_SDK_ID> — в AppsFlyer перейдите в Мои приложения, выберите свое веб-приложение (ваш домен с префиксом website-) и скопируйте Web SDK ID (также называется Web Dev Key) из раздела Аутентификация SDK.
  - <PRODUCTION_URL> — URL-адрес вашего сайта, который используется для проверки после развертывания.

Внедрите AppsFlyer Web SDK (пиксель веб-атрибуции) на этом сайте, включая события, важные для измерения эффективности маркетинга.


Мой Web SDK ID: <WEB_SDK_ID>

URL моего рабочего сайта: <PRODUCTION_URL>

## ШАГ 0 — Проверка конфигурации

Если указанный выше идентификатор Web SDK отсутствует или вместо него все еще используется заполнитель, ответьте ТОЛЬКО кратким запросом на предоставление идентификатора (в AppsFlyer: My Apps > приложение с префиксом «website-» > SDK authentication > Web SDK ID) и остановитесь.
 Не пишите код, пока идентификатор не будет предоставлен.
 Если URL рабочего сайта не указан, запросите его в том же ответе — он необходим для проверки после развертывания.


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


## Шаг 1 - Сначала проанализируйте сайт

Прежде чем писать код, изучите кодовую базу и самостоятельно составьте план событий — не просите меня перечислять события:

1. Определите фреймворк (обычный HTML, React, Next.js, Vue и т. д.) и место, где документ <head> управляется.

2. Определите действия-конверсии на основе кода. Проверьте в следующем порядке, от более надежного к менее надежному:

   - Существующие вызовы аналитики: события gtag()/GA4, Segment analytics.track(), fbq('track'), dataLayer.push (включая объекты eCommerce) — они покажут и действия, и то, где уже хранятся значения (сумма, валюта, идентификатор заказа).

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


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

   - Формы и CTA: формы для лидов, начало подписки/пробного периода, загрузки.

   Для продуктов, не связанных с электронной коммерцией, и инструментов: если на сайте нет процессов покупки, работы с корзиной, оформления заказа, регистрации или входа, не создавайте события электронной коммерции или аутентификации, которых на самом деле нет. Определите реальные действия пользователей в продукте (например, создание, копирование, экспорт, скачивание, отправку, выбор шаблона или изменение параметров) и сопоставьте их с пользовательскими событиями с понятными описательными названиями.


3. Сопоставьте каждое найденное действие со стандартным названием AppsFlyer:

   - завершенный заказ / "Заказ завершен" /purchase_success -> af_purchase (с eventRevenue)

   - регистрация/ зарегистрироваться/ учетная запись создана -> af_complete_registration

   - вход/ signin -> af_login

   - добавить в корзину / "Product Added" -> af_add_to_cart (af_price, без eventRevenue)

   - оформить заказ / "Checkout Started" -> af_initiated_checkout (af_price, без eventRevenue)

   - просмотр товара или контента -> af_content_view

   - оформление подписки -> af_subscribe; free trial started -> af_start_trial

   - поиск-> af_search

   Все, у чего нет стандартного эквивалента, сохраняет описательное пользовательское название.

4. Для каждого события определите в коде точный источник следующих данных: фактически списанная сумма (для af_purchase), валюта, идентификатор заказа/транзакции и идентификатор пользователя. Повторно используйте те же источники данных, из которых считывает существующая аналитика.

5. Проверьте, есть ли существующая платформа управления согласием (CMP), например OneTrust или Didomi. Также отметьте любые собственные настройки согласия или конфиденциальности, которые сохраняются на сайте, и спросите меня, как они должны ограничивать измерение, вместо того чтобы решать это за меня.


Примечание: существующая аналитика используется только как источник данных для определения событий - реализуйте события AppsFlyer как прямые вызовы AF(), а не передавайте их через Segment/GA4 с используемыми там названиями.

Затем покажите мне предлагаемый план событий в виде таблицы (название события AppsFlyer, триггер + файл, источник revenue/af_price, источник идентификатора дедупликации) и дождитесь моего подтверждения перед реализацией.
 Отмечайте любое событие, для которого вам не удалось найти источник значения, вместо того чтобы гадать.

## Шаг 2 — Установите SDK-сниппет

Добавьте этот фрагмент кода ближе к началу <head> на каждой странице, указав мой идентификатор Web SDK:

<script>

!function(t,e,n,s,a,c,i,o,p){t.AppsFlyerSdkObject=a,t.AF=t.AF||function(){

(t.AF.q=t.AF.q||[]).push([Date.now()].concat(Array.prototype.slice.call(arguments)))},

t.AF.id=t.AF.id||i,t.AF.plugins={},o=e.createElement(n),p=e.getElementsByTagName(n)[0],o.async=1,

o.src="https://websdk.appsflyer.com?"+(c.length>0?"st="+c.split(",").sort().join(",")+"&":"")+(i.length>0?"af_id="+i:""),

p.parentNode.insertBefore(o,p)}(window,document,"script",0,"AF","pba",{pba: {webAppId: "<WEB_SDK_ID>"}})

</script>

Жесткие правила:

- Используйте сниппет дословно. НЕ переписывайте его в виде пользовательского компонента или модуля-обертки. SDK, интегрированные через обертку, могут отправлять пользовательские события, в то время как автоматическое событие посещения (событие LOAD в SDK) не срабатывает - в результате на сайте отображается ноль посещений и атрибуция становится невозможной.


- SDK должен загружаться ровно ОДИН раз при каждой загрузке страницы. В React/Next.js предусмотрите защиту от повторного рендеринга и двойного монтирования (например, загружайте SDK в корневом шаблоне HTML/document, а не внутри компонента, который монтируется повторно).
 Многократная загрузка может привести к тому, что SDK перестанет работать.

* Если сайт уже загружает AppsFlyer SDK через менеджер тегов (GTM), НЕ добавляйте его также в код - должен использоваться один загрузчик, а не два.
 Сообщите мне, если найдете существующий тег AppsFlyer.

- НЕ внедряйте событие просмотра страницы или посещения вручную. SDK автоматически регистрирует посещения при загрузке; самодельное событие "page_view" никогда не будет учитываться как посещение.

- Ключ конфигурации — webAppId (а не appId).

- Если на сайте применяется строгая политика безопасности контента (Content Security Policy, CSP) с nonce, добавьте nonce в тег встроенного фрагмента кода И убедитесь, что политика включает 'strict-dynamic' - фрагмент кода динамически внедряет скрипт SDK, и без 'strict-dynamic' политика, использующая только nonce, блокирует его.

## Шаг 3 — Внедрите события

Формат вызова события:

AF('pba', 'event', {

  eventType: 'EVENT',            // always the literal string 'EVENT'

  eventName: 'af_purchase',

  eventRevenue: 49.99,           // top level - only on realized revenue

  eventRevenueCurrency: 'USD',   // top level - 3-letter ISO code, defaults to USD if omitted

  eventValue: {                  // JSON metadata, max 1000 characters

    "af_order_id": "TXN-12345",

    "af_customer_event_id": "evt-abc-001"

  }

});

Event rules - follow these exactly:

1.. Используйте стандартные названия событий AppsFlyer, чтобы кроссплатформенная отчетность и воронки были согласованы: af_purchase, af_complete_registration, af_login, af_add_to_cart, af_initiated_checkout, af_content_view, af_subscribe. Если есть мобильное приложение, используйте ТЕ ЖЕ названия событий, что и в мобильном SDK. Никогда не добавляйте суффиксы платформы, например "_web".

   Исключение — отдельные строки покупок: если сайт явно продаёт отдельные уровни или категории продуктов, для которых нужны отдельные разбивки в дэшборде (например, два продукта по подписке), предложите в плане событий раздельные названия (af_purchase_<tier>) вместо одного общего события и укажите почему. Сегментация только через eventValue не отображается в стандартных представлениях дэшборда. Никогда не отправляйте ОДНОВРЕМЕННО событие для конкретного уровня и общее событие для одной и той же покупки - это приводит к дублированию данных.


2. Доход указывайте ТОЛЬКО в поле eventRevenue верхнего уровня и ТОЛЬКО для событий, в которых деньги действительно были переведены (завершенная покупка, завершенная подписка, подтвержденное бронирование). Значения внутри eventValue (af_revenue, revenue, price, amount, total) НИКОГДА не учитываются как доход — указание дохода там является ошибкой реализации №1 и приводит к доходу $0 по каждой покупке.

3. Всегда отправляйте eventRevenueCurrency вместе с eventRevenue, если валюта не USD, иначе любая сумма будет записана как USD.

4. Отправляйте фактическую сумму одной транзакции как обычное число: без символов валют, без указания центов как целых единиц, без дублирования общей суммы корзины и суммы товара, без пожизненной ценности клиента.

5. Для денежных значений, которые НЕ являются фактически полученным доходом (стоимость добавления в корзину, стоимость начала оформления заказа, просмотренная цена), НЕ задавайте eventRevenue. Укажите сумму в "af_price", а валюту — в "af_currency" внутри eventValue. Если отправлять eventRevenue и для af_initiated_checkout, и для af_purchase, доход будет учитываться дважды.

6. Для покупок добавляйте "af_order_id" (идентификатор транзакции) внутри eventValue. Если на этом этапе в кодовой базе нет реального идентификатора транзакции, укажите это в плане событий вместо того, чтобы подставлять заполнитель.


7. Добавляйте уникальный "af_customer_event_id" внутри eventValue для каждого события конверсии. Одно и то же событие с одним и тем же ID никогда не должно отправляться дважды - создавайте ID отдельно для каждого действия и предусмотрите защиту от повторного срабатывания обработчика при повторном рендеринге SPA.
 Это также устраняет дублирование, если какой-либо серверный поток (S2S) отправляет те же конверсии.

8. Одно событие на одно действие пользователя. Не отправляйте одно и то же действие под двумя разными названиями и не передавайте одно и то же действие одновременно через AppsFlyer и через промежуточный слой пересылки под разными названиями.


9. Для корзин с несколькими товарами добавьте массив "af_order_info" внутри eventValue - по одному объекту для каждого товара с ключами: sku, revenue (цена за единицу), qty, content_name, content_type, content_category, brand.
 При покупке eventRevenue верхнего уровня по-прежнему содержит общую сумму заказа.

10. События должны срабатывать после того, как на странице загрузится сниппет SDK. Если конверсия завершается на странице подтверждения или благодарности, запускайте событие при загрузке этой страницы; для действий внутри страницы (кликов по кнопкам в SPA) запускайте его из обработчика действия.

11. Передавайте только необходимые данные - исключайте нерелевантные поля:

    - НЕ включайте eventRevenue или eventRevenueCurrency, если в рамках этого события фактически не было денежной транзакции. Никогда не отправляйте eventRevenue: 0 или валюту по умолчанию «на всякий случай».

    - НЕ включайте eventCategory, eventLabel и любые поля в стиле GA/Segment. Они не входят в API событий Web SDK AppsFlyer.

    - Внутри eventValue опускайте ключи, значения которых представляют собой пустую строку, null, undefined или false (если только само значение false не имеет смысла для этого свойства).

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


    - Пустые столбцы дохода/валюты в отчетах AppsFlyer не означают, что клиент должен отправлять нули или значения по умолчанию: просто не передавайте эти поля.

## ШАГ 4 - Задайте идентификатор пользователя клиента (CUID)

Сразу после того, как пользователь войдет в систему или зарегистрируется (а также при загрузке страниц, где пользователь уже аутентифицирован), вызовите:

AF('pba', 'setCustomerUserId', '<the user's internal ID, as a string>');

Правила:

- Используйте ТОТ ЖЕ идентификатор, который мобильные приложения передают в setCustomerUserId, если мобильные приложения существуют: именно он связывает путь пользователя между вебом и мобильными приложениями.

- Используйте непрозрачный внутренний идентификатор. Никогда: адрес электронной почты, номер телефона или другие PII.

- Вызывайте его как можно раньше: события, отправленные до этого, не будут содержать CUID.

- Сам по себе setCustomerUserId не создает событие, доступное для отчетности. Также отправляйте af_complete_registration при регистрации и af_login при входе после установки CUID, чтобы эти события содержали CUID.


## ШАГ 5 - Согласие (только если есть CMP)

Если на сайте есть платформа управления согласием:

- Инициализируйте SDK  с отключенным измерением {pba: {webAppId: "<WEB_SDK_ID>", measurementStatus: false}}

- После получения согласия: window.AF_SDK.PLUGINS.PBA.enableMeasurement()

- После отзыва согласия: window.AF_SDK.PLUGINS.PBA.disableMeasurement()
Примечания:

- Эти методы плагина становятся доступны только после полной загрузки скрипта SDK, в отличие от AF(), который представляет собой очередь-заглушку и доступен сразу.
 Обеспечьте правильную последовательность выполнения.


- Если измерение изначально отключено, до получения согласия визит не фиксируется. Явно обозначьте этот компромисс перед реализацией.

Если CMP нет, используйте обычный сниппет (по умолчанию измерение включено).

## Шаг 6 — Проверка

### 6a. Локальная верификация (во время внедрения)

Запустите проект, откройте его в браузере (с помощью Playwright/Puppeteer или браузерного инструмента, если он доступен) и зафиксируйте КАК данные запроса, ТАК И HTTP-статус ответа для каждого запроса к доменам AppsFlyer.
 Проверьте:

- Запрос загрузчика SDK возвращает статус 200 и выполняется ровно один раз при каждой загрузке страницы (переходите между страницами и повторно рендерите компоненты, чтобы убедиться в отсутствии повторной загрузки).

- При загрузке страницы отправляется запрос с eventType "LOAD" и заполненным afWebUserId, а его ответ имеет статус 2xx - это посещение; без него атрибуция невозможна.

- Каждая реализованная конверсия создает ровно один запрос события, каждый из которых возвращает статус 2xx, при этом для покупок eventRevenue и eventRevenueCurrency находятся на верхнем уровне, а af_customer_event_id присутствует и является уникальным.



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

Перехваченный запрос НЕ является доказательством успешного выполнения.
 Событие, ответ на которое имеет статус 4xx, было отклонено и никогда не появится в отчетности. Указывайте код статуса для каждого отправленного события и никогда не сообщайте, что событие проверено, если код статуса не получен.


Если вы не можете запустить браузер, выполните статическую проверку: фрагмент кода имеет единственную точку вставки, которая не может монтироваться дважды; каждый обработчик события срабатывает ровно один раз для каждого действия; revenue и currency передаются в полях верхнего уровня; setCustomerUserId доступен для каждого сценария входа аутентифицированного пользователя.
 Прямо укажите, что статус ответа получить не удалось.

### 6b. Проверка после развертывания на реальном домене (обязательно)

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

- Загрузите рабочий URL и убедитесь, что фрагмент кода присутствует в HTML-коде, ФАКТИЧЕСКИ ОТДАВАЕМОМ сервером.

- Загрузите рабочую страницу в браузере и повторите для нее все проверки из раздела 6a.

- Убедитесь, что параметр запроса af_id в исходящих запросах содержит Web SDK ID в точности без изменений - неверный или обрезанный ID означает, что события отправляются с идентификатором, которого нет в моем аккаунте, и в результате они просто никуда не попадут.

- Используйте специальный идентификатор пользователя для QA (например, qa_<yyyymmdd>_01), чтобы впоследствии можно было отдельно найти данные этого тестового запуска в необработанных данных.

Если развертывание еще не выполнено, сообщите мне, что проверка 6b еще не выполнена, и предоставьте точные команды и проверки, которые нужно запустить после развертывания.


### 6c. Запись QA

Подготовьте таблицу проверочного запуска, чтобы затем можно было сопоставить строки в сырых данных AppsFlyer — по одной строке на событие: метка времени UTC, имя события, CUID, af_order_id, af_customer_event_id, статус HTTP. Укажите время начала и окончания всего запуска в UTC, а также время развертывания в UTC, если оно вам известно.

## Шаг 7 — Обратная проверка данных

Включите в отчет подробные инструкции по проверке событий в AppsFlyer, поскольку посещения и конверсии относятся к разным типам записей и их легко перепутать:

- Визиты записываются автоматически и отображаются в данных уровня событий как строки SESSION с ПУСТЫМ именем события и нулевым доходом — так устроена схема, это не ошибка. Первые посещения и повторные посещения отображаются в данных уровня конверсии (FIRST_VISIT / REVISIT), а не как именованные события. Экспорт данных по сеансам никогда не будет содержать события в приложении, независимо от того, насколько правильно выполнена интеграция.

- Реализованные конверсии отображаются как отдельные строки с заполненным именем события (af_purchase, af_login и т. д.), а доход указывается только в строках покупки.

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


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


- Укажите точный фильтр, который нужно использовать, чтобы найти QA-запуск из 6c (временное окно плюс QA CUID), и опишите, как выглядит корректный результат.

- Если события возвращают статус 2xx, но по-прежнему не появляются после истечения периода задержки, четко укажите, что это проблема на стороне аккаунта (событие не включено для веб-приложения, область отчетности или доступ к данным), а не с ошибкой в коде, и перечислите, что мне следует проверить в интерфейсе AppsFlyer.

## Выходные данные

Когда закончите, предоставьте:

- Таблицу всех реализованных событий: название, место срабатывания (файл), обработка дохода, идентификатор дедупликации.

- Где был установлен сниппет и как гарантируется его однократная загрузка.

- Где вызывается setCustomerUserId.

- Таблица результатов QA из раздела 6c и четкое разделение того, что вы проверили самостоятельно (с указанием статусов ответов), и того, что остается мне проверить вручную по чек-листу QA (какую страницу открыть, какое действие выполнить, какой запрос и статус ожидать).

- Инструкции из шага 7 по получению данных из системы.

- Все, что вы не смогли реализовать или для чего вам нужны данные от меня (например, где хранится идентификатор пользователя, какое поле с суммой покупки содержит итоговую списанную сумму, любые источники значений, которые вы не стали определять самостоятельно).

Не реализуйте ничего сверх описанной здесь интеграции AppsFlyer Web SDK.

1. Получите свои ключи

Получите идентификатор Web SDK (также известный как Web Dev Key):

  1. В AppsFlyer в верхнем меню откройте Настройки приложений.
  2. В селекторе приложений в верхней части страницы выберите свое веб-приложение (домен вашего сайта с префиксом "website-").
  3. В разделе Аутентификация SDK скопируйте Web SDK ID.

Получите ключ Smart Banner (если необходимо):

  1. В AppsFlyer в боковом меню перейдите в раздел Вовлечение > Web to App > Smart Banners.
  2. Скопируйте необходимый ключ смарт-баннера.

2. Выберите фрагмент кода

Выберите фрагмент, который соответствует вашему типу интеграции и требованиям безопасности. Доступны следующие две опции:

  • Стандартный Web SDK: Стандартная интеграция.
  • Расширенная проверка SDK: улучшенная интеграция, которая обеспечивает дополнительную защиту цепочки поставок для Web SDK. Используйте эту опцию, чтобы добавить дополнительный уровень защиты от компрометации CDN, перехвата DNS и атак «человек-посередине».

Если вы переходите от стандартного Web SDK к расширенной проверке SDK, замените существующий сниппет на новый. Не добавляйте новый сниппет поверх существующего.

Стандартный Web SDK

Используйте этот сниппет для развертывания стандартной интеграции Web SDK. Вставьте его в верхней части тега на всех страницах, где вы хотите загрузить SDK.

Без Smart Banners
<script>
  // Queue — buffers AF() calls until the SDK is ready
  window.AppsFlyerSdkObject = "AF";
  window.AF = window.AF || function() {
    (window.AF.q = window.AF.q || []).push([Date.now()].concat(Array.prototype.slice.call(arguments)));
  };
  // Replace WEB_DEV_KEY with your Web SDK ID
  window.AF.id = window.AF.id || { pba: { webAppId: "WEB_DEV_KEY" } };
  window.AF.plugins = {};

  // Inject SDK
  var o = document.createElement("script"),
      p = document.getElementsByTagName("script")[0];
  o.async = 1;
  // Replace WEB_DEV_KEY with your Web SDK ID
  o.src = "https://websdk.appsflyersdk.com?" + "st=pba&af_id=WEB_DEV_KEY";
  p.parentNode.insertBefore(o, p);
</script>
С Smart Banners
<script>
  // Queue — buffers AF() calls until the SDK is ready
  window.AppsFlyerSdkObject = "AF";
  window.AF = window.AF || function() {
    (window.AF.q = window.AF.q || []).push([Date.now()].concat(Array.prototype.slice.call(arguments)));
  };
  window.AF.id = window.AF.id || { pba: { webAppId: "WEB_DEV_KEY" }, banners: { key: "YOUR_BANNER_KEY" } };
  window.AF.plugins = {};

  // Inject SDK
  var o = document.createElement("script"),
      p = document.getElementsByTagName("script")[0];
  o.async = 1;
  o.src = "https://websdk.appsflyersdk.com?" + "st=pba,banners&af_id=WEB_DEV_KEY";
  p.parentNode.insertBefore(o, p);
  AF('banners', 'showBanner');
</script>

Расширенная проверка SDK

Расширенная проверка SDK добавляет защиту цепочки поставок для Web SDK. Это гарантирует, что код, выполняемый в браузерах ваших пользователей, в точности соответствует коду, опубликованному AppsFlyer. Исходный код SDK идентичен стандартной интеграции; различаются только механизмы доставки и проверки.

Расширенная проверка SDK:

  • Добавляет дополнительный уровень безопасности против компрометации CDN, захвата DNS и атак «человек посередине».
  • Добавляет примерно 250 мс к времени загрузки SDK.

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

Если ваш сайт применяет Политику безопасности контента (CSP) с использованием nonce, смотрите Политика безопасности контента (CSP) в разделе Управление конфиденциальностью, чтобы получить расширенный вариант этого сниппета с nonce.

Без Smart Banners
<script>
  // Queue — buffers AF() calls until the SDK is ready
  window.AppsFlyerSdkObject = "AF";
  window.AF = window.AF || function() {
    (window.AF.q = window.AF.q || []).push([Date.now()].concat(Array.prototype.slice.call(arguments)));
  };
  window.AF.id = window.AF.id || { pba: { webAppId: "WEB_DEV_KEY" } };
  window.AF.plugins = {};

  // Manifest loader config
  window.AF_LOADER_CONFIG = {
    baseUrl: "https://websdk.appsflyersdk.com",
    plugins: ["pba"]
  };

  // Inject manifest loader
  var loaderScript = document.createElement("script");
  loaderScript.src = "https://websdk.appsflyersdk.com/manifestLoader.v1.js";
  loaderScript.integrity = "sha384-Uncl2YwvjFpFz0PwEfl3bL/0JsOQcDFEpwXHzcN0MBavn9vvFEx5pZxADTq8h+CV";
  loaderScript.crossOrigin = "anonymous";
  loaderScript.async = true;
  document.head.appendChild(loaderScript);
</script>
С Smart Banners
<script>
  // Queue — buffers AF() calls until the SDK is ready
  window.AppsFlyerSdkObject = "AF";
  window.AF = window.AF || function() {
    (window.AF.q = window.AF.q || []).push([Date.now()].concat(Array.prototype.slice.call(arguments)));
  };
  window.AF.id = window.AF.id || { pba: { webAppId: "WEB_DEV_KEY" }, banners: { key: "YOUR_BANNER_KEY" } };
  window.AF.plugins = {};

  // Manifest loader config
  window.AF_LOADER_CONFIG = {
    baseUrl: "https://websdk.appsflyersdk.com",
    plugins: ["banners", "pba"]
  };

  // Inject manifest loader
  var loaderScript = document.createElement("script");
  loaderScript.src = "https://websdk.appsflyersdk.com/manifestLoader.v1.js";
  loaderScript.integrity = "sha384-Uncl2YwvjFpFz0PwEfl3bL/0JsOQcDFEpwXHzcN0MBavn9vvFEx5pZxADTq8h+CV";
  loaderScript.crossOrigin = "anonymous";
  loaderScript.async = true;
  document.head.appendChild(loaderScript);
</script>

3. Разверните сниппет

Разверните выбранный вами на Шаге 2 сниппет, используя один из следующих методов. Убедитесь, что SDK загружается только один раз при каждой загрузке страницы.

Вариант A: Добавьте непосредственно на ваш сайт

Повторите это на всех страницах:

  1. В сниппете из Шага 2 замените WEB_DEV_KEY на ваш ID Web SDK (и YOUR_BANNER_KEY, если применимо).
  2. Вставьте сниппет ближе к началу тега <head> вашего сайта.
Вариант B: Разверните через Google Tag Manager (GTM)

Убедитесь, что SDK загружается один раз при каждой загрузке страницы, и настройте его загрузку сразу после загрузки страницы с помощью приоритизации в GTM.

  1. Открыть Google Tag Manager.
  2. Создать новый тег для Web SDK AppsFlyer.
  3. Выберите тип тега Пользовательский HTML.
  4. Присвойте тегу понятное название.
  5. Вставьте сниппет из Шага 2 в Конфигурацию тега.
  6. Нажмите Сохранить .
  7. Добавьте триггер:
    • Для всех страниц:
      1. Нажмите Добавить триггер.
      2. Выберите Все страницы.
      3. Нажмите Сохранить.
      4. Введите название тега, затем нажмите Сохранить.
    • Для конкретных страниц:
      1. Нажмите Сохранить тег.
      2. В главном окне GTM выберите Триггеры. Нажмите Новый.
      3. Нажмите на значок карандаша.
      4. Выберите тип триггера Просмотр страницы.
      5. Выберите Просмотр нескольких страниц.
      6. Настройте страницу и условия триггера по мере необходимости.
      7. Нажмите Сохранить .
      8. Свяжите триггер с тегом Web SDK AppsFlyer.
        1. В главном окне GTM выберите Теги.
        2. Выберите тег, который вы создали ранее.
        3. В панели триггеров нажмите на иконку карандаша.
        4. Выберите триггер просмотра страницы, который вы создали ранее.
        5. Нажмите Сохранить.

Пользовательские шаблоны GTM не поддерживают расширенную проверку SDK, поскольку их изолированная среда не позволяет задавать атрибут integrity, необходимый для проверки. Вместо этого используйте тип тега Пользовательский HTML.

Вариант С: Разверните через Adobe Launch Tag Manager

Создайте свойство в Adobe Experience Cloud

  1. Откройте Adobe Experience Cloud > Launch.
  2. В разделе Adobe Experience Cloud Launch нажмите Перейти к запуску.
  3. Нажмите Новое свойство.
  4. Присвойте свойству название.
  5. В разделе Платформа выберите Веб-сайт.
  6. Укажите домен своего сайта.
  7. Нажмите Сохранить.

Добавьте сниппет в свойство Adobe Launch

  1. На странице Свойства сайта выберите вкладку Правила .
  2. Дайте правилу название. Рекомендуется: Загрузите веб-SDK.
  3. В разделе ЕСЛИ под пунктом СОБЫТИЯ нажмите Добавить.
    • В разделе Тип события выберите Основное, с поддержкой DOM.
    • Нажмите Сохранить изменения.
  4. В разделе ТОГДА в пункте Действия нажмите Добавить.
    • В разделе Тип действия выберите Пользовательский код.
    • Выберите JavaScript > Открыть редактор и вставьте сниппет из Шага 2 (без строк-оберток).
    • Нажмите Сохранить изменения, чтобы закрыть Редактор кода.
  5. Нажмите Сохранить.

Добавьте тег Adobe Launch на сайт

  1. На странице Свойства сайта выберите вкладку Среды.
  2. Найдите строку со средой, которую вы хотите опубликовать (разработка или рабочая среда).
  3. В колонке Установка нажмите на иконку коробки в соответствующей строке.
  4. В диалоговом окне Инструкции по установке для веб-приложения скопируйте фрагмент кода скрипта и закройте диалоговое окно.
  5. Вставьте фрагмент кода в раздел <head> сайта.

Опубликуйте окружение Adobe Launch

  1. На странице Мой веб-ресурсвыберите вкладку Публикация .
  2. В разделе Разработка нажмите Добавить новую библиотеку.
    • Назовите библиотеку и выберите среду. 
    • В пункте Изменения ресурсов нажмите Добавить ресурс.
    • Нажмите Правила > Загрузка Web SDK > Последняя версия > Выбрать и создать новую редакцию.
    • Нажмите Сохранить.
  3. В разделе Разработка:
    • Рядом с недавно созданной библиотекой нажмите меню действий (3 точки) > выберите Собрать для разработки.
    • Снова откройте меню действий и выберите опцию Отправить на утверждение.
  4. В разделе Отправленные:
    • Нажмите меню действий > выберите Собрать для промежуточной среды.
    • Снова откройте меню действий и выберите опцию Утвердить для публикации.
  5. В разделе Утвержденные:
    • Нажмите меню действий > выберите Собрать и опубликовать в рабочей среде.

4. Убедитесь, что SDK работает

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

Скриншот DevTools

Чтобы убедиться, что SDK работает, выполните следующие шаги:

  1. Откройте веб-сайт.
  2. Откройте инструменты разработчика в браузере.
  3. Перейдите на вкладку (A) Сеть.
  4. Обновите страницу.
  5. Фильтровать по (B) appsflyer. Может появиться два запроса:
    • Загрузчик SDK — URL запроса начинается с https://websdk.appsflyersdk.com. Это подтверждает, что скрипт SDK загружен правильно.
    • Данные события — URL запроса начинается с https://wa.appsflyer.com/events. Это подтверждает, что SDK отправляет данные событий в AppsFlyer.
  6. Выберите сообщение (C) события (вызов wa.appsflyer.com).
  7. В разделе Заголовки (D) убедитесь, что:
    • URL запроса начинается с https://wa.appsflyer.com/events?site-id=.
    • site_id query parameter = WEB_DEV_KEY.
    • Код статуса 200.
  8. Проверьте, что site_id соответствует WEB_DEV_KEY в верхнем менюAppsFlyer > Мои приложения.
  9. Убедитесь, что пакет SDK загружается только один раз. Многократная загрузка SDK может привести к тому, что SDK перестанет работать.

Чтобы в реальном времени визуально подтвердить установку Web SDK и проверить, что ваши события срабатывают корректно, используйте страницу тестирования Web SDK.

5. Установите и запишите события

После инициализации Web SDK вы можете перейти от измерения базовых посещений к захвату конкретных действий пользователей. В этом разделе показано, как задавать и регистрировать пользовательские события, такие как покупки или регистрации, с использованием либо нативного JavaScript, либо Google Tag Manager.

Задать события

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

Пример события (событие покупки с сопутствующим доходом)

AF('pba', 'event', {eventType: 'EVENT', eventName: 'purchase', eventRevenue: 12, eventValue: {"key1": 123, "key2": "name", "af_customer_event_id": "evt-abc-001"}});
Таблица параметров событий Web SDK
Название параметра Обязательно Описание
eventType Да Тип события. Формат: Строка. Всегда заполняйте этот параметр значением EVENT.. Пример: eventType: "EVENT"
eventName Да Название события. Формат: Строка. Пример: Покупка, подписка
eventRevenue Нет Доход, присвоенный событию конверсии Формат:
eventRevenueCurrency Нет Валюта выручки. Трехбуквенный код валюты по стандарту ISO 4217. По умолчанию: USD. Формат: Строка
eventValue Нет Сопоставление параметров события, описывающих событие. Используйте этот параметр, чтобы передавать расширенные события внутри приложения, например артикул товара и цену позиции. Формат: JSON. Пример: {"sku": "ABC123", "color": "blue", "unit_price": 3.99, "currency": "USD"} Ограничение: 3000 символов (если превышено, значение будет усечено).
Записывайте события при загрузке страницы

Это стандартный подход для конверсий, которые заканчиваются перенаправлением, например, на странице Спасибо или подтверждения.

Вы можете реализовать этот триггер, добавив метод загрузки окна в ваш нативный JavaScript или настроив триггер просмотра страницы в Google Tag Manager.

Следующие примеры кода приведены исключительно в иллюстративных целях. Не используйте этот код в таком виде; адаптируйте его к конкретной структуре вашего сайта.

Пример: Запишите событие через AF Web SDK

Этот подход идеален для записи конверсий, которые происходят через перенаправления, такие как страница "Спасибо" для подписки на рассылку.

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

Пример загрузки нативной страницы:

window.onload = function(){
  AF('pba', 'event', {eventType: 'EVENT', eventValue: {'category': 'holiday_promotion'}, eventName: 'subscription'});
}

Как это работает:

  1. Страница загружает необходимый контент.
  2. Как только окно полностью загружено (window.onload), скрипт автоматически вызывает метод AF().
  3. Событие подписки, вместе с его сопутствующими метаданными (категория и метка), отправляется напрямую в AppsFlyer.
Пример: Запишите событие через GTM

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

1. Настройте страницу «Спасибо»

Следующая структура HTML загружает GTM, который, в свою очередь, загружает Web SDK. Она также демонстрирует, как данные могут быть доступны для GTM через функции или localStorage.

<html>
<head>
    <script>
        // Google Tag Manager loads the Web SDK
        (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
        new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
        j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
        'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
        })(window,document,'script','dataLayer','GTM-XXXX');
    </script>
    <script>
        function getResponseFromServer() {
            return JSON.stringify({ action: 'subscribe', category: 'site actions', label: userEmail })
        }
        localStorage.setItem('data', JSON.stringify({ action: 'subscribe', category: 'site actions', label: 'user@email.com' }));
    </script>
</head>
<body>
    <h1>Thank You for Subscribing to Our Newsletter</h1>
</body>
</html>

2. Настройте тег GTM

  1. Создайте новый тег в GTM и выберите тип тега Пользовательский HTML.
  2. Укажите уникальное название (например, "Событие подписки AF").
  3. Вставьте следующий скрипт в текстовое поле HTML:

    AF('pba', 'event', {eventType: 'EVENT', eventValue: {'category' : 'holiday_promotion'}, eventName: 'subscription'});
  4. Разверните Расширенные настройки > Последовательность тегов. Убедитесь, что он настроен на срабатывание после основного тега инициализации Web SDK.
  5. Установите триггер для этого тега, чтобы он срабатывал при Просмотре страницы вашей страницы "Спасибо".
Записывайте события при взаимодействии пользователя.

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

Для отслеживания таких взаимодействий обычно привязывают обработчик клика к нативному HTML-элементу или используют переменные Google Tag Manager, чтобы определять и измерять взаимодействия с конкретными элементами по их ID или CSS-селекторам.

Следующие примеры кода приведены исключительно в иллюстративных целях. Не используйте этот код в таком виде; адаптируйте его к конкретной структуре вашего сайта.

Пример: Запишите событие через AF Web SDK

Используйте этот метод для измерения определенных действий пользователей на странице, например нажатия кнопки Оформить заказ или Скачать.

Пример использования: У вас есть интернет-магазин, и вы хотите регистрировать событие checkout в момент, когда пользователь нажимает кнопку Оформить заказ в корзине.

Пример нативного взаимодействия пользователя:

<html>
<head>
    <script>
        window.onload = function () {
            document.getElementById('checkout').addEventListener('click', function () {
                AF('pba', 'event', {eventType: 'EVENT', eventValue: {'category' : 'holiday_promotion'}, eventName: 'checkout'});
            });
        }
    </script>
</head>
<body>
    <h1>Корзина</h1>
    <button id='checkout'>Оформление заказа</button>
</body>
</html>

Как это работает:

  1. При загрузке страницы скрипт привязывает обработчик события click к элементу с ID checkout.
  2. Когда пользователь нажимает кнопку, вызывается функция-обработчик обратного вызова.
  3. Функция может извлекать соответствующие данные (например, из localStorage) и передавать их в метод AF().
  4. SDK затем передает событие оформления заказа на платформу AppsFlyer.
Пример: Запишите событие через GTM

Этот метод фиксирует конкретные действия, такие как нажатие кнопки Оформить заказ, используя встроенные переменные и триггеры GTM.

1. Настройка страницы оформления заказа

<html>
<head>
    <script>
        (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
        new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
        j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
        'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
        })(window,document,'script','dataLayer','GTM-XXXX');
    </script>
</head>
<body>
    <h1>Shopping Cart</h1>
    <button id='checkout'>Checkout</button>
</body>
</html>

2. Настройте переменные и триггеры GTM

  1. В GTM нажмите Переменные > Настроить и включите Элемент клика в списке встроенных переменных.
  2. Создайте новую переменную, определяемую пользователем (Тип: Все элементы).
  3. Создайте новый Триггер:
    • Тип триггера: Клик - Все элементы.
    • Этот триггер срабатывает на: Некоторые клики.
    • Условие Элемент клика соответствует CSS селектору #checkout.

3. Создайте тег взаимодействия

  1. Создайте новый тег Пользовательский HTML для действия «Оформление заказа».
  2. Вставьте скрипт взаимодействия:

    <script>
      AF('pba', 'event', {eventType: 'EVENT', eventValue: {'category' : 'holiday_promotion'}, eventName: 'checkout'});
    </script>
  3. Назначьте триггер "Клик по оформлению заказа", который вы создали на предыдущем шаге.
Лучшие практики реализации событий

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

  • Порядок загрузки: Убедитесь, что тег функций Web SDK полностью загружен на странице до выполнения любых вызовов событий.
  • Форматирование данных: Не включайте специальные символы в значения событий. Например, используйте числовые значения для дохода, а не включайте символы валюты (используйте 10.50 вместо $10.50).
  • Ограничения строк: Делайте строки eventValue лаконичными; значения длиннее 3000 символов будут усечены.
  • Дедупликация событий: Рекомендуем передавать af_customer_event_id в eventValue с уникальным значением для каждого события. Это особенно важно, если одно и то же событие отправляется как через Web SDK, так и через API server-to-server (S2S). AppsFlyer передает это значение рекламной сети, которая использует его для дедупликации серверного события, полученного от AppsFlyer, и того же события, полученного через собственный пиксель.
  • Размещение дохода: Заполняйте eventRevenue только для событий, в которых действительно было движение денег, например при покупке или подтвержденной подписке. Для событий с денежным значением, которые не являются фактическим доходом (например, добавление в корзину, начало оформления заказа или просмотр контента), вместо этого используйте af_price и af_currency в eventValue. Если передавать eventRevenue и при оформлении заказа, и при покупке, доход будет учитываться дважды в каждом отчете.
  • Именование событий: Не добавляйте к названиям событий суффиксы платформы, например _web. Платформа уже является измерением в дэшборде и в сырых данных. Используйте те же названия событий, что и в вашем мобильном приложении, чтобы унифицировать кроссплатформенную отчетность.

6. Установить идентификатор пользователя клиента

После настройки измерения событий задайте постоянный идентификатор с помощью setCustomerUserId, чтобы связать веб-активность пользователя с его активностью на других платформах (мобильных устройствах, ПК и CTV) и получить единое представление о его пути на всех платформах.

Ключевые правила

  • Последовательность: Используйте то же значение CUID, что и в ваших мобильных приложениях (см. мобильный setCustomerUserId для: iOS, Android, Unity).
  • Время: Вы можете отправить CUID на любом этапе (например, после входа в систему или регистрации). Установите CUID как можно раньше, как только у вас будет к нему доступ. В большинстве случаев это означает, что вам нужно подождать, пока пользователь пройдет идентификацию через вход или регистрацию.
  • Синтаксис: Отправьте значение как строку (в кавычках). Пример: AF('pba', 'setCustomerUserId', '663274')
  • Конфиденциальность: Не включайте персональные данные (PII), например адреса электронной почты или номера телефонов.
Пример: Установка CUID после регистрации (нативно)

Код, приведенный в этих примерах, приведен только для справки. Не используйте этот код в таком виде. Если вы не знаете, как использовать этот код, проконсультируйтесь со своим веб-разработчиком.

Предполагается, что Web SDK загружен на страницу до отправки события; не загружайте его повторно.

Сценарий пользователя:

  • Пользователь регистрируется на вашем сайте.
  • Код сайта собирает данные пользователя и отправляет их на ваш сервер.
  • Сервер генерирует уникальный CUID для пользователя.
  • На странице «Спасибо» после регистрации вы запрашиваете у сервера новый CUID.
  • Используя ответ сервера, вы устанавливаете CUID AppsFlyer с помощью метода Web SDK setCustomerUserId().

Пример формы регистрации

Код ниже представляет собой простую форму регистрации. При отправке формы адрес электронной почты сохраняется в localStorage. Когда пользователь переходит на страницу «Спасибо», адрес электронной почты пользователя отправляется на сервер для получения уникального CUID для этого адреса.

<html>
<head>
    <script>
!function(t,e,n,s,a,c,i,o,p){t.AppsFlyerSdkObject=a,t.AF=t.AF||function(){
(t.AF.q=t.AF.q||[]).push([Date.now()].concat(Array.prototype.slice.call(arguments)))},
t.AF.id=t.AF.id||i,t.AF.plugins={},o=e.createElement(n),p=e.getElementsByTagName(n)[0],o.async=1,
o.src="https://websdk.appsflyersdk.com?"+(c.length>0?"st="+c.split(",").sort().join(",")+"&":"")+(i.length>0?"af_id="+i:""),
p.parentNode.insertBefore(o,p)}(window,document,"script",0,"AF","pba",{pba: {webAppId: "WEB_DEV_KEY"}})
    </script>
    <script>
        function storeUserEmail() {
            var userEmail = document.getElementById('email').value;
            localStorage.setItem('user_email', userEmail);
        }
    </script>
</head>
<body>
    <h1>Sign Up</h1>
    <form onsubmit="storeUserEmail()" action="/signup" method="post">
        <div><label>Name</label><input type="text" name="name" id="name"></div>
        <br/>
        <div><label>Email</label><input type="email" name="email" id="email"></div>
        <br/>
        <input type="submit" id="submit">
    </form>
</body>
</html>

Пример страницы благодарности

Код использует Fetch API. Он отправляет серверу адрес электронной почты, введенный пользователем. Если при регистрации сервер создает пользователя с уникальным CUID, то при отправке адреса электронной почты на сервер в ответ возвращается уникальный CUID. Сервер отвечает уникальным CUID, и этот уникальный CUID является значением, передаваемым с помощью методаsetCustomerUserId.

<html>
<head>
    <script>
!function(t,e,n,s,a,c,i,o,p){t.AppsFlyerSdkObject=a,t.AF=t.AF||function(){
(t.AF.q=t.AF.q||[]).push([Date.now()].concat(Array.prototype.slice.call(arguments)))},
t.AF.id=t.AF.id||i,t.AF.plugins={},o=e.createElement(n),p=e.getElementsByTagName(n)[0],o.async=1,
o.src="https://websdk.appsflyersdk.com?"+(c.length>0?"st="+c.split(",").sort().join(",")+"&":"")+(i.length>0?"af_id="+i:""),
p.parentNode.insertBefore(o,p)}(window,document,"script",0,"AF","pba",{pba: {webAppId: "WEB_DEV_KEY"}})
    </script>
    <script>
        window.onload = function () {
            var userEmail = localStorage.getItem('user_email');
            fetch('users/' + userEmail).then(function (res) {
                res.text().then(function (id) {
                    console.log(id);
                    AF('pba', 'setCustomerUserId', id);
                });
            });
        }
    </script>
</head>
<body>
    <h1>Thank You for Signing Up!</h1>
</body>
</html>
Пример: Установка CUID после регистрации (Google Tag Manager)
  1. Настройка страницы регистрации.

    Пример кода ниже представляет собой простую форму регистрации. При отправке формы адрес электронной почты сохраняется в localStorage. Когда пользователь переходит на страницу «Спасибо», адрес электронной почты пользователя отправляется на сервер для получения уникального CUID для этого адреса.

    <html>
    <head>
        <script>
            (function (w, d, s, l, i) {
                w[l] = w[l] || []; w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
                var f = d.getElementsByTagName(s)[0], j = d.createElement(s),
                    dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true;
                j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
                f.parentNode.insertBefore(j, f);
            })(window, document, 'script', 'dataLayer', 'GTM-5VJ6C7R');
            function storeUserEmail() {
                var userEmail = document.getElementById('email').value;
                localStorage.setItem('user_email', userEmail);
            }
        </script>
    </head>
    <body>
        <h1>Sign Up</h1>
        <form onsubmit="storeUserEmail()" action="/signup" method="post">
            <div><label>Name</label><input type="text" name="name" id="name"></div>
            <br />
            <div><label>Email</label><input type="email" name="email" id="email"></div>
            <br />
            <input type="submit" id="submit">
        </form>
    </body>
    </html>
  2. Настройте страницу благодарности для пользователей, которые регистрируются: В приведенном ниже коде показана страница благодарности с триггером GTM, который отправляет на сервер адрес электронной почты, указанный пользователем в форме регистрации. Предположим, что при регистрации сервер создает пользователя с уникальным CUID; при отправке на сервер адреса электронной почты он возвращает этот уникальный CUID. Сервер отвечает уникальным CUID, который отправляется с помощью метода setCustomerUserId().

    <script>
        window.onload = function () {
            var userEmail = localStorage.getItem('user_email');
            fetch('users/' + userEmail).then(function (res) {
                res.text().then(function (id) {
                    console.log(id);
                    AF('pba', 'setCustomerUserId', id);
                });
            });
        }
    </script>
  3. Добавьте новый тег для атрибуции подписок после загрузки страницы благодарности.

    Добавление нового тега GTM для события конверсии CUID
  4. Дайте тегу отдельное имя и выберите тип тега Custom HTML.

    Присвоение имени тегу и выбор типа тега «Пользовательский HTML» в GTM
    <script>
        var userEmail = localStorage.getItem('user_email');
        fetch('users/' + userEmail).then(function (res) {
            res.text().then(function (id) {
                console.log(id);
                AF('pba', 'setCustomerUserId', id);
            });
        });
    </script>
  5. Разверните Расширенные настройки и затем Последовательность тегов под текстовой областью и убедитесь, что конверсия настроена на срабатывание после выполнения тега.

    Настройка последовательности тегов в GTM для тега конверсии
  6. Установите триггер для тега конверсии, чтобы указать, когда тег конверсии должен срабатывать (в приведенном ниже примере он срабатывает при загрузке страницы благодарности).

    Настройка триггера GTM для срабатывания тега конверсии при загрузке страницы "Спасибо"

7. Управление конфиденциальностью

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

Согласие на отправку событий или отказ от нее

Вы можете контролировать измерение двумя способами:

Настройка начального состояния SDK (в сниппете)

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

  • Отправить события: {pba: {webAppId: "...", measurementStatus:true}}
  • Не отправлять события: {pba: {webAppId: "...", measurementStatus:false}}

Если measurementStatus пуст или имеет значение NULL, AppsFlyer рассматривает это так, как если бы measurementStatus:true.

Ручное управление

Ручное управление имеет приоритет над настройкой начального состояния и использует постоянные файлы cookie первой стороны:

  • Устанавливается на домене сайта.
  • Срок их действия истекает по прошествии периода, заданного Web SDK или браузером.
  • Всегда зависит от настроек файлов cookie в браузере.

Команды

  • Начать отправлять события (согласие): window.AF_SDK.PLUGINS.PBA.enableMeasurement()
  • Прекратить отправлять события (отказ): window.AF_SDK.PLUGINS.PBA.disableMeasurement()
Защита и фильтрация данных

Если ваш веб-сайт требует строгих протоколов безопасности или конфиденциальности данных, используйте следующие механизмы для настройки взаимодействия Web SDK с вашей средой и вашими данными.

Политика безопасности контента (CSP)

Если ваш веб-сайт требует, чтобы JavaScript был защищен CSP, Web SDK поддерживает два подхода в зависимости от вашей конфигурации CSP и сниппета, который вы выбрали на шаге 2.

  • CSP с директивой self: добавьте [https://websdk.appsflyersdk.com](https://websdk.appsflyersdk.com) в список разрешенных источников директивы script-src. Это работает как для стандартного Web SDK, так и для расширенной проверки SDK.
  • CSP с nonce: если в вашей политике используется script-src 'nonce-...', используйте приведенный ниже вариант расширенной проверки SDK с поддержкой nonce. Это передает nonce всем трем тегам скриптов, которые требуются для процесса проверки. Замените {{CSP_NONCE}} на сгенерированное сервером уникальное значение nonce для каждого запроса.

Таблица ниже показывает, какие политики CSP совместимы с вариантом с расширенным nonce.

Политика Работает Примечание
script-src 'self' Ни один Внешний CDN-источник не разрешен; встроенный скрипт также заблокирован.
script-src 'self' https://websdk.appsflyersdk.com Частичный Разрешает загрузчик и SDK, но встроенный скрипт настройки все еще заблокирован.
script-src 'nonce-...' https://websdk.appsflyersdk.com Да Nonce охватывает встроенный скрипт и загрузчик; тег SDK получает nonce, переданный загрузчиком.
script-src 'nonce-...' 'strict-dynamic' Да (рекомендуется) Nonce охватывает встроенный скрипт и загрузчик; strict-dynamic тем самым переносит доверие на динамически вставляемый тег SDK. CDN-источник не требуется в белом списке.
Совместимость с политикой CSP

Расширенная проверка SDK с фрагментами CSP nonce

Без Smart Banners
<script nonce="{{CSP_NONCE}}">
  // Queue — buffers AF() calls until the SDK is ready
  window.AppsFlyerSdkObject = "AF";
  window.AF = window.AF || function() {
    (window.AF.q = window.AF.q || []).push([Date.now()].concat(Array.prototype.slice.call(arguments)));
  };
  window.AF.id = window.AF.id || { pba: { webAppId: "WEB_DEV_KEY" } };
  window.AF.plugins = {};

  // Manifest loader config — nonce forwarded to the injected SDK <script> tag
  window.AF_LOADER_CONFIG = {
    baseUrl: "https://websdk.appsflyersdk.com",
    plugins: ["pba"],
    nonce: "{{CSP_NONCE}}"
  };

  // Inject manifest loader
  var loaderScript = document.createElement("script");
  loaderScript.src = "https://websdk.appsflyersdk.com/manifestLoader.v1.js";
  loaderScript.integrity = "sha384-Uncl2YwvjFpFz0PwEfl3bL/0JsOQcDFEpwXHzcN0MBavn9vvFEx5pZxADTq8h+CV";
  loaderScript.crossOrigin = "anonymous";
  loaderScript.nonce = "{{CSP_NONCE}}";
  loaderScript.async = true;
  document.head.appendChild(loaderScript);
</script>
С Smart Banners
<script nonce="{{CSP_NONCE}}">
  // Queue — buffers AF() calls until the SDK is ready
  window.AppsFlyerSdkObject = "AF";
  window.AF = window.AF || function() {
    (window.AF.q = window.AF.q || []).push([Date.now()].concat(Array.prototype.slice.call(arguments)));
  };
  window.AF.id = window.AF.id || { pba: { webAppId: "WEB_DEV_KEY" }, banners: { key: "YOUR_BANNER_KEY" } };
  window.AF.plugins = {};

  // Manifest loader config — nonce forwarded to the injected SDK <script> tag
  window.AF_LOADER_CONFIG = {
    baseUrl: "https://websdk.appsflyersdk.com",
    plugins: ["banners", "pba"],
    nonce: "{{CSP_NONCE}}"
  };

  // Inject manifest loader
  var loaderScript = document.createElement("script");
  loaderScript.src = "https://websdk.appsflyersdk.com/manifestLoader.v1.js";
  loaderScript.integrity = "sha384-Uncl2YwvjFpFz0PwEfl3bL/0JsOQcDFEpwXHzcN0MBavn9vvFEx5pZxADTq8h+CV";
  loaderScript.crossOrigin = "anonymous";
  loaderScript.nonce = "{{CSP_NONCE}}";
  loaderScript.async = true;
  document.head.appendChild(loaderScript);
</script>

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

Если параметры запроса URL содержат конфиденциальную информацию, настройте AppsFlyer так, чтобы они не сохранялись (в URL, реферерах и header_referer).

  • Исключать все параметры запроса: добавьте af_url=true
  • Исключатьконкретные параметры: используйте af_url_mask=param (разделяйте несколько параметров с помощью ;)

Например:

  • Оригинал: param1=value1&param2=value2&param3=value3&af_url_mask=param2;param3
  • Результат:param1=value1&af_url_mask=param2;param3

Справочник файлов cookie Web SDK

Web SDK устанавливает или использует следующие файлы cookie:

Имя файла cookie Домен Срок действия Когда применяется Детали
afUserid Домен вашего сайта 395 дней Страницы без технологии Accelerated Mobile Pages (AMP) Идентифицирует пользователя в контексте загрузки веб-страницы и событий навигации.
AF_SYNC Домен вашего сайта 1 неделя Страницы без AMP Указывает, что установлен окончательный идентификатор пользователя. Используется для уменьшения времени загрузки сайта.
af_id appsflyer.com 395 дней Обычные мобильные страницы (не AMP) при разрешенных сторонних cookie Идентифицирует пользователя в контексте событий запуска приложения и навигации
af_id onelink.me 395 дней Обычные мобильные страницы (не AMP) при разрешенных сторонних cookie Связывает взаимодействия с баннерами, взаимодействия с OneLink или оба типа взаимодействий с событиями запуска приложения.
amp-afUserid AMP CDN или домен вашего сайта 1 год Ускоренные мобильные страницы (AMP)
AF_DEFAULT_MEASUREMENT_STATUS Домен вашего сайта 395 дней Страницы без AMP Хранит состояние согласия. Блокирует работу SDK до тех пор, пока пользователь не даст согласие. По умолчанию не установлено. Используется только когда механизм согласия настроен.