AppsFlyer
Adapty обменивается данными с AppsFlyer в обоих направлениях. AppsFlyer сообщает Adapty, из какой кампании пришёл пользователь. Adapty сообщает AppsFlyer, сколько этот пользователь заплатил — покупки, продления, пробные периоды и возвраты с данными о выручке и продуктах.
- Просматривайте полный жизненный цикл подписки, а не только первую покупку. Продления и конвертации триалов — это события стора, для которых нет сессии приложения, чтобы клиентский SDK AppsFlyer мог их зафиксировать. Adapty получает события подписок на стороне сервера и пересылает их в AppsFlyer, поэтому данные по кампаниям обновляются ещё долго после первоначальной установки. Возвраты средств передаются тем же путём, и AppsFlyer вычитает их из доходов кампании.
- Оптимизируйте рекламные кампании с помощью данных о событиях подписок. AppsFlyer передаёт события встроенных покупок из Adapty в ваши рекламные сети в виде постбэков. Сервисы, управляющие вашим рекламным бюджетом, могут оптимизироваться на основе реальных платежей пользователей.
- Фильтруйте аналитику Adapty по кампании. Adapty сохраняет атрибуцию AppsFlyer в каждом профиле — вплоть до группы объявлений и креатива — и графики подписок можно фильтровать по этим данным.
- Показывайте разные пейволы для разных кампаний. Сегменты Adapty фильтруются по тем же полям атрибуции — кампании, группе объявлений и креативу. Используйте сегмент как аудиторию, чтобы подобрать пейвол под рекламу, которая привела пользователя.
В вашем аккаунте Adapty уже есть два инструмента для платных кампаний. Adapty Ads Manager управляет кампаниями Apple Ads; Adapty Attribution охватывает Meta Ads и TikTok. Оба показывают ROAS и LTV прямо из данных о покупках Adapty, и оба бесплатны для старта — подробнее в разделе цен.
Как работает интеграция
Adapty получает данные атрибуции от AppsFlyer и отправляет обратно события подписок. Оба процесса зависят от одного значения: AppsFlyer ID — строки, которую AppsFlyer генерирует при первом запуске вашего приложения.
- Когда пользователь устанавливает ваше приложение, SDK AppsFlyer присваивает ему уникальный ID.
- Ваше приложение передаёт этот ID в Adapty, которая сохраняет его в профиле пользователя как
appsflyer_id. - Ваше приложение также передаёт данные атрибуции AppsFlyer в Adapty, которая сохраняет их в том же профиле.
- Позже, когда пользователь совершает событие подписки — например, начинает пробный период или покупает продукт, — серверы Adapty отправляют это событие в S2S API AppsFlyer с тем же
appsflyer_id. - AppsFlyer сопоставляет ID с установкой, которую уже атрибутировал, и покупка наследует кампанию и источник медиа этой установки.
Инструкции по настройке
Перед началом работы:
- Убедитесь, что ваш тариф AppsFlyer поддерживает S2S in-app события. Пакет начального уровня Zero этого не поддерживает: его API отклоняет каждое событие, которое отправляет Adapty, с ошибкой
403 Forbidden. - Добавьте AppsFlyer SDK в приложение. Идентификатор AppsFlyer, от которого зависит интеграция, появляется только после инициализации этого SDK. Одна лишь серверная интеграция не создаст этот идентификатор.
- Отключите все остальные интеграции атрибуции. Adapty принимает только один источник атрибуции на профиль и не может перезаписать уже существующее значение. На iOS ненативная атрибуция Apple Ads всегда имеет приоритет — см. Выбор единственного источника атрибуции.
Создание S2S-токена в AppsFlyer
Adapty проходит аутентификацию в S2S API AppsFlyer с помощью токена, который вы создаёте. Открыть страницу Tokens могут только администраторы AppsFlyer, поэтому попросите администратора создать токен, если у вашей учётной записи нет прав администратора. Если токен уже есть, перейдите к разделу Настройка Adapty.
-
Войдите в AppsFlyer.
-
Нажмите на имя вашей учётной записи в правом верхнем углу и откройте Security center.
-
На странице Manage your account security найдите карточку AppsFlyer API and S2S tokens и нажмите Manage your AppsFlyer tokens. Откроется страница Tokens.
-
Нажмите New token.
-
Введите Name для токена. Это название только для вашего удобства, его можно изменить позже.
-
Выберите тип токена S2S. Любой другой тип нарушит интеграцию.
-
Нажмите Create new token.
AppsFlyer допускает не более двух токенов каждого типа. Если у вас уже есть два S2S-токена, используйте один из них повторно.
-
Найдите новый токен в списке. AppsFlyer скрывает значение, поэтому нажмите иконку копирования в столбце Token, чтобы получить его.
Настройка Adapty
- Откройте Integrations > AppsFlyer в дашборде Adapty.
- Включите переключатель AppsFlyer.
- Если вы уже подключили приложение к App Store, поле iOS App ID автоматически заполнится числовым Apple ID вашего приложения. Если оно пустое, сначала подключите аккаунт App Store. Для Android аналогичное поле не требуется.
- Вставьте S2S-токен в поле Production раздела S2S key for iOS, S2S key for Android или в оба.
- Заполните поля Sandbox, чтобы тестовые покупки не попадали в производственную статистику — см. Разделение данных песочницы и продакшена.
- В разделе How the revenue data should be send выберите, какое значение выручки Adapty будет отправлять как
af_revenue. Три варианта соответствуют представлениям выручки в Adapty Analytics, поэтому ваш выбор также определяет, с каким именно представлением должны совпадать данные AppsFlyer.
| Вариант | Что отправляет Adapty |
|---|---|
| Gross revenue | Полная сумма, которую заплатил покупатель, до вычета комиссии и налогов. По умолчанию. |
| Proceeds after store commission | Сумма за вычетом комиссии стора, но с учётом налогов. |
| Proceeds after store commission and taxes | Сумма за вычетом и того, и другого. |
- Настройте оставшиеся параметры:
| Переключатель | Когда включён | По умолчанию |
|---|---|---|
| Report user’s currency | Adapty сообщает о каждой продаже в валюте покупателя, а не в USD. | Выкл |
| Send trial price | Триалы не несут дохода в противном случае. Включите, чтобы назначить каждому пробному периоду условную цену; появится поле Trial price percentage — укажите, какую долю от цены подписки должен сообщать триал. При 60% подписка за $10 отправит $6. | Выкл |
| Exclude historical events | Adapty пропускает события, произошедшие до того, как пользователь установил сборку с SDK Adapty. | Вкл |
| Delay events with a future datetime | Apple сообщает о продлениях и конвертациях триалов заранее, поэтому эти события имеют будущую дату. AppsFlyer обычно заменяет её датой поступления события. Включите, чтобы удерживать каждое событие до наступления его даты — см. Продления попадают не в тот день. | Выкл |
-
Переименуйте или отключите отдельные события в разделе Events names — см. Названия событий.
-
Нажмите Save.
Отправка данных из песочницы отдельно от производственных
Чтобы тестовые покупки не попадали в реальную статистику, отправляйте их в отдельное приложение AppsFlyer. Зарегистрируйте второе приложение для dev-сборок и вставьте его токен в поле Sandbox соответствующего раздела платформы.
Adapty распределяет транзакции по окружению: реальные покупки — в приложение с токеном из Production, тестовые — в приложение из Sandbox. Если вы хотите видеть всё в одном приложении, просто вставьте одинаковый токен в оба поля.
Покупки в ходе ревью App Store и через TestFlight являются sandbox-транзакциями, даже если они выполняются в production-сборке. Adapty отправляет такие покупки с ключом Sandbox.
Транзакции из песочницы не отображаются в аналитических графиках. Они по-прежнему видны на страницах отдельных профилей и в ленте событий.
Настройте код вашего приложения
- Зарегистрируйте callback конверсии в AppsFlyer SDK. На iOS реализуйте протокол
AppsFlyerLibDelegate; на Android — интерфейсAppsFlyerConversionListener; на Unity — интерфейсIAppsFlyerConversionData. На React Native и Flutter вместо этого передайте обработчик в методonInstallConversionData. - Дождитесь, пока AppsFlyer вызовет этот callback. AppsFlyer атрибутирует каждую установку на своих серверах, поэтому результат поступает в приложение асинхронно, а не в момент запуска. SDK снова вызывает callback при каждой последующей сессии.
- Внутри callback прочитайте AppsFlyer ID пользователя с помощью
getAppsFlyerUIDи передайте его в Adapty черезsetIntegrationIdentifier(). События Adapty попадают к нужному пользователю AppsFlyer только при наличии этого значения. - Внутри того же callback передайте данные атрибуции AppsFlyer в Adapty через
updateAttribution(). Это сообщает Adapty, какая кампания привела к установке. В iOS и Android SDK 4.1 и выше метод называетсяupdateExternalAttribution(). - Используйте
await Adapty.identify()вместо того, чтобы запускать его параллельно с шагами 3 и 4. Adapty создаёт анонимный профиль при активации, а затем переключается на идентифицированный профиль после завершенияidentify(). Значениеappsflyer_id, установленное в момент этого переключения, не всегда сохраняется.
Полную последовательность вызовов см. в разделах для iOS, Android, React Native, Flutter, Unity, Capacitor и Kotlin Multiplatform.
Сторонние SDK генерируют пользовательские ID асинхронно. ID может быть ещё не готов в момент вызова Adapty.activate(). Если ваш Customer User ID приходит из одного из таких SDK, вызывайте Adapty.activate() без него. Как только ID будет получен, вызовите setIntegrationIdentifier(), а затем identify() с CUID.
Проверьте интеграцию
- Совершите покупку в песочнице и откройте Event Feed вашего приложения. Там отображается каждая попытка доставки. Чтобы увидеть ответ AppsFlyer на неудачную попытку, наведите курсор на нужную строку.
- В AppsFlyer откройте Settings > SDK Integration Tests > Live Events и выберите ваше тестовое устройство. В Live Events S2S-события появляются сразу по мере поступления — задолго до того, как они попадут на дашборд Activity в AppsFlyer.
- Откройте дашборд Activity вашего приложения и проверьте событие, его выручку и источник трафика. Подождите около часа — S2S-события попадают на этот дашборд не сразу.
События Adapty никогда не отображаются в отладочном логе AppsFlyer SDK вашего приложения. Adapty отправляет их со своих серверов, поэтому они не проходят через ваше приложение. Пустой локальный лог ничего не говорит о состоянии интеграции.
Структура событий AppsFlyer
Adapty отправляет один POST-запрос на каждое событие по адресу https://api3.appsflyer.com/inappevent/{app_id}, передавая S2S-токен в заголовке authentication. API 2 использует https://api2.appsflyer.com/inappevent/{app_id}.
{
"appsflyer_id": "1699887556000-6192770",
"eventName": "af_subscribe",
"eventTime": "2026-03-01 12:00:00",
"eventValue": "{\"af_content_id\":\"yearly.premium.6999\",\"af_order_id\":\"GPA.3383-4699-1373-07113\",\"store_country\":\"US\",\"profile_country\":\"US\",\"af_content_type\":\"in_app\",\"af_revenue\":\"9.9900\",\"af_currency\":\"USD\",\"af_quantity\":\"1\"}",
"os": "17.0.1",
"bundleIdentifier": "com.example.app",
"customer_user_id": "user_12345",
"eventCurrency": "USD",
"ip": "192.168.100.1",
"advertising_id": "00000000-0000-0000-0000-000000000000",
"idfa": "00000000-0000-0000-0000-000000000000",
"idfv": "00000000-0000-0000-0000-000000000000",
"att": "3"
}
| Параметр | Тип | Описание |
|---|---|---|
appsflyer_id | String | AppsFlyer ID, который ваше приложение передало в setIntegrationIdentifier. AppsFlyer сопоставляет событие с установкой по этому значению. |
eventName | String | Название из раздела Events names — см. Названия событий. |
eventTime | String | Время возникновения события (UTC, YYYY-MM-DD HH:MM:SS). Adapty заменяет его текущим временем для событий старше 26 часов — см. Старые события приходят с сегодняшней датой. |
eventValue | String | JSON-строка с полями из таблицы ниже. |
os | String | Версия ОС устройства пользователя. |
bundleIdentifier | String | Bundle ID приложения на iOS или имя пакета на Android. |
customer_user_id | String | Customer User ID пользователя. |
eventCurrency | String | Код валюты по ISO 4217, например USD. |
ip | String | IP-адрес пользователя. |
advertising_id | String | Только Android. Google Advertising ID. |
idfa | String | Только iOS. ID для рекламодателей (ID for Advertisers). |
idfv | String | Только iOS. ID для вендоров (ID for Vendors). |
att | String | Только iOS. Статус App Tracking Transparency, от 0 до 3. Adapty отправляет 0, если значение отсутствует. |
eventValue содержит саму покупку. Последние четыре параметра появляются только в событиях, несущих доход:
| Параметр | Тип | Описание |
|---|---|---|
af_content_id | String | ID продукта в сторе. |
af_order_id | String | Оригинальный ID транзакции. |
store_country | String | Страна аккаунта пользователя в сторе. |
profile_country | String | Страна, определённая Adapty по IP-адресу пользователя. |
af_content_type | String | Всегда in_app. |
af_revenue | String | Сумма дохода с точностью до 4 знаков после запятой. Отрицательное значение при возвратах. |
af_currency | String | Валюта af_revenue. |
af_quantity | String | Всегда 1. |
Названия событий
По умолчанию Adapty сопоставляет события с доходами со стандартными названиями событий AppsFlyer, а не отправляет собственные названия как кастомные события. Это важно при пересылке событий в рекламные сети: сеть реагирует на стандартные названия, которые уже распознаёт, — и вам не нужно вручную настраивать маппинг для каждого из них.
| Adapty event | Default AppsFlyer name |
|---|---|
| Subscription started | af_subscribe |
| Subscription renewed | af_subscribe |
| Trial converted | af_subscribe |
| Trial started | af_start_trial |
| Non-subscription purchase | af_purchase |
Все остальные события Adapty сохраняют свои имена, например subscription_refunded. В разделе Events names на странице интеграции AppsFlyer вы можете переименовать любое событие или отключить те, которые вам не нужны. Полный список событий, которые Adapty может отправлять, см. в разделе События.
Ограничения
- Профиль без
appsflyer_idне генерирует события. AppsFlyer сопоставляет событие с установкой, которая создала ID, и считывает кампанию из этой установки. Без него Adapty ничего не отправляет, а Event Feed помечает такие профили — см. События не доходят до AppsFlyer. - Нет ретроспективного заполнения. Adapty начинает передавать события с момента включения интеграции. Прошлые покупки в AppsFlyer не попадают.
- Данные об устройстве в raw data AppsFlyer остаются пустыми. S2S-событие содержит только то, что передано в запросе. Для Device Model, Device Category, Language, Operator, WIFI, App Version и App Name нет S2S-параметров, поэтому они не могут быть заполнены через этот канал.
Устранение неполадок
- События не доходят до AppsFlyer
- Покупки отображаются как органические
- Старые события приходят с сегодняшней датой
- Продления попадают не в тот день
- Выручка в AppsFlyer не совпадает с Adapty Analytics
Failed to authenticateв ленте событийaccess_level_updatedотображается как ошибка в ленте событий
События не доходят до AppsFlyer
Сначала откройте Event Feed. Неудачная доставка показывает ошибку, которую вернул AppsFlyer. Большинство случаев объясняется следующими причинами:
- В профиле нет
appsflyer_id. Убедитесь, что ваше приложение вызываетgetAppsFlyerUIDи передаёт результат вsetIntegrationIdentifierна каждой платформе — см. Настройка кода приложения. - Отсутствует App ID для этой платформы. AppsFlyer идентифицирует каждое приложение по ID, поэтому без него Adapty не отправит ни одного события. Для iOS-событий нужен iOS App ID на странице интеграции; для Android-событий — имя пакета из App settings > Android SDK — см. Настройка Adapty.
- Покупка является транзакцией в песочнице, а Sandbox-ключ не заполнен. См. Исключение данных песочницы из продакшна.
- Событие отключено в разделе Events names.
Успешная доставка не гарантирует, что AppsFlyer сохранит событие. AppsFlyer возвращает 200 OK на любой корректно сформированный запрос, после чего отбрасывает события, чей appsflyer_id не совпадает ни с одной реальной установкой.
Покупки отображаются как органические
Каждый appsflyer_id идентифицирует одну установку, и каждое событие с этим ID наследует атрибуцию установки — кампанию, которая её привела, или ничего, если установка была органической. AppsFlyer требуется 20–30 секунд или больше, чтобы атрибутировать новую установку. Событие, пришедшее раньше этого момента, не имеет атрибуции для наследования, поэтому AppsFlyer помечает его как неатрибутированную органику.
Ожидайте, что покупки при первом запуске будут отображаться как органические — триалы, начатые в течение нескольких секунд после запуска приложения. Чтобы избежать этого, достаточно отложить показ пейвола, пока AppsFlyer не завершит обработку установки.
Если все события выглядят органическими, а не только отдельные покупки при первом запуске, причина в атрибуции, а не в тайминге: другой источник уже зафиксировал профиль первым. См. Выбор единственного источника атрибуции.
Старые события приходят с сегодняшней датой
События могут поступать в Adapty с задержкой по двум причинам:
- Когда App Store Server Notifications отображаются как Delayed в App Store Connect, Apple ставит уведомления в очередь. В результате событие обновления подписки поступает в Adapty значительно позже фактического момента — см. App Store Server Notifications show “Delayed”.
- События с прошедшими датами проходят всегда, когда опция Exclude historical events отключена.
AppsFlyer не принимает слишком старые временны́е метки. Чтобы события обрабатывались корректно, Adapty заменяет eventTime на текущее время для любого события старше 26 часов. Отключить эту перезапись нельзя.
Продления попадают не на тот день
Apple уведомляет Adapty о продлениях и конвертациях триалов заранее, и Adapty немедленно передаёт их с исходным будущим eventTime. AppsFlyer сохраняет будущую временну́ю метку только если она приходится на день получения события — продление, датированное завтрашним числом, получит временну́ю метку сегодняшнего дня прихода.
Включите Delay events with a future datetime в настройках интеграции. Adapty будет удерживать каждое событие до наступления его времени, и AppsFlyer зафиксирует дату, объявленную Apple. См. Временны́е метки событий с датой в будущем.
Доходы в AppsFlyer не совпадают с Adapty Analytics
Adapty и AppsFlyer по-разному считают одни и те же покупки. Именно эти различия объясняют почти все расхождения.
- Обзорный дашборд AppsFlyer группирует доход по дате установки, а графики Adapty — по дате события. В AppsFlyer июльское продление подписки, установленной в январе, засчитывается в январь. Сравнивайте этот дашборд с когортным анализом Adapty, который также группирует доход по месяцу установки. Сырые отчёты AppsFlyer группируются по дате события — их стоит сравнивать с графиками Adapty.
- Покупки из профилей без
appsflyer_idникогда не попадают в AppsFlyer. Они остаются в Adapty Analytics. См. События не доходят до AppsFlyer. - AppsFlyer показывает только те данные о доходе, которые вы выбрали в Adapty. Настройка How the revenue data should be send определяет, что именно Adapty отправляет: валовой доход, выручку или чистый доход. Если сравнивать это с другим представлением Adapty Analytics, разница будет равна комиссии, налогу или обоим сразу.
- Adapty использует часовой пояс отчётности вашего приложения, AppsFlyer получает UTC. Интеграции всегда получают временны́е метки в UTC, независимо от настроек в App Settings. Покупка в 23:30 UTC 1 июля отобразится как 2 июля в Adapty, если ваш часовой пояс отчётности — +02:00.
- В AppsFlyer отсутствуют исторические события. Причин может быть две. Если включён параметр Exclude historical events, история AppsFlyer пользователя начинается с его первого запуска сборки с Adapty. Кроме того, Adapty никогда не восполняет события, обработанные до включения интеграции.
- Покупки в песочнице попадают в приложение AppsFlyer, указанное в ключе Sandbox. Если это продакшн-приложение, тестовые покупки завышают его доход. См. Как не допустить попадания данных песочницы в продакшн.
- События, отключённые в интеграции, никогда не попадают в AppsFlyer. Adapty Analytics по-прежнему их учитывает. Проверьте раздел Events names — отключение
subscription_renewedубирает большую часть дохода для любого работающего приложения.
Failed to authenticate в ленте событий
AppsFlyer отклоняет учётные данные, если они не соответствуют версии API. API 2 ожидает Dev key, API 3 — токен S2S. Если сменить версию, не заменив ключ, эта ошибка будет появляться на каждом событии.
Создайте новый токен в AppsFlyer Security Center и вставьте его в поля S2S key, либо следуйте инструкции Switch from AppsFlyer S2S API 2 to 3.
access_level_updated отображается как ошибка в ленте событий
access_level_updated — это событие только для вебхуков. Adapty не отправляет его в эту интеграцию. Однако Adapty фиксирует результат для каждой активной интеграции, и неподдерживаемое событие отображается как ошибка.