Краткий обзор. Отправляйте в AppsFlyer события со своих серверов, чтобы измерять мобильные события, происходящие вне приложения.
API межсерверных событий для мобильных устройств
Начиная с iOS 14, для приложений iOS требуется отправлять параметр os (операционная система).
Платформа AppsFlyer атрибутирует и записывает события мобильных приложений, отправленных через SDK AppsFlyer и по API. Используйте API S2S для сообщения о событиях, происходящих вне приложения; например, пользователь продлевает свою подписку, используя ваш веб-интерфейс. После регистрации события S2S доступны на всей платформе, включая дэшборды, сырые данные и аналитику. Для веб-событий PBA см. Web S2S для PBA.
AppsFlyer заполняет события S2S следующими значениями:
- Значения, отправленные в сообщении S2S
- Некоторые значения атрибуции установок AppsFlyer, например, время установки и медиа-источник.
Инструкции по использованию API
Создайте свой вызов API, используя информацию, содержащуюся в следующих разделах.
Факты о S2S API
Конечная точка API |
|
HTTP-метод | POST |
Принятый тип контента | application/json |
Авторизация |
|
Серверы в разрешенном списке для получения ответных сообщений |
Если ваши серверы расположены за брандмауэром, добавьте домен appsflyer.com в список разрешенных, чтобы получать ответные сообщения. |
Ограничение размера JSON |
Размер файла JSON: до 1 KB |
Ограничение предоставления данных |
Объем ограничения POST: 60 000 POST в минуту. Чтобы повысить этот лимит, обратитесь к своему менеджеру по работе с клиентами. |
Инструкции по программированию |
|
Кодирование URL |
Закодируйте зарезервированные процентом символы (https://tools.ietf.org/html/rfc3986#section-2.1) перед формированием URL метода. |
TLS |
Используйте TLS 1.2 или выше. Поддерживаемые шифры |
Параметры полезных данных
- В параметры полезных данных входят один или несколько идентификаторов устройств (в зависимости от ОС).
-
Что делать, если я не могу отправить идентификатор устройства?
- Иногда идентификатор нельзя отправить по не зависящим от вас обстоятельствам. Например, потому что пользователь ограничил отслеживание рекламы (LAT) или использует iOS 14 и не дал согласие на ATT. Если IDFV доступен, отправьте его.
- Если не отправлять рекламный идентификатор / идентификатор устройства, могут возникнут следующие проблемы:
- Проблемы с постбэками: медиа-источник будет получать постбэк без идентификатора устройства и, следовательно, не сможет связать его с пользователем.
- Ошибка сегментации аудиторий и применения правил. Для корректной работы наборов правил необходимы идентификаторы. Отправьте идентификатор устройства или идентификатор клиента, в зависимости от типа идентификатора, который используется в вашем наборе правил.
Операционные системы | Имя идентификатора | Описание |
---|---|---|
iOS.
|
idfa |
Когда доступно, введите IDFA устройства. Формат: строка Например: |
idfv |
Когда доступно, введите IDFV устройства. Формат: строка |
|
Android; |
advertising_id |
Когда доступно, введите GAID устройства (рекламный ID) Формат: строка Например: |
oaid |
Формат: строка Например: |
|
amazon_aid |
Формат: строка |
|
imei |
Формат: строка Например: |
Параметр | Обязательный | Описание | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
appsflyer_id |
Да |
Уникальный идентификатор, генерируемый AppsFlyer при первом запуске приложения.
|
|||||||||
customer_user_id |
Нет |
Идентификатор клиента, уникальный идентификатор пользователя, заданный владельцем приложения.
|
|||||||||
att |
Нет |
iOS Статус авторизации ATTrackingManager
Внимание! Мы рекомендуем указывать для параметра |
|||||||||
ip |
Нет |
IP-адрес мобильного устройства во время события.
|
|||||||||
Устаревшее |
|
||||||||||
eventName |
Да |
Определите имя события. Убедитесь, что имена событий соответствуют требованиям маркетолога.
|
|||||||||
Значение события |
Да |
Если нужно отправить событие без значения, то передайте просто:
|
|||||||||
app_version_name |
Нет |
Версия вашего приложения или идентификатор.
|
|||||||||
app_store |
Нет |
Эквивалентно AF_STORE в приложениях для Android. Магазин, из которого было скачано приложение.
|
|||||||||
Event Time (Время события) |
Нет |
Время, когда произошло событие, используя часовой пояс UTC.
Закрытие дня:
Пример
|
|||||||||
eventCurrency |
Нет |
Код валюты с использованием 3-символьных кодов ISO 4217 и BCN (биткойн)
|
|||||||||
bundleIdentifier |
Нет* |
Уникальный идентификатор приложения. В сырых данных параметр заполняет Bundle ID (идентификатор пакета). [Рекомендация] Всегда заполняйте этот параметр. Многие рекламные сети требуют это значение для оптимизации кампаний.
|
|||||||||
sharing_filter |
Нет |
Фильтр общего доступа блокирует доступ к событиям S2S через постбэки / API для интегрированных партнеров и других сторонних интеграций. Используйте фильтр для соблюдения нормативных требований, таких как GDPR и CCPA, для реализации механизмов отказа пользователей от предоставления данных и по другим причинам бизнес-логики. У sharing_filter есть следующие параметры:
Чтобы получить список идентификаторов партнеров, обратитесь к вашему CSM или в службу поддержки AppsFlyer. |
|||||||||
custom_dimension |
Нет |
Зарезервировано AppsFlyer для использования в будущем |
|||||||||
app_type |
Нет |
Для приложений iOS. Допустимое значение: Если пользовательское событие происходит в app_clip, отправьте параметр. Во всех остальных случаях параметр отправлять не нужно. |
|||||||||
custom_data |
Нет |
Отправка индивидуально настраиваемых данных на платформу AppsFlyer. Аналогично отправке данных из SDK с помощью В сырых данных: заполняет поле Формат: JSON, как в следующем примере. Пример:
|
|||||||||
os |
Нет** |
Версия операционной системы устройства. Считайте этот параметр обязательным для всех платформ. Формат: строка Пример: Внимание! Начиная с 1 июля 2021 года, если вы не отправляете этот параметр для приложений iOS, то мы считаем, что данные получены с устройства с iOS 14.5. |
|||||||||
aie |
Нет |
Используйте этот флажок, чтобы указать, запретил ли пользователь предоставлять свой идентификатор рекламодателя. Используйте это поле для устройств под управлением Android (все версии) или iOS до 14 версии. Внимание! Для iOS 14.5+ используйте параметр att. Заполните это поле следующим образом:
|
|||||||||
*Необходим многим рекламным сетям для оптимизации **Этот параметр требуется отправлять для корректной обработки данных. В соответствии с принципом обратной совместимости мы не требуем этого в обязательном порядке, поэтому он не помечен как обязательный. |
Пример curl
curl --location --request POST 'https://api2.appsflyer.com/inappevent/<app_id_placeholder>' \
--header 'authentication: <dev_key_placeholder>
' \
--header 'Content-Type: application/json' \
--data-raw '{
"appsflyer_id": "9999999999999-9999999999999999999",
"advertising_id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
"customer_user_id" : "example_customer_id_123",
"ip": "199.0.2.1",
"app_version_name" : "example_version_name",
"eventTime" : "2020-02-25 12:00.000",
"eventName": "af_purchase",
"eventCurrency": "ZAR",
"os" : "14.6",
"att" : 3,
"eventValue":
"{
\"af_revenue\": \"1006\",
\"af_content_type\": \"wallets\",
\"af_content_id\": \"15854\",
\"af_quantity\" :\"1\"
}"
}
'
Коды ответа
Код ответа | Сообщение | Способ устранения |
---|---|---|
200 | OK |
При получении сообщения выполняется минимальная валидация данных. Таким образом, вы можете получить ответ ОК, даже если событие не будет полностью записано в AppsFlyer. Для отладки событий:
|
400 | Failed to Authenticate | Убедитесь, что ключ аутентификации правильный. |
400 | appsflyer_id is a mandatory field |
|
401 | Не авторизовано | Когда ключ, предоставленный в заголовке аутентификации, не является ключом <dev_key> для этого приложения. |
400 | Bad request |
Когда запрос не прошел как минимум один из критериев валидации. |
400 | Payload is missing or failed to parse |
|
500 | Internal Server Error | Убедитесь, что данные JSON преобразованы в строки и правильно отформатированы. |
Тестирование
Рассмотрим:
- Для тестирования используйте идентификатор AppsFlyer для неорганической установки, чтобы тестировать атрибуты событий в реальном времени. Органические события атрибутируются с задержкой в несколько часов.
- Некоторые поля события заполняются с использованием события атрибуции установки пользователем. Например, время установки и медиа-источник.
Чтобы атрибутировать тестовое устройство как неорганическую установку:
- Подготовьте настраиваемую ссылку атрибуции для тестирования сообщений S2S. Установите для параметра медиа-источника в ссылке значение s2s_test и задайте рекламный идентификатор (GAID, IDFA и т. п.) в ссылке, как показано во фрагментах кода примера ссылки атрибуции.
- Регистрация тестового устройства
- Удалите приложение с тестового устройства.
- Отправьте ссылку на тестовое устройство.
- Щелкните ссылку.
- Установите и запустите приложение.
- На дэшборде проверьте, что установка атрибутирована.
- Получите AppsFlyer ID для использования в вашем сообщении S2S.
Чтобы отправить тестовое сообщение S2S:
- Подготовьте сообщение S2S, используя назначенный идентификатор AppsFlyer. См. ниже примеры кода.
- Отправьте сообщение.
- Выполните одно из следующих действий, чтобы увидеть, как сообщение записывается в AppsFlyer:
- Загрузите отчетсырых данных о внутренних событиях приложения. После отправки события, данные о нем появятся в отчете сырых данных через 15 минут.
- Push API (рассмотрите возможность использования таких инструментов, как Postman и Webhook).
- Проверьте и просмотрите, что:
- Значения, отправленные в сообщении S2S, правильно заполняют отчет. Обратите особое внимание на поля «Дата события», «Валюта события», «Доход от события» и «Значение события».
- Источник атрибуции и время установки заполняются AppsFlyer.
- Значения, предоставляемые самим SDK, такие как версия SDK, не заполняются.
Пример ссылки атрибуции
Android;
https://app.appsflyer.com/<app_id>?pid=s2s_test&c=test&advertising_id=<GAID>
iOS.
https://app.appsflyer.com/<app_id>?pid=s2s_test&c=test&idfa=<IDFA>
Пример кода для отправки сообщений S2S
/* using the okhttp package
install from maven https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp */
import okhttp3.*;
import java.io.IOException;
public class SendRequest {
public static void main(String[] args) {
OkHttpClient client = new OkHttpClient();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, " +
"{\r\n\t\"appsflyer_id\": \"<APPS_FLYER_ID>\"," +
"\r\n\t\"customer_user_id\": \"123456\",\r\n\t\"eventName\": \"af_purchase\",\r\n\t\" +
"eventValue\": \"{\\\"af_revenue\\\":\\\"6\\\" ,\\\"af_content_id\\\":\\\"15854\\\"}\",\r\n\t\" +
"af_currency\": \"USD\",\r\n\t\" +
"eventTime\": \"2018-08-10 4:17:00.000\",\r\n\t\");
Request request = new Request.Builder()
.url("https://api2.appsflyer.com/inappevent/<APP_ID>")
.post(body)
.addHeader("Content-Type", "application/json")
.addHeader("authentication", "<YOUR_DEV_KEY>")
.build();
try {
Response response = client.newCall(request).execute();
System.out.println(response.code());
System.out.println(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
''' using the requests python package, install using pip install requests '''
import requests
url = "https://api2.appsflyer.com/inappevent/[Insert app ID here]"
payload = "{\r\n \"appsflyer_id\": \"9999999999999999999999\",\r\n\t\"IDFA\":\"999999999999999999999999\",\r\n\t\"customer_user_id\" : \"14mar\",\r\n\t\"ip\": \"10.0.0.1\",\r\n\t\"app_version_name\" : \"example_version_name\",\r\n\t\"eventTime\" : \"2020-04-25 08:59:01.23\",\r\n\t\"eventName\": \"gaf_purchase\",\r\n\t\"eventCurrency\": \"ZAR\",\r\n\t\"eventValue\": \r\n\t\"{\r\n\t\t\\\"af_revenue\\\": \\\"1000\\\",\r\n\t\t\\\"af_content_type\\\": \\\"wallets\\\",\r\n\t\t\\\"af_content_id\\\": \\\"15854\\\",\r\n\t\t\\\"af_quantity\\\" :\\\"1\\\"\r\n }\"\r\n}"
headers = {
'authentication': '[Insert dev key]',
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data = payload)
print(response.text.encode('utf8'))
/* using the request npm package, install using npm install request */
var request = require("request");
var options = { method: 'POST',
url: 'https://api2.appsflyer.com/inappevent/<APP_ID>',
headers:
{
"authentication": '<YOUR_DEV_KEY>',
'Content-Type': 'application/json'
},
body:
{ appsflyer_id: '<APPS_FLYER_ID>',
customer_user_id: '123456',
eventName: 'node_js',
eventValue: '{"node_js":"6" ,"af_content_id":"15854"}',
eventCurrency: 'USD',
ip: '1.0.0.0',
eventTime: '2018-07-09 4:17:00.000'
},
json: true };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
/* using the RestSharp package, install using NuGet */
using System;
using RestSharp;
namespace CS
{
class Event
{
static void Main(string[] args)
{
var client = new RestClient("https://api2.appsflyer.com/inappevent/<APP_ID>");
var request = new RestRequest(Method.POST);
request.AddHeader("authentication", "<YOUR_DEV_KEY>");
request.AddHeader("Content-Type", "application/json");
var body = "{\"appsflyer_id\": \"<APPS_FLYER_ID>\"," +
"\"customer_user_id\": \"123456\"," +
"\"eventName\": \"af_purchase\"," +
"\"eventValue\": \"{\\\"af_revenue\\\":\\\"6\\\" ,\\\"af_content_id\\\":\\\"15854\\\"}\"," +
"\"eventCurrency\": \"USD\"," +
"\"eventTime\": \"2018-07-08 4:17:00.000\"
}";
request.AddParameter("undefined", body, ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
// handle response by reading response.StatusCode
Console.WriteLine(response.Content);
}
}
}
$purchase_event = array(
'appsflyer_id' => <APPS_FLYER_DEVICE_ID>,
'idfa' => <IDFA>,
'eventCurrency' => <PURCHASE_CURRENCY>,
'ip' => <DEVICE_ID_ADDRESS>,
'eventTime' => date("Y-m-d H:i:s.000", time())
);
$purchase_event['eventName'] = 'af_purchase';
$purchase_event['eventValue'] = json_encode(array('af_revenue' => <PURCHASE_REVENUE>,
'af_price' => <PURCHASE_PRICE>,
'af_order_id' => <PURCHASE_ORDER_ID>,
'af_currency' => <PURCHASE_CURRENCY>,
'af_content_type' => <PURCHASE_TYPE>,
'af_quantity' => <PURCHASE_QUANTITY>,
'af_content' => <PRODUCT_NAME>,
'af_content_id' => <PRODUCT_ID>),
JSON_UNESCAPED_UNICODE);
$data_string = json_encode($purchase_event);
$ch = curl_init('https://api2.appsflyer.com/inappevent/<YOUR_APP_ID>');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'authentication: <YOUR_APPS_FLYER_DEV_TOKEN>',
'Content-Length: ' . strlen($data_string))
);
$result = curl_exec($ch);
$curl = curl_init();
Отправка рекламного идентификатора / идентификатора устройства важна
- Рекламный идентификатор / идентификатор устройства является обязательным для отправки постбэков в сети SRN, такие как Facebook и Google Ads. Если вы не можете отправить идентификатор, примите во внимание, что нельзя отправлять постбэки.
- Если вы отправите только идентификатор AppsFlyer, внутренние события приложения будут записываться и атрибутироваться правильно.
Заполнение параметров
Разница между органическими и неорганическими событиями
Когда AppsFlyer обрабатывает события S2S в приложении, поля атрибуции заполняются с помощью идентификатора AppsFlyer, чтобы определить соответствующее событие установки, которое предшествовало событиям в приложении.
Это означает, что некоторые данные, которые AppsFlyer связывает с неорганическими S2S-событиями, не будут связаны с органическими S2S-событиями в приложении.
Пример
Например, если сравнить отчеты о необработанных данных для неорганических и органических S2S-событий, можно заметить, что неорганические события содержат данные, которых нет в органических событиях.
Неорганические внутренние события приложения содержат данные о медиа-источнике, кампании, атрибутированном типе и времени взаимодействия.
Что касается органических событий приложения, то они происходят после органической установки. Органические установки не содержат данных о кампании, медиа-источнике, атрибутированном типе взаимодействия и времени установки.
Сопоставление идентификатора AppsFlyer ID с идентификатором клиента (CUID)
Логическая схема на стороне сервера необходима для того, чтобы получить определенные значения для указанного параметра. Ниже описано, как вы можете получить идентификатор AppsFlyer:
- Идентификатор AppsFlyer является обязательным и используется для атрибуции событий.
- Он генерируется, когда пользователь впервые устанавливает мобильное приложение.
- Чтобы вы могли сопоставить свой CUID с идентификатором AppsFlyer, вам нужно задать CUID в приложении.
Простой способ сопоставления пользователей с выполненными ими событиями приведен ниже.
- Задайте идентификатор клиента при установке приложения пользователем.
- Отчеты по сырым данным AppsFlyer содержат CUID и идентификатор AppsFlyer. Используйте один из инструментов доставки данных или AppsFlyer Push API.
- Используйте отчеты о сырых данных, чтобы сопоставить CUID с идентификатором AppsFlyer.
- Идентификаторы AppsFlyer можно получить с помощью SDK AppsFlyer, интегрированных в ваши приложения (Android / IOS).
- Сопоставьте идентификатор AppsFlyer с идентификатором клиента во внутренних системах (важно для использования в будущем).
Сопоставив идентификатор AppsFlyer с CUID, вы можете определить пользователя, выполнившего события. Затем вы сможете получить другие значения (значение события, валюту события, время события и т.д.) и отправить внутреннее событие приложения от сервера к серверу.
Пример тела запроса
{
"appsflyer_id": "1415211453000-6513894",
"advertising_id": "38412345-8cf0-aa78-b23e-10b96e40000d",
"eventName": "af_purchase",
"eventValue":
"{
\"af_revenue\": \"6\",
\"af_currency\" \"USD"\",
\"af_content_type\": \"wallets\",
\"af_content_id\": \"15854\",
\"af_quantity\" :\"1\"
}",
"eventCurrency": "USD",
"ip": "1.2.3.4",
"eventTime": "2014-05-15 12:17:00.000"
}
В этом случае AppsFlyer получает межсерверное (S2S) внутреннее событие, которое представляет собой покупку с доходом, вместе с дополнительными свойствами, например, тип контента и пр.
Получение идентификатора AppsFlyer ID
В сообщениях межсерверных событий параметр appsflyer_id
является обязательным. AppsFlyer использует данный параметр для атрибуции события исходному устройству и атрибутированному медиа-источнику. Вы можете получить ID одним из следующих способов:
- С мобильного устройства путем вызова API SDK AppsFlyer: Android, iOS.
- От платформы AppsFlyer с использованием одного из следующих способов: Pull API, Push API, Экспорт отчета по сырым данным об установках
Совет
Если при тестировании сообщений S2S вы используете сырые данные, ищите запись с медиа-источником "s2s_test". Это ваше тестовое устройство, а его идентификатор устройства AppsFlyer — это необходимый ID.
Отправка данных об отрицательной выручке
События с отрицательным значением дохода могут быть отправлены. Например, если покупка была отменена. Параметр af_revenue
может иметь отрицательные значения для записи этого события.
Если вы заполняете af_quantity
, возможно, вы захотите заполнить его отрицательным значением в зависимости от логики вашей системы. AppsFlyer не использует af_quantity
.
Примеры данных об отрицательной выручке
{
"eventName": "cancel_purchase",
"eventValue":
"{
\"af_revenue\": \"-6\",
\"af_content_type\": \"wallets\",
\"af_content_id\": \"15854\",
\"af_quantity\" :\"1\"
}",
"eventCurrency": "USD",
}
Устранение неполадок
События не отображаются в дэшборде
- Конечная точка: убедитесь, что используемая конечная точка верна.
- Убедитесь, что полезные данные содержат обязательные параметры. См. здесь.
- Убедитесь, что AppsFlyer ID, используемый для запуска события, является действительным идентификатором appsflyer_id, который установлен в конкретном приложении. Что это не тестовый идентификатор, представленный в документации. См. здесь.
- Для S2S-событий групповая отправка событий в одном запросе S2S не поддерживается. Каждое событие необходимо отправлять отдельно.
- На обзорном дэшборде диапазон дат относится к дате установки приложения (LTV), а не к дате события.
- Убедитесь, что вы ввели правильный диапазон дат.
- Убедитесь, что диапазон дат на дэшборде соответствует дате установки устройства (appsflyer_id), а не дате события.
- Отчет по сырым данным о событиях: диапазон дат относится к дате события, а не дате установки.
События не содержат доход
Если после отправки S2S-событий окажется, что данные о доходе не записаны, убедитесь, что отправленные данные в формате JSON преобразованы в строки. Самое важное — это значение параметра события в формате JSON. Он должен быть преобразован в строку, как показано на следующем примере.
"{\"af_revenue\":\"6\" ,\"af_content_type\":\"wallets\"}"
Если значение события не преобразовано в строку, оно обрабатывается неправильно и величина дохода не записывается.
Значения дохода не должны форматироваться. Они могут содержать десятичный разделитель. Не используйте знаки/коды валют или разделители в виде запятой ,
. Доход может иметь префикс -
.
- Пример допустимых значений:
123
,-123.45
,123.456
- Примеры недопустимых значений:
1,234.56
,1,234
В событиях S2S заполнены не все поля
Поля сырых данных заполняются с использованием значения, отправленного в вызове S2S, а некоторые поля заполняются с помощью события установки. Аналогичное поведение, но не идентичное, наблюдается для событий в приложении, сообщаемых с помощью AppsFlyer SDK. Существуют некоторые различия, в частности, следующие поля не заполняются для событий S2S:
- wifi
- operator
- language
- Тип устройства
- Категория устройства
- Версия приложения: используйте
app_version_name
. - Имя приложения