При чтении документации Privacy Sandbox для Android используйте кнопку Developer Preview или Beta , чтобы выбрать версию программы, с которой вы работаете, поскольку инструкции могут отличаться.
API отчетов об атрибуции разработан для обеспечения улучшенной конфиденциальности пользователей путем устранения зависимости от кросс-партийных идентификаторов пользователей и для поддержки ключевых вариантов использования для измерения атрибуции и конверсии в приложениях. В этом руководстве разработчика описывается, как настроить и протестировать API отчетов об атрибуции для регистрации кликов по рекламе, просмотров и конверсий путем вызова методов, которые регистрируют соответствующие триггеры и источники для таких событий.
Это руководство научит вас, как настроить конечные точки сервера и создать клиентское приложение, которое вызывает эти службы. Узнайте больше об общем дизайне API Attribution Reporting в предложении по дизайну .
Ключевые термины
- Источники атрибуции относятся к кликам или просмотрам.
- Триггеры — это события, которые можно отнести к конверсиям.
- Отчеты содержат данные о триггере и соответствующем источнике атрибуции. Эти отчеты отправляются в ответ на события триггера. API отчетов об атрибуции поддерживает отчеты на уровне событий и агрегируемые отчеты .
Прежде чем начать
Чтобы использовать API Attribution Reporting, выполните задачи на стороне сервера и клиента, перечисленные в следующих разделах.
Настройка конечных точек API Attribution Reporting
API Attribution Reporting требует набора конечных точек, к которым можно получить доступ с тестового устройства или эмулятора. Создайте одну конечную точку для каждой из следующих задач на стороне сервера:
- Зарегистрируйте источник атрибуции (просмотреть или нажать)
- Регистрация триггера (конверсии)
- Принимать отчеты на уровне событий
- Принимать агрегированные отчеты
Существует несколько методов настройки требуемых конечных точек:
- Самый быстрый способ приступить к работе — развернуть определения служб OpenAPI v3 из нашего репозитория образцов кода на платформе mock или микросервисов. Вы можете использовать Postman , Prism или любую другую платформу mock-сервера, которая принимает этот формат. Разверните каждую конечную точку и отслеживайте URI для использования в вашем приложении. Чтобы проверить доставку отчета, обратитесь к вызовам, которые ранее были сделаны на платформе mock или serverless.
- Запустите свой собственный автономный сервер, используя пример Kotlin на основе Spring Boot . Разверните этот сервер на вашем облачном провайдере или во внутренней инфраструктуре.
- Используйте определения служб в качестве примеров для интеграции конечных точек в существующую систему.
Принять регистрацию источника
К этой конечной точке должен быть возможен адрес URI, аналогичный следующему:
https://adtech.example/attribution_source
Когда клиентское приложение регистрирует источник атрибуции , оно предоставляет URI для этой конечной точки сервера. Затем API отчетов об атрибуции делает запрос и включает один из следующих заголовков:
Для событий щелчка:
Attribution-Reporting-Source-Info: navigation
Для просмотра событий:
Attribution-Reporting-Source-Info: event
Настройте конечную точку сервера для ответа следующим образом:
// Metadata associated with attribution source.
Attribution-Reporting-Register-Source: {
"destination": "[app package name]",
"web_destination": "[eTLD+1]",
"source_event_id": "[64 bit unsigned integer]",
"expiry": "[64 bit signed integer]",
"event_report_window": "[64-bit signed integer]",
"aggregatable_report_window": "[64-bit signed integer]",
"priority": "[64 bit signed integer]",
"filter_data": {
"[key name 1]": ["key1 value 1", "key1 value 2"],
"[key name 2]": ["key2 value 1", "key2 value 2"],
// Note: "source_type" key will be automatically generated as
// one of {"navigation", "event"}.
},
// Attribution source metadata specifying histogram contributions in aggregate
// report.
"aggregation_keys": {
"[key1 name]": "[key1 value]",
"[key2 name]": "[key2 value]",
},
"debug_key": "[64-bit unsigned integer]",
"debug_reporting": [boolean]
}
// Specify additional ad tech URLs to register this source with.
Attribution-Reporting-Redirect: <Ad Tech Partner URI 1>
Attribution-Reporting-Redirect: <Ad Tech Partner URI 2>
Вот пример с добавленными образцами значений:
Attribution-Reporting-Register-Source: {
"destination": "android-app://com.example.advertiser",
"source_event_id": "234",
"expiry": "259200",
"event_report_window": "172800",
"aggregatable_report_window": "172800",
"priority": "5",
"filter_data": {
"product_id": ["1234"]
},
"aggregation_keys": {
// Generates a "0x159" key piece named (low order bits of the key) for the key
// named "campaignCounts".
// User saw an ad from campaign 345 (out of 511).
"campaignCounts": "0x159",
// Generates a "0x5" key piece (low order bits of the key) for the key named
// "geoValue".
// Source-side geo region = 5 (US), out of a possible ~100 regions.
"geoValue": "0x5",
},
// Opts in to receiving verbose debug reports
"debug_reporting": true
}
Attribution-Reporting-Redirect:
https://adtechpartner1.example?their_ad_click_id=567
Attribution-Reporting-Redirect:
https://adtechpartner2.example?their_ad_click_id=890
Если Attribution-Reporting-Redirects
содержит URI партнеров по рекламным технологиям, API Attribution Reporting затем делает аналогичный запрос к каждому URI. Каждый партнер по рекламным технологиям должен настроить сервер, который отвечает этими заголовками:
Attribution-Reporting-Register-Source: {
"destination": "[app package name]",
"web_destination": "[eTLD+1]",
"source_event_id": "[64 bit unsigned integer]",
"expiry": "[64 bit signed integer]",
"event_report_window": "[64-bit signed integer]",
"aggregatable_report_window": "[64-bit signed integer]",
"priority": "[64 bit signed integer]",
"filter_data": {
"[key name 1]": ["key1 value 1", "key1 value 2"],
"[key name 2]": ["key2 value 1", "key2 value 2"],
// Note: "source_type" key will be automatically generated as
// one of {"navigation", "event"}.
},
"aggregation_keys": {
"[key1 name]": "[key1 value]",
"[key2 name]": "[key2 value]",
}
}
// The Attribution-Reporting-Redirect header is ignored for ad tech partners.
Принять регистрацию триггера конверсии
К этой конечной точке должен быть возможен адрес URI, аналогичный следующему:
https://adtech.example/attribution_trigger
Когда клиентское приложение регистрирует событие-триггер , оно предоставляет URI для этой конечной точки сервера. Затем API Attribution Reporting делает запрос и включает один из следующих заголовков:
Настройте конечную точку сервера для ответа следующим образом:
// Metadata associated with trigger.
Attribution-Reporting-Register-Trigger: {
"event_trigger_data": [{
// "trigger_data returned" in event reports is truncated to
// the last 1 or 3 bits, based on conversion type.
"trigger_data": "[unsigned 64-bit integer]",
"priority": "[signed 64-bit integer]",
"deduplication_key": "[signed 64-bit integer]",
// "filter" and "not_filters" are optional fields which allow configuring
// event trigger data based on source's filter_data. They consist of a
// filter set, which is a list of filter maps. An event_trigger_data object
// is ignored if none of the filter maps in the set match the source's
// filter data.
// Note: "source_type" can be used as a key in a filter map to filter based
// on the source's "navigation" or "event" type. The first
// Event-Trigger that matches (based on the filters/not_filters) will be
// used for report generation. If none of the event-triggers match, no
// event report will be generated.
"filters": [{
"[key name 1]": ["key1 value 1", "key1 value 2"],
// If a key is missing from filters or source's filter_data, it won't be
// used during matching.
"[key name 2]": ["key2 value 1", "key2 value 2"],
}],
"not_filters": [{
"[key name 1]": ["key1 value 1", "key1 value 2"],
// If a key is missing from not_filters or source's filter_data, it won't
// be used during matching.
"[key name 2]": ["key2 value 1", "key2 value 2"],
}]
}],
// Specify a list of dictionaries that generates aggregation keys.
"aggregatable_trigger_data": [
// Each dictionary entry independently adds pieces to multiple source keys.
{
"key_piece": "[key piece value]",
"source_keys": ["[key name the key piece value applies to]",
["list of IDs in source to match. Non-matching IDs are ignored"]]
// filters/not_filters are optional fields similar to event trigger data
// filter fields.
"filters": [{
"[key name 1]": ["key1 value 1", "key1 value 2"]
}],
"not_filters": [{
"[key name 1]": ["key1 value 1", "key1 value 2"],
"[key name 2]": ["key2 value 1", "key2 value 2"],
}]
},
..
],
// Specify an amount of an abstract value which can be integers in [1, 2^16]
// to contribute to each key that is attached to aggregation keys in the
// order they are generated.
"aggregatable_values": [
// Each source event can contribute a maximum of L1 = 2^16 to the
// aggregate histogram.
{
"[key_name]": [value]
},
..
],
aggregatable_deduplication_keys: [{
deduplication_key": [unsigned 64-bit integer],
"filters": {
"category": [filter_1, …, filter_H]
},
"not_filters": {
"category": [filter_1, …, filter_J]
}
},
...
{
"deduplication_key": [unsigned 64-bit integer],
"filters": {
"category": [filter_1, …, filter_D]
},
"not_filters": {
"category": [filter_1, …, filter_J]
}
}
]
"debug_key": "[64-bit unsigned integer]",
"debug_reporting": [boolean]
}
// Specify additional ad tech URLs to register this trigger with.
// Repeated Header field "Attribution-Reporting-Redirect"
Attribution-Reporting-Redirect: <Ad Tech Partner URI 1>
Attribution-Reporting-Redirect: <Ad Tech Partner URI 2>
Вот пример с добавленными образцами значений:
Attribution-Reporting-Register-Trigger: {
"event_trigger_data": [{
"trigger_data": "1122", // Returns 010 for CTCs and 0 for VTCs in reports.
"priority": "3",
"deduplication_key": "3344"
"filters": [{ // Filter strings can't exceed 25 characters
"product_id": ["1234"],
"source_type": ["event"]
}]
},
{
"trigger_data": "4", // Returns 100 for CTCs and 0 for VTCs in reports.
"priority": "3",
"deduplication_key": "3344"
"filters": [{ // Filter strings can't exceed 25 characters
"product_id": ["1234"],
"source_type": ["navigation"]
}]
}],
"aggregatable_trigger_data": [
// Each dictionary independently adds pieces to multiple source keys.
{
// Conversion type purchase = 2 at a 9-bit offset, i.e. 2 << 9.
// A 9-bit offset is needed because there are 511 possible campaigns,
// which takes up 9 bits in the resulting key.
"key_piece": "0x400",// Conversion type purchase = 2
// Apply this key piece to:
"source_keys": ["campaignCounts"]
// Filter strings can't exceed 25 characters
},
{
// Purchase category shirts = 21 at a 7-bit offset, i.e. 21 << 7.
// A 7-bit offset is needed because there are ~100 regions for the geo
// key, which takes up 7 bits of space in the resulting key.
"key_piece": "0xA80",
// Apply this key piece to:
"source_keys": ["geoValue", "nonMatchingIdsAreIgnored"]
// source_key values must not exceed the limit of 25 characters
}
],
"aggregatable_values":
{
// Privacy budget for each key is L1 / 2 = 2^15 (32768).
// Conversion count was 1.
// Scale the count to use the full budget allocated: 1 * 32768 = 32768.
"campaignCounts": 32768,
// Purchase price was $52.
// Purchase values for the app range from $1 to $1,024 (integers only).
// Scaling factor applied is 32768 / 1024 = 32.
// For $52 purchase, scale the value by 32 ($52 * 32 = $1,664).
"geoValue": 1664
}
,
// aggregatable_deduplication_keys is an optional field. Up to 50 "keys"
// can be included in the aggregatable_deduplication_keys list. Filters, not
// filters, and deduplication_key are optional fields. If deduplication_key
// is omitted, it will be treated as a null value. See
// https://wicg.github.io/attribution-reporting-api/#triggering-aggregatable-attribution
aggregatable_deduplication_keys:
[
{
deduplication_key": 3,
"filters": {
"category": [A]
}
},
{
"deduplication_key": 4,
"filters": {
"category": [C, D]
},
"not_filters": {
"category": [F]
}
}
]
// Opts into receiving verbose debug reports
"debug_reporting": true
}
Attribution-Reporting-Redirect:https://adtechpartner.example?app_install=567
Существует ограничение в 25 байт на идентификатор ключа агрегации и строку фильтра. Это означает, что ваши идентификаторы ключей агрегации и строки фильтра не должны превышать 25 символов. В этом примере campaignCounts
составляет 14 символов, поэтому это допустимый идентификатор ключа агрегации, а 1234
составляет 4 символа, поэтому это допустимая строка фильтра. Если идентификатор ключа агрегации или строка фильтра превышает 25 символов, триггер игнорируется.
Если Attribution-Reporting-Redirect
содержит URI партнеров по рекламным технологиям, API Attribution Reporting затем делает аналогичный запрос к каждому URI. Каждый партнер по рекламным технологиям должен настроить сервер, который отвечает этими заголовками:
// Metadata associated with trigger.
Attribution-Reporting-Register-Trigger: {
"event_trigger_data": [{
// "trigger_data" returned in event reports is truncated to
// the last 1 or 3 bits, based on conversion type.
"trigger_data": "[unsigned 64-bit integer]",
"priority": "[signed 64-bit integer]",
"deduplication_key": "[signed 64-bit integer]",
// filter and not_filters are optional fields which allow configuring
// different event trigger data based on source's filter_data. They
// consist of a filter set, which is a list of filter maps. An
// event_trigger_data object is ignored if none of the filter maps in the
// set match the source's filter data. Note: "source_type" can be used as
// a key in a filter map to filter based on the source's "navigation" or
// "event" type. The first Event-Trigger that matches (based on the
// filters/not_filters) will be used for report generation. If none of the
// event-triggers match, no report will be generated.
"filters": [{
"[key name 1]": ["key1 value 1", "key1 value 2"],
// If a key is missing from filters or source's filter_data, it won't be
// used during matching.
"[key name 2]": ["key2 value 1", "key2 value 2"],
}],
"not_filters": [{
"[key name 1]": ["key1 value 1", "key1 value 2"],
// If a key is missing from not_filters or source's filter_data, it won't
// be used during matching.
"[key name 2]": ["key2 value 1", "key2 value 2"],
}]
}],
"aggregatable_trigger_data": [
// Each dictionary entry independently adds pieces to multiple source keys.
{
"key_piece": "[key piece value]",
"source_keys": ["[key name the key piece value applies to]",
["list of IDs in source to match. Non-matching IDs are ignored"]],
// filters/not_filters are optional fields similar to event trigger data
// filter fields.
"filters": [{
"[key name 1]": ["key1 value 1", "key1 value 2"]
}],
"not_filters": [{
"[key name 1]": ["key1 value 1", "key1 value 2"],
"[key name 2]": ["key2 value 1", "key2 value 2"],
}]
},
..
],
// Specify an amount of an abstract value which can be integers in [1, 2^16] to
// contribute to each key that is attached to aggregation keys in the order they
// are generated.
"aggregatable_values": [
// Each source event can contribute a maximum of L1 = 2^16 to the aggregate
// histogram.
{
"[key_name]": [value]
}
]
}
// The Attribution-Reporting-Redirect header is ignored for ad tech partners.
Принимать отчеты на уровне событий
Эта конечная точка должна быть адресуемой из URI. См. Регистрация для учетной записи Privacy Sandbox для получения дополнительной информации о регистрации URI. (URI выводится из источника серверов, используемых для принятия регистрации источника и регистрации триггера.) Используя примеры URI для конечных точек, которые принимают регистрацию источника и регистрацию триггера , URI этой конечной точки будет:
https://adtech.example/.well-known/attribution-reporting/report-event-attribution
Настройте этот сервер для приема JSON-запросов, использующих следующий формат:
{
"attribution_destination": "android-app://com.advertiser.example",
"source_event_id": "12345678",
"trigger_data": "2",
"report_id": "12324323",
"source_type": "navigation",
"randomized_trigger_rate": "0.02"
[Optional] "source_debug_key": "[64-bit unsigned integer]",
[Optional] "trigger_debug_key": "[64-bit unsigned integer]",
}
Ключи отладки позволяют получить дополнительную информацию об отчетах об атрибуции; узнайте больше об их настройке.
Принимать агрегированные отчеты
Эта конечная точка должна быть адресуемой из URI. См. Регистрация для учетной записи Privacy Sandbox для получения дополнительной информации о регистрации URI. (URI выводится из источника серверов, используемых для принятия регистрации источника и регистрации триггера.) Используя примеры URI для конечных точек, которые принимают регистрацию источника и регистрацию триггера , URI этой конечной точки будет:
https://adtech.example/.well-known/attribution-reporting/report-aggregate-attribution
Зашифрованные и незашифрованные поля заполняются для агрегируемых отчетов. Зашифрованные отчеты позволяют вам начать тестирование с помощью службы агрегации, в то время как незашифрованное поле дает представление о том, как заданные пары ключ-значение структурируют данные.
Настройте этот сервер для приема JSON-запросов, использующих следующий формат:
{
// Info that the aggregation services also need encoded in JSON
// for use with AEAD. Line breaks added for readability.
"shared_info": "{
\"api\":\"attribution-reporting\",
\"attribution_destination\": \"android-app://com.advertiser.example.advertiser\",
\"scheduled_report_time\":\"[timestamp in seconds]\",
\"source_registration_time\": \"[timestamp in seconds]\",
\"version\":\"[api version]\",
\"report_id\":\"[UUID]\",
\"reporting_origin\":\"https://reporter.example\" }",
// In the current Developer Preview release, The "payload" and "key_id" fields
// are not used because the platform doesn't yet encrypt aggregate reports.
// The "debug_cleartext_payload" field holds unencrypted reports.
"aggregation_service_payloads": [
{
"payload": "[base64 HPKE encrypted data readable only by the aggregation service]",
"key_id": "[string identifying public key used to encrypt payload]",
"debug_cleartext_payload": "[unencrypted payload]"
},
],
"source_debug_key": "[64 bit unsigned integer]",
"trigger_debug_key": "[64 bit unsigned integer]"
}
Ключи отладки позволяют получить дополнительную информацию об отчетах об атрибуции; узнайте больше об их настройке.
Настроить Android-клиент
Клиентское приложение регистрирует источники и триггеры атрибуции и позволяет генерировать отчеты на уровне событий и агрегированные отчеты. Чтобы подготовить клиентское устройство Android или эмулятор для использования API отчетов об атрибуции, выполните следующие действия:
- Настройте среду разработки для Privacy Sandbox на Android.
- Установите образ системы на поддерживаемое устройство или настройте эмулятор , включающий поддержку Privacy Sandbox на Android.
Включите доступ к API Attribution Reporting, выполнив следующую команду ADB. (API отключен по умолчанию.)
adb shell device_config put adservices ppapi_app_allow_list \"\*\"
Если вы локально тестируете API Attribution Reporting (например, на устройстве, к которому у вас есть физический доступ), выполните эту команду, чтобы отключить регистрацию:
adb shell device_config put adservices disable_measurement_enrollment_check "true"
Включите разрешение
ACCESS_ADSERVICES_ATTRIBUTION
в файл манифеста Android и создайте конфигурацию рекламных служб для своего приложения, чтобы использовать API отчетов об атрибуции:<uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
(Необязательно) Если вы планируете получать отчеты об отладке, включите разрешение
ACCESS_ADSERVICES_AD_ID
в файл манифеста Android:<uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID" />
Укажите конфигурацию рекламных служб в элементе
<application>
вашего манифеста:<property android:name="android.adservices.AD_SERVICES_CONFIG" android:resource="@xml/ad_services_config" />
Укажите ресурс XML рекламных служб, на который есть ссылка в манифесте, например
res/xml/ad_services_config.xml
. Узнайте больше о разрешениях рекламных служб и управлении доступом SDK .<ad-services-config> <attribution allowAllToAccess="true" /> </ad-services-config>
Регистрация рекламных событий
Ваше приложение должно регистрировать источники и конверсии по мере их возникновения, чтобы убедиться, что они правильно сообщаются. Класс MeasurementManager
содержит методы, которые помогут вам регистрировать события источника атрибуции и триггеры конверсии .
Регистрация события источника атрибуции
При просмотре или нажатии на рекламу приложение издателя вызывает registerSource()
для регистрации источника атрибуции, как показано во фрагменте кода.
API отчетов об атрибуции поддерживает следующие типы событий источника атрибуции:
- Клики, которые вы обычно регистрируете в методе обратного вызова, похожем на
onClick()
. Соответствующее событие триггера обычно происходит вскоре после события щелчка. Этот тип событий предоставляет больше информации о взаимодействии пользователя и, следовательно, является хорошим типом источника атрибуции, чтобы задать высокий приоритет. Просмотры, которые вы обычно регистрируете в методе обратного вызова, похожем на
onAdShown()
. Соответствующее событие триггера может произойти через несколько часов или дней после события просмотра.
Котлин
companion object {
private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}
val measurementManager = context.getSystemService(MeasurementManager::class.java)
var exampleClickEvent: InputEvent? = null
// Use the URI of the server-side endpoint that accepts attribution source
// registration.
val attributionSourceUri: Uri =
Uri.parse("https://adtech.example/attribution_source?AD_TECH_PROVIDED_METADATA")
val future = CompletableFuture<Void>()
adView.setOnTouchListener(_: View?, event: MotionEvent?)) ->
exampleClickEvent = event
true
}
// Register Click Event
measurementManager.registerSource(
attributionSourceUri,
exampleClickEvent,
CALLBACK_EXECUTOR,
future::complete)
// Register View Event
measurementManager.registerSource(
attributionSourceUri,
null,
CALLBACK_EXECUTOR,
future::complete)
Ява
private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool();
private InputEvent exampleClickEvent;
MeasurementManager measurementManager =
context.getSystemService(MeasurementManager.class);
// Use the URI of the server-side endpoint that accepts attribution source
// registration.
Uri attributionSourceUri =
Uri.parse("https://adtech.example/attribution_source?AD_TECH_PROVIDED_METADATA");
CompletableFuture<Void> future = new CompletableFuture<>();
adView.setOnTouchListener(v, event)) -> {
exampleClickEvent = event;
return true;
}
// Register Click Event
measurementManager.registerSource(attributionSourceUri, exampleClickEvent,
CALLBACK_EXECUTOR, future::complete);
// Register View Event
measurementManager.registerSource(attributionSourceUri, null,
CALLBACK_EXECUTOR, future::complete);
После регистрации API отправляет HTTP-запрос POST к конечной точке сервиса по адресу, указанному attributionSourceUri
. Ответ конечной точки включает значения destination, source_event_id, expiry
и source_priority
.
Если исходная рекламная технология хочет поделиться регистрацией источника, исходный URI источника атрибуции может включать перенаправления на другие конечные точки рекламной технологии. Ограничения и правила, применимые к перенаправлениям, подробно описаны в техническом предложении .
Добавлена поддержка перенаправлений daisy-chain для registerSource
и registerTrigger
. В дополнение к заголовку регистрации потребитель API теперь может предоставить перенаправление HTTP в качестве ответа сервера, который включает код статуса 302 и заголовок «Location» со следующим URL-адресом для посещения для дополнительной регистрации.
Только поле "destination", указанное в самом первом посещении, используется в daisy-chain. Количество посещений имеет тот же предел, что и заголовки "Attribution-Reporting-Redirect". Эта поддержка перенаправления является дополнением к существующей поддержке "Attribution-Reporting-Redirect", и если присутствуют оба, предпочтение отдается "Attribution-Reporting-Redirect".
Регистрация события-триггера конверсии
Чтобы зарегистрировать событие триггера конверсии, вызовите registerTrigger()
в своем приложении:
Котлин
companion object {
private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}
val measurementManager = context.getSystemService(MeasurementManager::class.java)
// Use the URI of the server-side endpoint that accepts trigger registration.
val attributionTriggerUri: Uri =
Uri.parse("https://adtech.example/trigger?AD_TECH_PROVIDED_METADATA")
val future = CompletableFuture<Void>()
// Register trigger (conversion)
measurementManager.registerTrigger(
attributionTriggerUri,
CALLBACK_EXECUTOR,
future::complete)
Ява
private static final Executor CALLBACK_EXECUTOR = Executors.newCachedThreadPool();
MeasurementManager measurementManager =
context.getSystemService(MeasurementManager.class);
// Use the URI of the server-side endpoint that accepts trigger registration.
Uri attributionTriggerUri =
Uri.parse("https://adtech.example/trigger?AD_TECH_PROVIDED_METADATA");
CompletableFuture<Void> future = new CompletableFuture<>();
// Register trigger (conversion)
measurementManager.registerTrigger(
attributionTriggerUri,
CALLBACK_EXECUTOR,
future::complete)
После регистрации API отправляет HTTP-запрос POST к конечной точке сервиса по адресу, указанному attributionTriggerUri
. Ответ конечной точки включает значения для отчетов о событиях и агрегированных отчетов.
Если исходная рекламная техническая платформа позволяет совместно использовать триггерные регистрации, URI может включать перенаправления на URI, принадлежащие другим рекламным техническим платформам. Ограничения и правила, применимые к перенаправлениям, подробно описаны в техническом предложении .
Регистрация кросс-приложений и веб-измерений
В случае, когда и приложение, и браузер играют роль в пути пользователя от источника к триггеру, существуют тонкие различия в реализации регистрации рекламных событий. Если пользователь видит рекламу в приложении и перенаправляется в браузер для конверсии, источник регистрируется приложением, а конверсия — веб-браузером. Аналогично, если пользователь начинает работу в веб-браузере и перенаправляется в приложение для конверсии, браузер регистрирует источник, а приложение регистрирует конверсию.
Поскольку существуют различия в организации рекламных технологий в Интернете и на Android, мы добавили новые API для регистрации источников и триггеров, когда они происходят в браузерах. Ключевое различие между этими API и соответствующими API на основе приложений заключается в том, что мы ожидаем, что браузер будет следовать перенаправлениям, применять любые фильтры, специфичные для браузера, и передавать действительные регистрации на платформу, вызывая registerWebSource()
или registerWebTrigger()
.
В следующем фрагменте кода показан пример вызова API, который браузер выполняет для регистрации источника атрибуции перед тем, как направить пользователя в приложение:
Котлин
companion object {
private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}
val measurementManager =
context.getSystemService(MeasurementManager::class.java)
var exampleClickEvent: InputEvent? = null
// Use the URIs of the server-side endpoints that accept attribution source
// registration.
val sourceParam1 = WebSourceParams.Builder(Uri.parse(
"https://adtech1.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
// True, if debugging is allowed for the ad tech.
.setDebugKeyAllowed(true)
.build()
val sourceParam2 = WebSourceParams.Builder(Uri.parse(
"https://adtech2.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
.setDebugKeyAllowed(false)
.build()
val sourceParam3 = WebSourceParams.Builder(Uri.parse(
"https://adtech3.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
.build()
val sourceParams = Arrays.asList(sourceParam1, sourceParam2, sourceParam3)
val publisherOrigin = Uri.parse("https://publisher.example")
val appDestination = Uri.parse("android-app://com.example.store")
val webDestination = Uri.parse("https://example.com")
val future = CompletableFuture<Void>()
adView.setOnTouchListener {_: View?, event: MotionEvent? ->
exampleClickEvent = event
true
}
val clickRegistrationRequest = WebSourceRegistrationRequest.Builder(
sourceParams,
publisherOrigin)
.setAppDestination(appDestination)
.setWebDestination(webDestination)
.setInputEvent(event)
.build()
val viewRegistrationRequest = WebSourceRegistrationRequest.Builder(
sourceParams,
publisherOrigin)
.setAppDestination(appDestination)
.setWebDestination(webDestination)
.setInputEvent(null)
.build()
// Register a web source for a click event.
measurementManager.registerWebSource(
clickRegistrationRequest,
CALLBACK_EXECUTOR,
future::complete)
// Register a web source for a view event.
measurementManager.registerWebSource(
viewRegistrationRequest,
CALLBACK_EXECUTOR,
future::complete)
Ява
private static final Executor CALLBACK_EXECUTOR =
Executors.newCachedThreadPool();
private InputEvent exampleClickEvent;
MeasurementManager measurementManager =
context.getSystemService(MeasurementManager.class);
// Use the URIs of the server-side endpoints that accept attribution source
// registration.
WebSourceParams sourceParam1 = WebSourceParams.Builder(Uri.parse(
"https://adtech1.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
// True, if debugging is allowed for the ad tech.
.setDebugKeyAllowed(true)
.build();
WebSourceParams sourceParam2 = WebSourceParams.Builder(Uri.parse(
"https://adtech2.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
.setDebugKeyAllowed(false)
.build();
WebSourceParams sourceParam3 = WebSourceParams.Builder(Uri.parse(
"https://adtech3.example/attribution_source?AD_TECH_PROVIDED_METADATA"))
.build();
List<WebSourceParams> sourceParams =
Arrays.asList(sourceParam1, sourceParam2, sourceParam3);
Uri publisherOrigin = Uri.parse("https://publisher.example");
Uri appDestination = Uri.parse("android-app://com.example.store");
Uri webDestination = Uri.parse("https://example.com");
CompletableFuture<Void> future = new CompletableFuture<>();
adView.setOnTouchListener(v, event) -> {
exampleClickEvent = event;
return true;
}
WebSourceRegistrationRequest clickRegistrationRequest =
new WebSourceRegistrationRequest.Builder(sourceParams, publisherOrigin)
.setAppDestination(appDestination)
.setWebDestination(webDestination)
.setInputEvent(event)
.build();
WebSourceRegistrationRequest viewRegistrationRequest =
new WebSourceRegistrationRequest.Builder(sourceParams, publisherOrigin)
.setAppDestination(appDestination)
.setWebDestination(webDestination)
.setInputEvent(null)
.build();
// Register a web source for a click event.
measurementManager.registerWebSource(clickRegistrationRequest,
CALLBACK_EXECUTOR, future::complete);
// Register a web source for a view event.
measurementManager.registerWebSource(viewRegistrationRequest,
CALLBACK_EXECUTOR, future::complete);
В следующем фрагменте кода показан пример вызова API, который браузер выполняет для регистрации конверсии после того, как пользователь был перенаправлен из приложения:
Котлин
companion object {
private val CALLBACK_EXECUTOR = Executors.newCachedThreadPool()
}
val measurementManager = context.getSystemService(MeasurementManager::class.java)
// Use the URIs of the server-side endpoints that accept trigger registration.
val triggerParam1 = WebTriggerParams.Builder(Uri.parse(
"https://adtech1.example/trigger?AD_TECH_PROVIDED_METADATA"))
// True, if debugging is allowed for the ad tech.
.setDebugKeyAllowed(true)
.build()
val triggerParam2 = WebTriggerParams.Builder(Uri.parse(
"https://adtech2.example/trigger?AD_TECH_PROVIDED_METADATA"))
.setDebugKeyAllowed(false)
.build()
val triggerParams = Arrays.asList(triggerParam1, triggerParam2)
val advertiserOrigin = Uri.parse("https://advertiser.example")
val future = CompletableFuture<Void>()
val triggerRegistrationRequest = WebTriggerRegistrationRequest.Builder(
triggerParams,
advertiserOrigin)
.build()
// Register the web trigger (conversion).
measurementManager.registerWebTrigger(
triggerRegistrationRequest,
CALLBACK_EXECUTOR,
future::complete)
Ява
private static final Executor CALLBACK_EXECUTOR =
Executors.newCachedThreadPool();
MeasurementManager measurementManager =
context.getSystemService(MeasurementManager.class);
// Use the URIs of the server-side endpoints that accept trigger registration.
WebTriggerParams triggerParam1 = WebTriggerParams.Builder(Uri.parse(
"https://adtech1.example/trigger?AD_TECH_PROVIDED_METADATA"))
// True, if debugging is allowed for the ad tech.
.setDebugKeyAllowed(true)
.build();
WebTriggerParams triggerParam2 = WebTriggerParams.Builder(Uri.parse(
"https://adtech2.example/trigger?AD_TECH_PROVIDED_METADATA"))
.setDebugKeyAllowed(false)
.build();
List<WebTriggerParams> triggerParams =
Arrays.asList(triggerParam1, triggerParam2);
Uri advertiserOrigin = Uri.parse("https://advertiser.example");
CompletableFuture<Void> future = new CompletableFuture<>();
WebTriggerRegistrationRequest triggerRegistrationRequest =
new WebTriggerRegistrationRequest.Builder(
triggerParams, advertiserOrigin)
.build();
// Register the web trigger (conversion).
measurementManager.registerWebTrigger( triggerRegistrationRequest,
CALLBACK_EXECUTOR, future::complete);
Добавление шума для конфиденциальности
Отчеты на уровне событий содержат пункт назначения, идентификатор источника атрибуции и данные триггера. Они отправляются в исходном (незашифрованном) формате в источник отчетов. Для защиты конфиденциальности пользователя можно добавить шум, чтобы затруднить идентификацию отдельного пользователя. Зашумленные отчеты на уровне событий генерируются и отправляются в соответствии с фреймворком дифференциальной конфиденциальности . Это значения процента шума по умолчанию для различных сценариев:
Тип источника | Исходное значение назначения | Вероятность зашумленного отчета на регистрацию источника |
Вид | Приложение или веб | 0.0000025 |
Вид | Приложение и веб | 0.0000042 |
Нажмите | Приложение или веб | 0,0024263 |
Нажмите | Приложение и веб | 0,0170218 |
В измерении атрибуции «приложение-в-веб», где источники могут управлять конверсией как в приложениях, так и в веб-приложениях, отчеты на уровне событий могут указывать, произошел ли триггер в приложении или на веб-сайте. Чтобы компенсировать эту дополнительную информацию, генерируемые зашумленные отчеты составляют до ~7x для кликов и ~1,7x для просмотров.
Некоторые специалисты по рекламе не требуют отчетов на уровне событий, чтобы указать, произошел ли триггер на приложении или веб-адресе. Специалисты по рекламе могут использовать поле coarse_event_report_destinations
под заголовком Attribution-Reporting-Register-Source
для снижения шума. Если источник с указанным полем coarse_event_report_destinations
выигрывает атрибуцию, результирующий отчет включает как приложения, так и веб-адреса, независимо от того, где произошел фактический триггер.
В следующих примерах пользователь нажимает на рекламу, и этот источник регистрируется в API. Затем пользователь конвертируется как в приложении рекламодателя, так и на веб-сайте рекламодателя. Обе эти конверсии регистрируются как триггеры и приписываются первоначальному клику.
HTTP-заголовок регистрации источника на основе кликов:
Attribution-Reporting-Register-Source: {
"destination": "android-app://com.advertiser.example",
"web_destination": "https://advertiser.com",
"source_event_id": "234",
"expiry": "60000",
"priority": "5",
// Ad tech opts out of receiving app-web destination distinction
// in event report, avoids additional noise
"coarse_event_report_destinations": "true"
}
Триггер регистрируется из приложения с именем пакета com.advertiser.example
:
Attribution-Reporting-Register-Trigger: {
"event_trigger_data": [{
"trigger_data": "1",
"priority": "1"
}],
}
Триггер регистрируется из браузера с сайта с доменом eTLD+1 https://advertiser.com
:
Attribution-Reporting-Register-Trigger: {
"event_trigger_data": [{
"trigger_data": "2",
"priority": "2"
}],
}
Генерируются итоговые отчеты на уровне событий. Предполагая, что оба триггера приписываются источнику, генерируются следующие отчеты на уровне событий:
{
"attribution_destination": ["android-app://com.advertiser.example,https://advertiser.com"],
"scheduled_report_time": "800176400",
"source_event_id": "53234",
"trigger_data": "1",
// Can be "event" if source were registered by user viewing the ad
"source_type": "navigation",
// Would be 0.0170218 without coarse_event_report_destinations as true in the source
"randomized_trigger_rate": 0.0024263
}
Создание и предоставление отчетов
API отчетов об атрибуции отправляет отчеты на конечные точки вашего сервера, которые принимают отчеты на уровне событий и агрегированные отчеты .
Принудительное выполнение заданий по созданию отчетов
После регистрации события источника атрибуции или регистрации события-триггера система планирует выполнение задания по созданию отчетов. По умолчанию это задание выполняется каждые 4 часа. В целях тестирования вы можете принудительно запустить задания по созданию отчетов или сократить интервалы между заданиями.
Принудительно запустить задание атрибуции:
adb shell cmd jobscheduler run -f com.google.android.adservices.api 5
Принудительно запустить задание по созданию отчета на уровне событий:
adb shell cmd jobscheduler run -f com.google.android.adservices.api 3
Принудительно запустить задание по созданию агрегируемой отчетности:
adb shell cmd jobscheduler run -f com.google.android.adservices.api 7
Проверьте вывод в logcat, чтобы увидеть, когда задания были запущены. Это должно выглядеть примерно так:
JobScheduler: executeRunCommand(): com.google.android.adservices.api/0 5 s=false f=true
Принудительная доставка отчетов
Даже если задание по созданию отчетов принудительно запущено, система все равно отправляет отчеты в соответствии с запланированным временем доставки , которое варьируется от пары часов до нескольких дней. Для целей тестирования вы можете перевести системное время устройства вперед, чтобы оно было после запланированных задержек, чтобы инициировать доставку отчетов.
Проверьте отчеты на вашем сервере
После отправки отчетов проверьте их доставку, проверив полученные отчеты, соответствующие журналы сервера, такие как история фиктивного сервера или ваша пользовательская система.
Расшифруйте ваш сводный отчет
При получении сводного отчета поле debug_cleartext_payload
содержит незашифрованную версию вашего сводного отчета. Хотя эта версия вашего отчета не зашифрована, ее все равно нужно расшифровать.
Ниже приведен пример декодирования содержимого поля debug_cleartext_payload
в два этапа: первый этап с использованием декодирования Base 64, а второй — с использованием декодирования CBOR.
String base64DebugPayload = "omRkYXRhgqJldmFsdWVEAAAGgGZidWNrZXRQAAAAAAAAAAAAAAAAAAAKhaJldmFsdWVEAACAAGZidWNrZXRQAAAAAAAAAAAAAAAAAAAFWWlvcGVyYXRpb25paGlzdG9ncmFt";
byte[] cborEncoded = Base64.getDecoder().decode(base64DebugPayload);
// CbodDecoder comes from this library https://github.com/c-rack/cbor-java
final List<DataItem> dataItems = new CborDecoder(new ByteArrayInputStream(cborEncoded)).decode();
// In here you can see the contents, but the value will be something like:
// Data items: [{ data: [{ value: co.nstant.in.cbor.model.ByteString@a8b5c07a,
// bucket: co.nstant.in.cbor.model.ByteString@f812097d },
// { value: co.nstant.in.cbor.model.ByteString@a8b5dfc0,
// bucket: co.nstant.in.cbor.model.ByteString@f8120934 }], operation: histogram }]
Log.d("Data items : " + dataItems);
// In order to see the value for bucket and value, you can traverse the data
// and get their values, something like this:
final Map payload = (Map) dataItems.get(0);
final Array payloadArray = (Array) payload.get(new UnicodeString("data"));
payloadArray.getDataItems().forEach(i -> {
BigInteger value = new BigInteger(((ByteString) ((Map)i).get(new UnicodeString("value"))).getBytes());
BigInteger bucket = new BigInteger(((ByteString) ((Map)i).get(new UnicodeString("bucket"))).getBytes());
Log.d("value : " + value + " ;bucket : " + bucket);
});
Тестирование
Чтобы помочь вам начать работу с API Attribution Reporting, вы можете использовать проект MeasurementSampleApp на GitHub. Этот пример приложения демонстрирует регистрацию источника атрибуции и регистрацию триггера.
Для конечных точек сервера рассмотрите следующие справочные ресурсы или ваше индивидуальное решение:
- MeasurementAdTechServerSpec включает определения служб OpenAPI, которые можно развернуть на поддерживаемых платформах-макетах или микросервисах.
- MeasurementAdTechServer включает в себя эталонную реализацию фиктивного сервера на основе приложения Spring Boot для Google App Engine.
Предпосылки
Разверните фиктивные API на удаленных конечных точках, доступных с вашего тестового устройства или эмулятора. Для простоты тестирования обратитесь к примерам проектов MeasurementAdTechServerSpec и MeasurementAdTechServer .
Функциональность для тестирования
- Осуществить регистрацию источника атрибуции и триггера конверсии. Проверьте, что конечные точки на стороне сервера отвечают в правильном формате.
- Выполнение заданий по составлению отчетов .
- Проверьте доставку отчетов на бэкэнд или консоль вашего тестового сервера.
Предстоящие функции
Гибкая конфигурация на уровне событий
Конфигурация по умолчанию для отчетов на уровне событий рекомендуется для начала тестирования полезности, но может не быть идеальной для всех случаев использования. API отчетов об атрибуции будет поддерживать дополнительные, более гибкие конфигурации, чтобы специалисты по рекламе имели больший контроль над структурой своих отчетов на уровне событий и могли максимизировать полезность данных. Эта дополнительная гибкость будет введена в API отчетов об атрибуции в два этапа:
- Фаза 1 : Облегченная гибкая конфигурация уровня событий; подмножество фазы 2.
- Фаза 2 : Полная версия гибкой конфигурации уровня событий.
Фаза 1: Облегченный гибкий уровень событий
Мы добавим следующие два необязательных параметра в JSON в Attribution-Reporting-Register-Source
:
-
max_event_level_reports
-
event_report_windows
{
...
// Optional. This is a parameter that acts across all trigger types for the
// lifetime of this source. It restricts the total number of event-level
// reports that this source can generate. After this maximum is hit, the
// source is no longer capable of producing any new data. The use of
// priority in the trigger attribution algorithm in the case of multiple
// attributable triggers remains unchanged. Defaults to 3 for navigation
// sources and 1 for event sources
"max_event_level_reports": <int>,
// Optional. Represents a series of time windows, starting at 0. Reports
// for this source will be delivered an hour after the end of each window.
// Time is encoded as seconds after source registration. If
// event_report_windows is omitted, will use the default windows. This
// field is mutually exclusive with the existing `event_report_window` field.
// // End time is exclusive.
"event_report_windows": {
"start_time": <int>,
"end_times": [<int>, ...]
}
}
Пример пользовательской конфигурации
Этот пример конфигурации предназначен для разработчика, который хочет оптимизировать получение отчетов в более ранние периоды отчетности.
{
...
"max_event_level_reports": 2,
"event_report_windows": {
"end_times": [7200, 43200, 86400] // 2 hours, 12 hours, 1 day in seconds
}
}
Фаза 2: Полный гибкий уровень мероприятия
В дополнение к параметрам, которые были добавлены на этапе 1, мы добавим дополнительный необязательный параметр trigger_specs
в JSON в Attribution-Reporting-Register-Source
.
{
// A trigger spec is a set of matching criteria, along with a scheme to
// generate bucketized output based on accumulated values across multiple
// triggers within the specified event_report_window. There will be a limit on
// the number of specs possible to define for a source.
"trigger_specs": [{
// This spec will only apply to registrations that set one of the given
// trigger data values (non-negative integers) in the list.
// trigger_data will still appear in the event-level report.
"trigger_data": [<int>, ...]
// Represents a series of time windows, starting at the source registration
// time. Reports for this spec will be delivered an hour after the end of
// each window. Time is encoded as seconds after source registration.
// end_times must consist of strictly increasing positive integers.
//
// Note: specs with identical trigger_data cannot have overlapping windows;
// this makes sure that triggers match at most one spec. If
// event_report_windows is omitted, will use the "event_report_window" or
// "event_report_windows" field specified at the global level for the source
// (or the default windows if none are specified). End time is exclusive.
"event_report_windows": {
"start_time": <int>,
"end_times": [<int>, ...],
}
// Represents an operator that summarizes the triggers within a window
// count: number of triggers attributed within a window
// value_sum: sum of the value of triggers within a window
// The summary is reported as an index into a bucketization scheme. Defaults
// to "count"
"summary_window_operator": <one of "count" or "value_sum">,
// Represents a bucketization of the integers from [0, MAX_INT], encoded as
// a list of integers where new buckets begin (excluding 0 which is
// implicitly included).
// It must consist of strictly increasing positive integers.
//
// e.g. [5, 10, 100] encodes the following ranges:
// [[0, 4], [5, 9], [10, 99], [100, MAX_INT]]
//
// At the end of each reporting window, triggers will be summarized into an
// integer which slots into one of these ranges. Reports will be sent for
// every new range boundary that is crossed. Reports will never be sent for
// the range that includes 0, as every source is initialized in this range.
//
// If omitted, then represents a trivial mapping
// [1, 2, ... , MAX_INT]
// With MAX_INT being the maximum int value defined by the browser.
"summary_buckets": [<bucket start>, ...]
}, {
// Next trigger_spec
} ...],
// See description in phase 1.
"max_event_level_reports": <int>
// See description in phase 1.
"event_report_windows": {
"start_time": <int>,
"end_times": [<int>, ...]
}
}
Эта конфигурация полностью определяет выходное пространство отчетов на уровне событий, на регистрацию источника. Для каждой спецификации триггера мы полностью указываем:
- Набор критериев соответствия:
- К каким конкретным данным триггера применяется эта спецификация. Этот источник может быть сопоставлен только с триггерами, имеющими одно из указанных значений
trigger_data
вtrigger_specs
. Другими словами, если триггер сопоставил бы этот источник, но егоtrigger_data
не является одним из значений в конфигурации источника, триггер игнорируется. - Когда определенный триггер соответствует этой спецификации (используя
event_report_windows
). Обратите внимание, что триггер все равно может быть сопоставлен с источником для агрегируемых отчетов, несмотря на несоответствие двум критериям соответствия, упомянутым ранее.
- К каким конкретным данным триггера применяется эта спецификация. Этот источник может быть сопоставлен только с триггерами, имеющими одно из указанных значений
- Конкретный алгоритм для суммирования и группировки всех триггеров в окне атрибуции. Это позволяет триггерам указывать параметр
value
, который суммируется для конкретной спецификации, но сообщается как групповое значение.
Триггеры также будут поддерживать добавление необязательного параметра значения в словарях внутри event_trigger_data
.
{
"event_trigger_data": [
{
"trigger_data": "2",
"value": 100, // Defaults to 1
"filters": ...
},
...
]
}
Каждая регистрация триггера будет соответствовать максимум одной спецификации триггера и обновлять ее связанное с ней сводное значение. На высоком уровне, во время триггера мы будем:
- Примените глобальные фильтры атрибуции.
- Для каждой спецификации триггера оцените
event_trigger_data
в спецификации, чтобы найти соответствие, используяevent_reporting_window
спецификации.event_reporting_windows
верхнего уровня действует как значение по умолчанию в случае, если какая-либо спецификация триггера представляет собой отсутствующее подполеevent_report_windows
. - Для атрибуции выбирается первая совпавшая спецификация, а итоговое значение увеличивается на
value
.
Когда event_report_window
для спецификации завершается, мы сопоставляем его сводное значение с контейнером и отправляем отчет на уровне событий для каждого приращения в сводном контейнере, вызванного атрибутированными значениями триггера. Отчеты будут содержать одно дополнительное поле, trigger_summary_bucket
.
{
...
"trigger_summary_bucket": [<bucket start>, <bucket end>],
}
Конфигурации, эквивалентные текущей версии
Ниже приведены эквивалентные конфигурации для текущих событий API и источников навигации соответственно. Особенно для источников навигации это иллюстрирует, почему уровни шума настолько высоки относительно источников событий для поддержания тех же значений эпсилон: источники навигации имеют гораздо большее выходное пространство.
Возможно, существует несколько эквивалентных конфигураций, поскольку некоторые параметры можно установить по умолчанию или удалить.
Эквивалентные источники событий
// Note: most of the fields here are not required to be explicitly listed.
// Here we list them explicitly just for clarity.
{
"trigger_specs": [
{
"trigger_data": [0, 1],
"event_report_windows": {
"end_times": [<30 days>]
},
"summary_window_operator": "count",
"summary_buckets": [1],
}],
"max_event_level_reports": 1,
...
// expiry must be greater than or equal to the last element of the end_times
"expiry": <30 days>,
}
Эквивалентные навигационные источники
// Note: most of the fields here are not required to be explicitly listed.
// Here we list them explicitly just for clarity.
{
"trigger_specs": [
{
"trigger_data": [0, 1, 2, 3, 4, 5, 6, 7],
"event_report_windows": {
"end_times": [<2 days>, <7 days>, <30 days>]
},
"summary_window_operator": "count",
"summary_buckets": [1, 2, 3],
}],
"max_event_level_reports": 3,
...
// expiry must be greater than or equal to the last element of the end_times
"expiry": <30 days>,
}
Примеры пользовательских конфигураций
Ниже приведены некоторые дополнительные конфигурации, выходящие за рамки настроек по умолчанию. Во всех этих примерах компромиссы разработчиков включают:
- уменьшение некоторого измерения конфигурации по умолчанию (количество триггеров, мощность данных триггера, количество окон) для увеличения другого измерения для сохранения уровня шума
- уменьшение некоторых измерений конфигурации по умолчанию (количество триггеров, количество данных триггера, количество окон) для снижения уровня шума
Отчет о триггерных значениях сегментов
Этот пример конфигурации поддерживает разработчика, который хочет оптимизировать данные о значении только для одного окна отчетности (например, 7 дней), жертвуя меньшим количеством окон отчетности ради меньшего шума. В этом примере любой триггер, который устанавливает trigger_data
в значение, отличное от 0, не подлежит атрибуции.
{
"trigger_specs": [
{
"trigger_data": [0],
"event_report_windows": {
"end_times": [604800, 1209600] // 7 days, 14 days represented in seconds
},
"summary_window_operator": "value_sum",
"summary_buckets": [5, 10, 100]
}],
}
Триггеры могут быть зарегистрированы с набором полей value
, которые суммируются и группируются. Например, если есть три триггера в течение 7 дней с момента регистрации источника со значениями 1, 3 и 4.
{ "event_trigger_data": [{"trigger_data": "0", "value": 1}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 3}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 4}] }
Значения суммируются до 8 и сообщаются в следующих отчетах через 7 дней + 1 час:
// Report 1
{
...
"trigger_summary_bucket": [5, 9]
}
В последующие 7 дней регистрируются следующие триггеры:
{ "event_trigger_data": [{"trigger_data": "0", "value": 50}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 45}] }
Значения суммируются до 8 + 50 + 45 = 103. Это дает следующие отчеты через 14 дней + 1 час:
// Report 2
{
...
"trigger_summary_bucket": [10, 99]
},
// Report 3
{
...
"trigger_summary_bucket": [100, MAX_INT]
}
Количество триггеров отчета
В этом примере показано, как разработчик может настроить источник для получения количества триггеров до 10.
{
"trigger_specs": [
{
"trigger_data": [0],
"event_report_windows": {
"end_times": [604800] // 7 days represented in seconds
},
// This field could be omitted to save bandwidth since the default is "count"
"summary_window_operator": "count",
"summary_buckets": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}],
}
Атрибутированные триггеры с trigger_data
, установленным на 0, подсчитываются и ограничиваются 10. Значение триггера игнорируется, поскольку summary_window_operator
установлен на count. Если зарегистрировано 4 триггера и приписано источнику, отчет будет выглядеть следующим образом:
// Report 1
{
...
"trigger_summary_bucket": [1, 1]
}
// Report 2
{
...
"trigger_summary_bucket": [2, 2]
}
// Report 3
{
...
"trigger_summary_bucket": [3, 3]
}
// Report 4
{
...
"trigger_summary_bucket": [4, 4]
}
Двоичный с более частой отчетностью
Этот пример конфигурации поддерживает разработчика, который хочет узнать, произошла ли хотя бы одна конверсия за первые 10 дней (независимо от значения), но хочет получать отчеты с более частыми интервалами, чем по умолчанию. Опять же, в этом примере любой триггер, который устанавливает trigger_data
в значение, отличное от 0, не подлежит атрибуции. Вот почему этот вариант использования называется binary .
{
"trigger_specs": [
{
"trigger_data": [0],
"event_report_windows": {
// 1 day, 2 days, 3 days, 5 days, 7 days, 10 days represented in seconds
"end_times": [86400, 172800, 259200, 432000, 604800, 864000]
},
// This field could be omitted to save bandwidth since the default is "count"
"summary_window_operator": "count",
"summary_buckets": [1]
}],
}
Изменяйте характеристики триггера от источника к источнику
{
"trigger_specs": [
{
"trigger_data": [0, 1, 2, 3],
"event_report_windows": {
"end_times": [172800, 604800, 2592000] // 2 days, 7 days, 30 days represented in seconds
}
}],
"max_event_level_reports": 3
}
{
"trigger_specs": [
{
"trigger_data": [4, 5, 6, 7],
"event_report_windows": {
"end_times": [172800, 604800, 2592000] // 2 days, 7 days, 30 days represented in seconds
}
}],
"max_event_level_reports": 3
}
Мы призываем разработчиков предлагать различные варианты использования этого расширения API, и мы обновим это объяснение примерами конфигураций для этих вариантов использования.
Межсетевая атрибуция без перенаправлений
Специалисты по рекламе должны использовать перенаправления для регистрации нескольких триггеров источника атрибуции и для выполнения кросс-сетевой атрибуции. Эта функция помогает поддерживать кросс-сетевую атрибуцию, когда перенаправления невозможны между сетями. Подробнее .
Технические специалисты по рекламе могут отправлять конфигурацию в ответе на регистрацию триггера на основе того, какие источники, зарегистрированные другими техническими специалистами по рекламе, выбираются для генерации производных источников; эти производные источники затем используются для атрибуции. Сводные отчеты генерируются, если триггер приписывается производному источнику. Генерация отчета о событиях для производных источников не поддерживается.
Технические специалисты по рекламе могут выбирать из aggregation_keys
в своих зарегистрированных источниках, которыми они намерены поделиться с партнерскими техническим специалистами по рекламе. Эти ключи могут быть объявлены в необязательном поле shared_aggregation_keys
, расположенном под заголовком регистрации источника Attribution-Reporting-Register-Source
:
"shared_aggregation_keys": ["[key name1]", "[key name2]"]
Производные источники генерируются на основе конфигурации под заголовком регистрации триггера Attribution-Reporting-Register-Trigger
:
// Specifies the configuration based on which derived sources should be
// generated. Those derived sources will be included for source matching at the
// time of attribution. For example, if adtech2 is registering a trigger with an
// attribution_config with source_network as adtech1, available sources
// registered by adtech1 will be considered with additional filtering criteria
// applied to that set as mentioned in the attribution_config. Derived
// sources can have different values to priority, post_install_exclusivity_window
// etc.
"attribution_config": [
{
// Derived sources are created from this adtech's registered sources
"source_network": "[original source's adtech enrollment ID]",
//(optional) Filter sources whose priority falls in this range
"source_priority_range": {
"start": [priority filter lower bound],
"end": [priority filter upper bound]
},
// (optional) Filter sources whose at least one of filter maps matches these
// filters
"source_filters": {
"key name 1": ["key1 value 1"]
},
// (optional) Filter sources whose none of filter map matches these
// filters
"source_not_filters": {
"key name 1": ["key1 value 1"]
},
// (optional) Apply this priority to the generated derived sources
"priority": "[64 bit signed integer]",
// (optional) The derived source will have expiry set as this or parent
// source's, whichever is earlier
"expiry": "[64 bit signed integer]",
// (optional) set on the derived source
"filter_data": {
"key name 1": ["key1 value 1"]
},
// (optional) set on the derived source
"post_install_exclusivity_window": "[64-bit unsigned integer]"
}
]
Вот версия с примерами добавленных значений:
"attribution_config": [
{
"source_network": "adtech1-enrollment-id",
"source_priority_range": {
"start": 50,
"end": 100
},
"source_filters": {
"source_type": ["NAVIGATION"]
},
"source_not_filters": {
"product_id": ["789"]
},
"priority": "30",
"expiry": "78901",
// (optional) set on the derived source
"filter_data": {
"product_id": ["1234"]
},
// (optional) set on the derived source
"post_install_exclusivity_window": "7890"
}
]
Два новых необязательных поля добавлены в заголовок регистрации триггера. Эти поля включают идентификатор победившей рекламной технологии в агрегируемых ключах отчета:
-
x_network_bit_mapping
: Идентификатор регистрации для битового отображения идентификатора рекламной технологии -
x_network_data
: Смещение (сдвиг влево) для операции ИЛИx_network_bit_mapping
победившей рекламной технологии с ключевой частью триггера
Пример:
"Attribution-Reporting-Register-Trigger": {
"attribution_config": [...],
"aggregatable_trigger_data": [
{
"key_piece": "0x400",
"source_keys": ["campaignCounts"]
"x_network_data" : {
"key_offset" : 12 // [64 bit unsigned integer]
}
}
…
]
…
"x_network_bit_mapping": {
// This mapping is used to generate trigger key pieces with ad tech identifier
// bits. eg. If Ad Tech-A's sources wins the attribution then 0x1 here will be
// OR'd with the trigger key pieces to generate the final key piece.
"Ad-Tech-A-enrollment_id": "0x1", // Identifier bits in hex for A
"Ad-Tech-B-enrollment_id": "0x2" // Identifier bits in hex for B
}
…
}
Вот итоговый расчет ключевого элемента триггера при формировании отчета для источника AdTechB:
-
key_piece
:0x400 (010000000000)
-
key_offset
:12
- Значение
enrollment_id
AdtechB:2 (010)
(изx_network_bit_mapping
) - Результирующая часть ключа триггера:
0x400 | 0x2 << 12 = 0x2400
Ограничения
Список возможностей, находящихся в разработке для SDK Runtime, см. в примечаниях к выпуску .
Сообщить об ошибках и проблемах
Ваш отзыв — важная часть Privacy Sandbox на Android! Сообщите нам о любых найденных вами проблемах или идеях по улучшению Privacy Sandbox на Android.