Podczas czytania dokumentacji Piaskownicy prywatności na Androida używaj przycisku Wersja przedpremierowa dla programistów lub Beta, aby wybrać wersję programu, z której korzystasz, ponieważ instrukcje mogą się różnić.
Interfejs Attribution Reporting API ma zapewniać lepszą ochronę prywatności użytkowników dzięki wyeliminowaniu zależności od takich identyfikatorów (własnych i pochodzących od firm zewnętrznych) oraz obsługiwać najważniejsze przypadki pomiaru konwersji i przypisywania udziału w konwersji w aplikacjach. W tym przewodniku dla deweloperów opisujemy, jak skonfigurować i testować interfejsy Attribution Reporting API, aby rejestrować kliknięcia i wyświetlenia reklam oraz konwersje przez wywoływanie metod, które rejestrują odpowiednie reguły i źródła tych zdarzeń.
Z tego przewodnika dowiesz się, jak skonfigurować punkty końcowe serwera i utworzyć aplikację kliencką, która wywołuje te usługi. Więcej informacji o ogólnej konstrukcji interfejsu Attribution Reporting API znajdziesz w projekcie.
Hasła kluczowe
- Źródła atrybucji odnoszą się do kliknięć lub wyświetleń.
- Wywołania to zdarzenia, które można przypisać do konwersji.
- Raporty zawierają dane o wywołaniu i odpowiednim źródle atrybucji. Te raporty są wysyłane w odpowiedzi na zdarzenia wywołujące. Interfejs Attribution Reporting API obsługuje raporty na poziomie zdarzenia i raporty z możliwością agregacji.
Zanim zaczniesz
Aby korzystać z interfejsu Attribution Reporting API, wykonaj zadania po stronie serwera i po stronie klienta wymienione w sekcjach poniżej.
Konfigurowanie punktów końcowych interfejsu Attribution Reporting API
Interfejs Attribution Reporting API wymaga zestawu punktów końcowych, do których możesz uzyskać dostęp z urządzenia testowego lub emulatora. Utwórz po jednym punkcie końcowym dla każdego z tych zadań po stronie serwera:
- Rejestrowanie źródła atrybucji (wyświetlenia lub kliknięcia)
- Rejestrowanie aktywatora (konwersji)
- Akceptowanie raportów na poziomie zdarzenia
- Akceptowanie raportów zbiorczych
Wymagane punkty końcowe można skonfigurować na kilka sposobów:
- Najszybszym sposobem na rozpoczęcie pracy jest wdrożenie definicji usługi OpenAPI w wersji 3 z naszego repozytorium przykładowego kodu na platformie mikroserwisów lub platformie do testowania. Możesz użyć Postmana, Prisma lub dowolnej innej platformy serwera testowego, która akceptuje ten format. Wdróż każdy punkt końcowy i śledź identyfikatory URI, aby używać ich w aplikacji. Aby sprawdzić dostarczanie raportów, odwołaj się do wywołań wykonanych wcześniej na platformie testowej lub bezserwerowej.
- Uruchom własny serwer autonomiczny, korzystając z przykładowego kodu w Kotlinie opartego na Spring Boot. Wdróż ten serwer na platformie usług chmurowych lub w infrastrukturze wewnętrznej.
- Użyj definicji usług jako przykładów, aby zintegrować punkty końcowe z dotychczasowym systemem.
Akceptowanie rejestracji źródła
Ten punkt końcowy powinien być dostępny pod adresem URI podobnym do tego:
https://adtech.example/attribution_source
Gdy aplikacja kliencka rejestruje źródło atrybucji, podaje identyfikator URI tego punktu końcowego serwera. Interfejs Attribution Reporting API wysyła następnie żądanie i zawiera jeden z tych nagłówków:
W przypadku zdarzeń kliknięcia:
Attribution-Reporting-Source-Info: navigationW przypadku zdarzeń wyświetlenia:
Attribution-Reporting-Source-Info: event
Skonfiguruj punkt końcowy serwera tak, aby odpowiadał w ten sposób:
// 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>
Oto przykład z dodanymi przykładowymi wartościami:
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
Jeśli parametr Attribution-Reporting-Redirects zawiera identyfikatory URI partnerów technologii reklamowych, interfejs Attribution Reporting API wysyła podobne żądanie do każdego identyfikatora URI. Każdy partner technologiczny ds. reklam musi skonfigurować serwer, który odpowiada tymi nagłówkami:
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.
Akceptowanie rejestracji wywołania konwersji
Ten punkt końcowy powinien być dostępny pod adresem URI podobnym do tego:
https://adtech.example/attribution_trigger
Gdy aplikacja kliencka rejestruje zdarzenie wywołujące, podaje adres URI tego punktu końcowego serwera. Interfejs Attribution Reporting API wysyła następnie żądanie i zawiera jeden z tych nagłówków:
Skonfiguruj punkt końcowy serwera tak, aby odpowiadał w ten sposób:
// 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>
Oto przykład z dodanymi przykładowymi wartościami:
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
Identyfikator klucza agregacji i ciąg filtra mogą mieć maksymalnie 25 bajtów. Oznacza to, że identyfikatory kluczy agregacji i ciągi znaków filtra nie powinny przekraczać 25 znaków. W tym przykładzie ciąg campaignCounts ma 14 znaków, więc jest prawidłowym identyfikatorem klucza agregacji, a ciąg 1234 ma 4 znaki, więc jest prawidłowym ciągiem filtra.
Jeśli identyfikator klucza agregacji lub ciąg filtra przekracza 25 znaków, wyzwalacz jest ignorowany.
Jeśli parametr Attribution-Reporting-Redirect zawiera identyfikatory URI partnerów technologii reklamowych, interfejs Attribution Reporting API wysyła podobne żądanie do każdego identyfikatora URI. Każdy partner technologiczny ds. reklam musi skonfigurować serwer, który odpowiada tymi nagłówkami:
// 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.
Akceptowanie raportów na poziomie zdarzenia
Ten punkt końcowy powinien być dostępny pod adresem URI. Więcej informacji o rejestrowaniu adresów URI znajdziesz w artykule Rejestracja konta w Piaskownicy prywatności. (Identyfikator URI jest wywnioskowany ze źródła serwerów używanych do akceptowania rejestracji źródła i rejestracji wyzwalacza). Korzystając z przykładowych identyfikatorów URI punktów końcowych, które akceptują rejestrację źródła i akceptują rejestrację wyzwalacza, identyfikator URI tego punktu końcowego to:
https://adtech.example/.well-known/attribution-reporting/report-event-attribution
Skonfiguruj ten serwer tak, aby akceptował żądania JSON w tym formacie:
{
"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]",
}
Klucze debugowania umożliwiają uzyskanie dodatkowych informacji w raportach o atrybucji. Dowiedz się więcej o ich konfigurowaniu.
Akceptowanie raportów zbiorczych
Ten punkt końcowy powinien być dostępny pod adresem URI. Więcej informacji o rejestrowaniu adresów URI znajdziesz w artykule Rejestracja konta w Piaskownicy prywatności. (Identyfikator URI jest wywnioskowany ze źródła serwerów używanych do akceptowania rejestracji źródła i rejestracji wyzwalacza). Korzystając z przykładowych identyfikatorów URI punktów końcowych, które akceptują rejestrację źródła i akceptują rejestrację wyzwalacza, identyfikator URI tego punktu końcowego to:
https://adtech.example/.well-known/attribution-reporting/report-aggregate-attribution
W przypadku raportów, które można agregować, wypełniane są zarówno zaszyfrowane, jak i niezaszyfrowane pola. Zaszyfrowane raporty umożliwiają rozpoczęcie testowania usługi agregacji, a niezaszyfrowane pole dostarcza informacji o tym, jak ustawione pary klucz-wartość strukturują dane.
Skonfiguruj ten serwer tak, aby akceptował żądania JSON w tym formacie:
{
// 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]"
}
Klucze debugowania umożliwiają uzyskanie dodatkowych informacji w raportach o atrybucji. Dowiedz się więcej o ich konfigurowaniu.
Konfigurowanie klienta Androida
Aplikacja klienta rejestruje źródła i wyzwalacze atrybucji oraz umożliwia generowanie raportów na poziomie zdarzenia i raportów zbiorczych. Aby przygotować urządzenie lub emulator z Androidem do korzystania z interfejsu Attribution Reporting API, wykonaj te czynności:
- Skonfiguruj środowisko programistyczne dla Piaskownicy prywatności na Androida.
- Zainstaluj obraz systemu na obsługiwanym urządzeniu lub skonfiguruj emulator, który obsługuje Piaskownicę prywatności na Androidzie.
Włącz dostęp do interfejsu Attribution Reporting API, uruchamiając to polecenie ADB: (Interfejs API jest domyślnie wyłączony).
adb shell device_config put adservices ppapi_app_allow_list \"\*\"Jeśli testujesz interfejs Attribution Reporting API lokalnie (np. na urządzeniu, do którego masz fizyczny dostęp), uruchom to polecenie, aby wyłączyć rejestrację:
adb shell device_config put adservices disable_measurement_enrollment_check "true"W pliku manifestu Androida umieść uprawnienie
ACCESS_ADSERVICES_ATTRIBUTIONi utwórz konfigurację usług reklamowych, aby aplikacja mogła korzystać z interfejsów Attribution Reporting API:<uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />(Opcjonalnie) Jeśli planujesz otrzymywać raporty debugowania, dodaj uprawnienia
ACCESS_ADSERVICES_AD_IDdo pliku manifestu Androida:<uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID" />Odwołaj się do konfiguracji usług reklamowych w elemencie
<application>pliku manifestu:<property android:name="android.adservices.AD_SERVICES_CONFIG" android:resource="@xml/ad_services_config" />Określ zasób XML usług reklamowych, do którego odwołuje się manifest, np.
res/xml/ad_services_config.xml. Dowiedz się więcej o uprawnieniach usług reklamowych i kontroli dostępu do pakietu SDK.<ad-services-config> <attribution allowAllToAccess="true" /> </ad-services-config>
Rejestrowanie zdarzeń reklamy
Aplikacja powinna rejestrować źródła i konwersje w miarę ich występowania, aby sprawdzić, czy są prawidłowo raportowane. Klasa MeasurementManager zawiera metody, które pomagają rejestrować zdarzenia źródła atrybucji i wyzwalacze konwersji.
Rejestrowanie zdarzenia źródła atrybucji
Gdy reklama zostanie wyświetlona lub kliknięta, aplikacja wydawcy wywołuje funkcję registerSource(), aby zarejestrować źródło atrybucji, jak pokazano we fragmencie kodu.
Interfejs Attribution Reporting API obsługuje te typy zdarzeń źródła atrybucji:
- Kliknięcia, które zwykle rejestrujesz w metodzie wywołania zwrotnego podobnej do tej:
onClick()Odpowiednie zdarzenie aktywujące zwykle występuje wkrótce po zdarzeniu kliknięcia. Ten typ zdarzenia dostarcza więcej informacji o interakcji użytkownika, dlatego jest dobrym źródłem atrybucji, któremu warto przypisać wysoki priorytet. Wyświetlenia, które zwykle rejestrujesz w metodzie wywołania zwrotnego podobnej do
onAdShown(). Odpowiednie zdarzenie wywołujące może wystąpić kilka godzin lub dni po zdarzeniu wyświetlenia.
Kotlin
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)
Java
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);
Po rejestracji interfejs API wysyła żądanie HTTP POST do punktu końcowego usługi pod adresem określonym przez attributionSourceUri. Odpowiedź punktu końcowego zawiera wartości parametrów destination, source_event_id, expiry i source_priority.
Jeśli pierwotna platforma reklamowa chce udostępniać rejestracje źródła, pierwotny identyfikator URI źródła atrybucji może zawierać przekierowania do innych punktów końcowych platform reklamowych. Limity i reguły dotyczące przekierowań są szczegółowo opisane w propozycji technicznej.
Dodaliśmy obsługę przekierowań łańcuchowych w przypadku registerSource i registerTrigger. Oprócz nagłówka rejestracji odbiorca interfejsu API może teraz podać przekierowanie HTTP jako odpowiedź serwera, która zawiera kod stanu 302 i nagłówek „Location” z następnym adresem URL do odwiedzenia w celu dodatkowej rejestracji.
W całym łańcuchu używane jest tylko pole „miejsce docelowe” podane podczas pierwszej wizyty. Liczba wizyt ma taki sam limit jak nagłówki „Attribution-Reporting-Redirect”. Obsługa przekierowań jest dodatkiem do istniejącej już obsługi przekierowań „Attribution-Reporting-Redirect”. Jeśli obie są obecne, pierwszeństwo ma „Attribution-Reporting-Redirect”.
Rejestrowanie zdarzenia wywołującego konwersję
Aby zarejestrować zdarzenie wywołujące konwersję, wywołaj w aplikacji funkcję registerTrigger():
Kotlin
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)
Java
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)
Po rejestracji interfejs API wysyła żądanie HTTP POST do punktu końcowego usługi pod adresem określonym przez attributionTriggerUri. Odpowiedź punktu końcowego zawiera wartości raportów dotyczących zdarzeń i raportów zbiorczych.
Jeśli platforma technologii reklamowej, z której pochodzi rejestracja wyzwalacza, zezwala na udostępnianie rejestracji, URI może zawierać przekierowania do URI należących do innych platform technologii reklamowej. Limity i reguły dotyczące przekierowań są szczegółowo opisane w propozycji technicznej.
Rejestrowanie pomiarów obejmujących aplikacje i witryny
Jeśli w ścieżce użytkownika od źródła do wywołania zdarzenia uczestniczą zarówno aplikacja, jak i przeglądarka, występują subtelne różnice w implementacji rejestrowania zdarzeń związanych z reklamami. Jeśli użytkownik zobaczy reklamę w aplikacji i zostanie przekierowany do przeglądarki w celu dokonania konwersji, źródło zostanie zarejestrowane przez aplikację, a konwersja przez przeglądarkę. Podobnie jeśli użytkownik rozpocznie proces w przeglądarce internetowej i zostanie przekierowany do aplikacji w celu dokonania konwersji, przeglądarka zarejestruje źródło, a aplikacja – konwersję.
Ze względu na różnice w sposobie organizacji technologii reklamowych w internecie i na Androidzie dodaliśmy nowe interfejsy API do rejestrowania źródeł i wyzwalaczy, gdy występują w przeglądarkach. Główna różnica między tymi interfejsami API a odpowiednimi interfejsami API opartymi na aplikacjach polega na tym, że oczekujemy, że przeglądarka będzie śledzić przekierowania, stosować filtry specyficzne dla przeglądarki i przekazywać prawidłowe rejestracje na platformę, wywołując funkcje registerWebSource() lub registerWebTrigger().
Poniższy fragment kodu pokazuje przykład wywołania interfejsu API, które przeglądarka wykonuje, aby zarejestrować źródło atrybucji przed przekierowaniem użytkownika do aplikacji:
Kotlin
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)
Java
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);
Ten fragment kodu pokazuje przykład wywołania interfejsu API, które przeglądarka wykonuje w celu zarejestrowania konwersji po przekierowaniu użytkownika z aplikacji:
Kotlin
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)
Java
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);
Dodawanie szumu w celu ochrony prywatności
Raporty na poziomie zdarzenia zawierają dane dotyczące miejsca docelowego, identyfikatora źródła atrybucji i wyzwalacza. Są one wysyłane w oryginalnym (niezaszyfrowanym) formacie do źródła raportowania. Aby chronić prywatność użytkowników, można dodać szum, który utrudni identyfikację poszczególnych użytkowników. Raporty na poziomie zdarzenia z dodanym szumem są generowane i wysyłane zgodnie z ramami prywatności różnicowej. Oto domyślne wartości procentowe szumu w różnych scenariuszach:
Typ źródła |
Wartość miejsca docelowego źródła |
Prawdopodobieństwo raportu z zaszumionymi danymi według rejestracji źródła |
Wyświetl |
Aplikacja lub strona internetowa |
0,0000025 |
Wyświetl |
Aplikacja i internet |
0,0000042 |
Kliknięcie |
Aplikacja lub strona internetowa |
0,0024263 |
Kliknięcie |
Aplikacja i internet |
0,0170218 |
W przypadku pomiaru atrybucji z aplikacji do witryny, w którym źródła mogą generować konwersje w aplikacji i w witrynie, raporty na poziomie zdarzenia mogą określać, czy wyzwalacz wystąpił w aplikacji czy w witrynie. Aby zrekompensować te dodatkowe szczegóły, wygenerowane raporty z szumem są do ok. 7 razy większe w przypadku kliknięć i ok. 1,7 razy większe w przypadku wyświetleń.
Niektóre platformy reklamowe nie wymagają, aby raporty na poziomie zdarzenia określały, czy wyzwalacz wystąpił w aplikacji czy w miejscu docelowym w internecie. Aby ograniczyć szum, dostawcy technologii reklamowych mogą używać pola coarse_event_report_destinations w sekcji Attribution-Reporting-Register-Source. Jeśli źródło z określonym polem coarse_event_report_destinations wygrywa atrybucję, raport zawiera zarówno miejsca docelowe w aplikacji, jak i w internecie bez rozróżnienia, gdzie nastąpiło rzeczywiste wywołanie.
W poniższych przykładach użytkownik klika reklamę, a to źródło jest rejestrowane w interfejsie API. Użytkownik dokonuje konwersji zarówno w aplikacji reklamodawcy, jak i w jego witrynie. Obie te konwersje są rejestrowane jako wywołania i przypisywane do początkowego kliknięcia.
Nagłówek HTTP rejestracji źródła na podstawie kliknięć:
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"
}
Aktywator jest zarejestrowany w aplikacji o nazwie pakietu com.advertiser.example:
Attribution-Reporting-Register-Trigger: {
"event_trigger_data": [{
"trigger_data": "1",
"priority": "1"
}],
}
Zdarzenie jest rejestrowane w przeglądarce z witryny z domeną eTLD+1:https://advertiser.com
Attribution-Reporting-Register-Trigger: {
"event_trigger_data": [{
"trigger_data": "2",
"priority": "2"
}],
}
Wygenerowane zostaną raporty na poziomie zdarzenia. Załóżmy, że oba wyzwalacze są przypisane do źródła. W takim przypadku generowane są te raporty na poziomie zdarzenia:
{
"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
}
generować i dostarczać raporty,
Interfejs Attribution Reporting API wysyła raporty do punktów końcowych na Twoim serwerze, które akceptują raporty na poziomie zdarzenia i raporty zbiorcze.
Wymuszanie uruchamiania zadań raportowania
Po zarejestrowaniu zdarzenia źródła atrybucji lub zdarzenia wywołującego system zaplanuje uruchomienie zadania raportowania. Domyślnie to zadanie jest uruchamiane co 4 godziny. Na potrzeby testów możesz wymusić uruchomienie zadań raportowania lub skrócić odstępy między nimi.
Wymuś uruchomienie zadania atrybucji:
adb shell cmd jobscheduler run -f com.google.android.adservices.api 5
Wymuś uruchomienie zadania raportowania na poziomie zdarzenia:
adb shell cmd jobscheduler run -f com.google.android.adservices.api 3
Wymuś uruchomienie zadania raportowania, które można agregować:
adb shell cmd jobscheduler run -f com.google.android.adservices.api 7
Sprawdź dane wyjściowe w logcat, aby zobaczyć, kiedy zadania zostały uruchomione. Powinno to wyglądać mniej więcej tak:
JobScheduler: executeRunCommand(): com.google.android.adservices.api/0 5 s=false f=true
Wymuszanie dostarczania raportów
Nawet jeśli zadanie raportowania zostanie uruchomione wymuszenie, system nadal wysyła raporty zgodnie z zaplanowanymi godzinami dostawy, które wynoszą od kilku godzin do kilku dni. Na potrzeby testów możesz przesunąć czas systemowy urządzenia na czas po zaplanowanych opóźnieniach, aby zainicjować dostarczenie raportu.
Weryfikowanie raportów na serwerze
Po wysłaniu raportów sprawdź, czy zostały dostarczone, przeglądając otrzymane raporty i odpowiednie dzienniki serwera, np. historię serwera testowego lub własny system.
Odczytywanie raportu zbiorczego
W przypadku otrzymania raportu zbiorczego pole debug_cleartext_payload zawiera niezaszyfrowaną wersję raportu zbiorczego. Ta wersja raportu nie jest zaszyfrowana, ale nadal wymaga dekodowania.
Poniżej znajdziesz przykład dekodowania zawartości pola debug_cleartext_payload w 2 krokach: najpierw za pomocą dekodowania Base64, a potem za pomocą dekodowania 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);
});
Testowanie
Aby ułatwić Ci rozpoczęcie korzystania z interfejsu Attribution Reporting API, możesz użyć projektu MeasurementSampleApp na GitHubie. Ta przykładowa aplikacja demonstruje rejestrację źródła atrybucji i rejestrację wyzwalacza.
W przypadku punktów końcowych serwera skorzystaj z tych materiałów lub z własnego rozwiązania:
- MeasurementAdTechServerSpec zawiera definicje usług OpenAPI, które można wdrożyć na obsługiwanych platformach mikroserwisów lub platformach do testowania.
- MeasurementAdTechServer zawiera przykładową implementację serwera pozornego opartego na aplikacji Spring Boot dla Google App Engine.
Wymagania wstępne
Wdrażaj interfejsy API na zdalnych punktach końcowych dostępnych z urządzenia testowego lub emulatora. Aby ułatwić testowanie, zapoznaj się z projektami przykładowymi MeasurementAdTechServerSpec i MeasurementAdTechServer.
Funkcje do przetestowania
- Rejestracja źródła atrybucji ćwiczeń i wyzwalaczy konwersji. Sprawdź, czy punkty końcowe po stronie serwera odpowiadają w prawidłowym formacie.
- Wykonywanie zadań raportowania.
- Sprawdź dostarczanie raportów na backendzie lub w konsoli serwera testowego.
Nadchodzące funkcje
Elastyczna konfiguracja na poziomie zdarzenia
Domyślna konfiguracja raportowania na poziomie zdarzenia jest zalecana na początek testowania przydatności, ale może nie być idealna we wszystkich przypadkach użycia. Interfejs Attribution Reporting API będzie obsługiwać opcjonalne, bardziej elastyczne konfiguracje, dzięki czemu dostawcy technologii reklamowych będą mieć większą kontrolę nad strukturą raportów na poziomie zdarzenia i będą mogli maksymalizować użyteczność danych. Ta dodatkowa elastyczność zostanie wprowadzona w interfejsie Attribution Reporting API w 2 fazach:
- Etap 1: uproszczona elastyczna konfiguracja na poziomie zdarzenia; podzbiór etapu 2.
- Etap 2: pełna wersja elastycznej konfiguracji na poziomie zdarzenia.
Etap 1. Elastyczny poziom zdarzenia Lite
Do pliku JSON w Attribution-Reporting-Register-Source dodamy te 2 parametry opcjonalne:
max_event_level_reportsevent_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>, ...]
}
}
Przykład konfiguracji niestandardowej
Ta przykładowa konfiguracja jest przeznaczona dla dewelopera, który chce zoptymalizować otrzymywanie raportów w krótszych przedziałach czasu.
{
...
"max_event_level_reports": 2,
"event_report_windows": {
"end_times": [7200, 43200, 86400] // 2 hours, 12 hours, 1 day in seconds
}
}
Etap 2. Pełny elastyczny poziom zdarzenia
Oprócz parametrów dodanych w fazie 1 do pliku JSON w trigger_specsAttribution-Reporting-Register-Source dodamy dodatkowy parametr opcjonalny trigger_specs.
{
// 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>, ...]
}
}
Ta konfiguracja w pełni określa przestrzeń wyjściową raportów na poziomie zdarzenia dla każdej rejestracji źródła. W przypadku każdej specyfikacji aktywatora podajemy:
- zestaw kryteriów dopasowania:
- Konkretne dane wywołujące, do których odnosi się ta specyfikacja. To źródło może być dopasowywane tylko do wyzwalaczy, które mają jedną z określonych wartości
trigger_dataw polutrigger_specs. Inaczej mówiąc, jeśli wyzwalacz pasowałby do tego źródła, ale jegotrigger_datanie jest jedną z wartości w konfiguracji źródła, wyzwalacz jest ignorowany. - Gdy konkretny wyzwalacz pasuje do tej specyfikacji (używając
event_report_windows). Pamiętaj, że wyzwalacz może nadal pasować do źródła w przypadku raportów z możliwością agregacji, mimo że nie spełnia 2 kryteriów dopasowania wspomnianych wcześniej.
- Konkretne dane wywołujące, do których odnosi się ta specyfikacja. To źródło może być dopasowywane tylko do wyzwalaczy, które mają jedną z określonych wartości
- Specjalny algorytm podsumowujący i grupujący wszystkie wywołania w okresie atrybucji. Umożliwia to wyzwalaczom określanie parametru
value, który jest sumowany dla konkretnej specyfikacji, ale raportowany jako wartość przedziałowa.
W przypadku reguł będzie też można dodawać opcjonalny parametr wartości w słownikach w sekcji event_trigger_data.
{
"event_trigger_data": [
{
"trigger_data": "2",
"value": 100, // Defaults to 1
"filters": ...
},
...
]
}
Każda rejestracja wyzwalacza będzie pasować do co najwyżej jednej specyfikacji wyzwalacza i zaktualizuje powiązaną z nią wartość podsumowania. W momencie wywołania wykonamy te czynności:
- Zastosuj globalne filtry atrybucji.
- W przypadku każdej specyfikacji wyzwalacza sprawdź
event_trigger_dataw specyfikacji, aby znaleźć dopasowanie, używającevent_reporting_windowspecyfikacji. Element najwyższego poziomuevent_reporting_windowsdziała jako wartość domyślna w przypadku, gdy w specyfikacji wyzwalacza brakuje pola podrzędnegoevent_report_windows. - Do atrybucji wybierana jest pierwsza pasująca specyfikacja, a wartość podsumowania jest zwiększana o
value.
Gdy event_report_window dla specyfikacji zostanie ukończone, przypiszemy wartość podsumowania do przedziału i wyślemy raport na poziomie zdarzenia dla każdego przyrostu w przedziale podsumowania spowodowanego przez przypisane wartości wyzwalające. Raporty będą zawierać dodatkowe pole trigger_summary_bucket.
{
...
"trigger_summary_bucket": [<bucket start>, <bucket end>],
}
Konfiguracje, które są odpowiednikami bieżącej wersji
Poniżej znajdziesz równoważne konfiguracje bieżącego zdarzenia i źródeł nawigacji interfejsów API. W przypadku źródeł nawigacji pokazuje to, dlaczego poziomy szumu są tak wysokie w porównaniu ze źródłami zdarzeń, aby zachować te same wartości epsilona: źródła nawigacji mają znacznie większą przestrzeń wyjściową.
Może istnieć wiele równoważnych konfiguracji, ponieważ niektóre parametry można ustawić jako domyślne lub usunąć.
Równoważne źródła zdarzeń
// 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>,
}
Równoważne źródła nawigacji
// 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>,
}
Przykładowe konfiguracje niestandardowe
Poniżej znajdziesz dodatkowe konfiguracje poza domyślnymi. We wszystkich tych przykładach kompromisy, na które musi pójść deweloper, to:
- zmniejszenie niektórych wymiarów konfiguracji domyślnej (liczba reguł, moc zbioru danych reguły, liczba okien) w celu zwiększenia innego wymiaru i zachowania poziomu szumu.
- zmniejszenie niektórych wymiarów konfiguracji domyślnej (liczba wyzwalaczy, kardynalność danych wyzwalacza, liczba okien) w celu zmniejszenia poziomu szumu;
Raportowanie zakresów wartości aktywatora
Ta przykładowa konfiguracja jest przeznaczona dla dewelopera, który chce optymalizować dane o wartości tylko w jednym oknie raportowania (np. 7 dni), rezygnując z mniejszej liczby okien raportowania na rzecz mniejszego szumu. W tym przykładzie każdy wyzwalacz, który ustawia wartość trigger_data inną niż 0, nie kwalifikuje się do atrybucji.
{
"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]
}],
}
Można rejestrować wyzwalacze z ustawionym polem value, które są sumowane i grupowane. Jeśli na przykład w ciągu 7 dni od rejestracji źródła wystąpią 3 zdarzenia wywołujące o wartościach 1, 3 i 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}] }
Wartości są sumowane do 8 i wyświetlane w tych raportach po 7 dniach i 1 godzinie:
// Report 1
{
...
"trigger_summary_bucket": [5, 9]
}
W ciągu kolejnych 7 dni rejestrowane są te wyzwalacze:
{ "event_trigger_data": [{"trigger_data": "0", "value": 50}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 45}] }
Suma wartości wynosi 8 + 50 + 45 = 103. W ten sposób po 14 dniach i 1 godzinie uzyskasz te raporty:
// Report 2
{
...
"trigger_summary_bucket": [10, 99]
},
// Report 3
{
...
"trigger_summary_bucket": [100, MAX_INT]
}
Raportowanie liczby reguł
Ten przykład pokazuje, jak deweloper może skonfigurować źródło, aby uzyskać liczbę wywołań do 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]
}],
}
Przypisane wywołania z wartością trigger_data ustawioną na 0 są zliczane i ograniczone do 10.
Wartość wyzwalacza jest ignorowana, ponieważ parametr summary_window_operator jest ustawiony na zliczanie. Jeśli 4 wyzwalacze są zarejestrowane i przypisane do źródła, raport będzie wyglądał tak:
// 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]
}
Dane binarne z częstszym raportowaniem
Ta przykładowa konfiguracja jest przeznaczona dla dewelopera, który chce się dowiedzieć, czy w ciągu pierwszych 10 dni nastąpiła co najmniej 1 konwersja (niezależnie od wartości), ale chce otrzymywać raporty częściej niż domyślnie. W tym przykładzie każdy wyzwalacz, który ustawia wartość trigger_data na inną niż 0, nie kwalifikuje się do atrybucji. Dlatego ten przypadek użycia jest określany jako binarny.
{
"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]
}],
}
Różnicowanie specyfikacji aktywatora w zależności od źródła
{
"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
}
Zachęcamy deweloperów do proponowania różnych przypadków użycia tego rozszerzenia interfejsu API. Będziemy aktualizować ten opis, dodając przykładowe konfiguracje dla tych przypadków.
Atrybucja międzysieciowa bez przekierowań
Technologie reklamowe powinny używać przekierowań, aby rejestrować wiele wywołań źródła atrybucji i przeprowadzać atrybucję międzysieciową. Ta funkcja pomaga w atrybucji w różnych sieciach, w których przekierowania nie są możliwe. Więcej informacji
Dostawcy technologii reklamowych mogą wysyłać konfigurację w odpowiedzi na rejestrację wyzwalacza na podstawie tego, które źródła zarejestrowane przez innych dostawców technologii reklamowych zostały wybrane do generowania źródeł pochodnych. Te źródła pochodne są następnie używane do atrybucji. Raporty zbiorcze są generowane, jeśli wywołanie jest przypisane do źródła pochodnego. Generowanie raportu o zdarzeniach w przypadku źródeł pochodnych nie jest obsługiwane.
Dostawcy technologii reklamowych mogą wybrać aggregation_keys w zarejestrowanych źródłach, które zamierzają udostępniać partnerom. Klucze te można zadeklarować w opcjonalnym polu shared_aggregation_keys, które znajduje się pod nagłówkiem rejestracji źródła Attribution-Reporting-Register-Source:
"shared_aggregation_keys": ["[key name1]", "[key name2]"]
Źródła pochodne są generowane na podstawie konfiguracji w nagłówku rejestracji aktywatora 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]"
}
]
Oto wersja z dodanymi przykładowymi wartościami:
"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"
}
]
Do nagłówka rejestracji wywołania dodano 2 nowe pola opcjonalne. Te pola umożliwiają uwzględnienie identyfikatora zwycięskiej technologii reklamowej w kluczach raportu umożliwiającego agregację:
x_network_bit_mapping: mapowanie identyfikatora rejestracji na identyfikator technologii reklamowejx_network_data: przesunięcie (w lewo) w przypadku zwycięskiej technologii reklamowejx_network_bit_mappingLUB operacja z kluczowym elementem wyzwalającym
Przykład:
"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
}
…
}
Oto wynik obliczeń klucza wyzwalającego podczas generowania raportu dotyczącego źródła AdTechB:
key_piece:0x400 (010000000000)key_offset:12- Wartość
enrollment_idplatformy AdTechB:2 (010)(zx_network_bit_mapping) - Wynikowy fragment klucza reguły:
0x400 | 0x2 << 12 = 0x2400
Ograniczenia
Listę funkcji pakietu SDK Runtime, nad którymi trwają prace, znajdziesz w informacjach o wersji.
Zgłaszanie błędów i problemów
Twoje opinie są kluczową częścią Piaskownicy prywatności na Androida. Daj nam znać, jeśli napotkasz jakieś problemy lub masz pomysły na ulepszenie Piaskownicy prywatności na Androidzie.