詳閱 Android 版 Privacy Sandbox 說明文件時,請利用「開發人員預覽版」或「Beta 版」按鈕選取您要使用的計畫版本,因為兩者的操作說明可能不盡相同。
Attribution Reporting API 的設計宗旨是要避免仰賴跨方使用者 ID,進一步保護使用者隱私,同時顧及重要使用情境,支援應用程式的歸因與轉換評估功能。本開發人員指南說明如何設定及測試 Attribution Reporting API,針對廣告點擊、瀏覽和轉換事件,透過呼叫可登錄這類事件的相關觸發條件和來源進行登錄作業。
本指南說明如何設定伺服器端點,以及建構呼叫這些服務的用戶端應用程式。要進一步瞭解 Attribution Reporting API 的整體設計,請參閱設計提案。
重要字詞
- 「歸因來源」是指點擊次數或觀看次數。
- 「觸發條件」是指可歸因於轉換的事件。
- 「報表」包含觸發條件和相對應歸因來源的資料。為回應觸發事件,系統會傳送這些報表。Attribution Reporting API 支援事件層級報表和匯總報表。
事前準備
如要使用 Attribution Reporting API,請完成以下各節列出的伺服器端和用戶端工作。
設定 Attribution Reporting API 端點
Attribution Reporting API 需要一組端點,供您透過測試裝置或模擬器存取。為下列伺服器端工作各建立一個端點:
- 登錄歸因來源 (觀看或點擊)
- 登錄觸發條件 (轉換)
- 接受事件層級報表
- 接受可匯總的報表
您可以透過下列幾種方式設定必要的端點:
- 設定和執行最快的方法,是將程式碼範例存放區中的 OpenAPI v3 服務定義部署至模擬或微服務平台。您可以使用 Postman、Prism 或任何其他接受此格式的模擬伺服器平台。部署每個端點,並持續追蹤應用程式中使用的 URI。如要驗證報表提交,請參閱先前對模擬或無伺服器平台發出的呼叫。
- 使用以 Spring Boot 為基礎的 Kotlin 範例執行您自己的獨立伺服器。在您的雲端供應商或內部基礎架構中部署此伺服器。
- 使用服務定義做為將端點整合至現有系統的範例。
接受來源登錄
此端點應可從與以下類似的 URI 定址:
https://adtech.example/attribution_source
用戶端應用程式登錄歸因來源時,就會提供此伺服器端點的 URI。然後 Attribution Reporting 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,Attribution Reporting API 就會向每個 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。然後 Attribution Reporting API 會發出要求,並包含下列其中一個標頭:
設定伺服器端點以回應以下項目:
// 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 not 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 not 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 not 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
每個匯總鍵 ID 和篩選字串最多只能有 25 個位元組。也就是說,匯總鍵 ID 和篩選字串不應超過 25 個字元。在這個範例中,campaignCounts
有 14 個字元,因此是有效的匯總鍵 ID;1234
有 4 個字元,也是有效的篩選字串。如果匯總鍵 ID 或篩選字串超過 25 個字元,系統就會忽略觸發條件。
如果 Attribution-Reporting-Redirect
包含廣告技術合作夥伴的 URI,Attribution Reporting API 就會向每個 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 will not 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 will not
// 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 中定址。如要進一步瞭解如何註冊 URI,請參閱「註冊 Privacy Sandbox 帳戶」一文 (系統會透過接受來源登錄和觸發條件登錄所用的伺服器 eTLD+1 推斷 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 中定址。如要進一步瞭解如何註冊 URI,請參閱「註冊 Privacy Sandbox 帳戶」一文 (系統會透過接受來源登錄和觸發事件登錄所用的伺服器來源推斷 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 does not yet encrypt aggregate reports.
// Currently, 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 用戶端
用戶端應用程式會登錄歸因來源和觸發條件,並啟用產生事件層級報表和可匯總報表的功能。如要準備使用 Attribution Reporting API 的 Android 用戶端裝置或模擬器,請執行以下操作:
- 為 Android 版 Privacy Sandbox 設定開發環境。
- 在支援的裝置中安裝系統映像檔,或設定支援 Android 版 Privacy Sandbox 的模擬器。
執行下列 ADB 指令,啟用 Attribution Reporting API 的存取權。(這個 API 預設為停用狀態)。
adb shell device_config put adservices ppapi_app_allow_list \"\*\"
如果您要在本機測試 Attribution Reporting API (例如在您可實際存取的裝置上測試),請執行下列指令來停用註冊功能:
adb shell device_config put adservices disable_measurement_enrollment_check "true"
在 Android 資訊清單檔案中加入
ACCESS_ADSERVICES_ATTRIBUTION
權限,並為應用程式建立廣告服務設定,即可使用 Attribution Reporting API:<uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
(選用) 如果您打算接收偵錯報表,請在 Android 資訊清單檔案中加入
ACCESS_ADSERVICES_AD_ID
權限:<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()
來登錄歸因來源,如程式碼片段所示。
Attribution Reporting API 支援下列歸因來源事件類型:
- 點擊 (通常可在類似
onClick()
的回呼方法中登錄)。對應的觸發事件通常會在點擊事件之後發生。此類型事件可提供使用者互動的詳細資訊,因此是可以提供較高優先順序的良好歸因類型。 觀看 (通常可在類似
onAdShown()
的回呼方法中登錄)。對應的觸發事件可能會在觀看事件發生的數小時或數天後發生。
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);
登錄後,API 會在 attributionSourceUri
指定的位址向服務端點發出 HTTP POST 要求。端點的回應包括 destination, source_event_id, expiry
和 source_priority
的值。
如果原始廣告技術想要共用來源登錄,原始的歸因來源 URI 就可能包含其他廣告技術端點的重新導向。如要進一步瞭解適用於重新導向的限制和規則,請參閱技術提案。
目前已支援 registerSource
和 registerTrigger
的串連重新導向。除了登錄標頭以外,API 取用者現在也能針對其他登錄作業,以伺服器回應的形式提供 HTTP 重新導向,這類回應會提供 302 狀態碼,以及含有下一個前往網址的「Location」標頭。
只有首次造訪時提供的「destination」欄位會用於串連。造訪次數上限與「Attribution-Reporting-Redirect」標頭數量上限相同。除了現有的「Attribution-Reporting-Redirect」支援功能外,也可以使用這項重新導向支援功能。如果同時擁有這兩項功能,會以「Attribution-Reporting-Redirect」為優先。
登錄轉換觸發事件
如要登錄轉換觸發事件,請在應用程式中呼叫 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)
登錄後,API 會在 attributionTriggerUri
指定的位址向服務端點發出 HTTP POST 要求。端點的回應包含事件和匯總報表的值。
如果原始廣告技術平台允許共用觸發條件登錄,則 URI 可能包含屬於其他廣告技術平台的 URI 重新導向。如要進一步瞭解重新導向適用的限制和規則,請參閱技術提案。
登錄跨應用程式和網站評估
如果從來源到觸發事件的使用者歷程同時涉及應用程式和瀏覽器,廣告事件登錄的實作方式會稍有不同。如果使用者在應用程式中看到廣告,經重新導向至瀏覽器完成轉換,來源就會由應用程式登錄,轉換則由網路瀏覽器登錄。同樣地,假如使用者一開始是在網路瀏覽器中操作,然後前往應用程式完成轉換,來源就會由瀏覽器登錄,轉換則由應用程式登錄。
由於廣告技術在網頁上和 Android 系統上的組織方式不同,因此我們加入新的 API,方便在瀏覽器發生來源和觸發事件時進行登錄作業。這些 API 與相對應的應用程式型 API 之間的主要差異在於,我們會預期瀏覽器追蹤重新導向、套用所有瀏覽器專用的篩選器,並呼叫 registerWebSource()
或 registerWebTrigger()
,將有效的登錄資料傳遞至平台。
以下程式碼片段提供瀏覽器發出的 API 呼叫範例,示範如何先登錄歸因來源,再將使用者導向至應用程式:
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);
以下程式碼片段提供瀏覽器發出的 API 呼叫範例,示範將使用者從應用程式帶到瀏覽器後,如何登錄轉換:
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);
加入雜訊來保護隱私
事件層級報表中收錄了目的地、歸因來源 ID 和觸發事件資料,會以原始 (未加密) 格式傳送至報表來源。為保護使用者隱私,您可以在其中加入雜訊,讓有心人士較難識別個別使用者的身分。系統會根據差異化隱私架構,產生並傳送加入雜訊的事件層級報表。以下是不同情境的預設雜訊百分比值:
來源類型 |
來源目的地值 |
每項來源登錄作業的雜訊報表機率 |
查看 |
應用程式或網站 |
0.0000025 |
查看 |
應用程式和網站 |
0.0000042 |
點擊 |
應用程式或網站 |
0.0024263 |
點擊 |
應用程式和網站 |
0.0170218 |
在應用程式至網頁的歸因評估中,來源可同時提高對應用程式和網站目的地的轉換,而事件層級報表可指定觸發事件是發生在應用程式還是網站上。為了補足這些額外的細節,在系統產生的雜訊報表中,點擊次數最多約為 7 倍,觀看次數則約為 1.7 倍。
部分廣告技術不需要事件層級報表,就能指定觸發事件是要在應用程式還是網頁目的地發生。廣告技術可以使用 Attribution-Reporting-Register-Source
標頭下的 coarse_event_report_destinations
欄位來減少雜訊。如果指定 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
}
產生並提交報表
Attribution Reporting 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);
});
測試
為協助您開始使用 Attribution Reporting API,您可以使用 GitHub 上的 MeasurementSampleApp 專案。此範例應用程式會示範歸因來源登錄和觸發條件登錄。
如為伺服器端點,請考慮下列參考資源或您的自訂解決方案:
- MeasurementAdTechServerSpec 包含 OpenAPI 服務定義,可部署至支援的模擬或微服務平台。
- MeasurementAdTechServer 包含根據 Google App Engine 適用的 Spring Boot 應用程式模擬伺服器參考實作。
必要條件
在可透過測試裝置或模擬器存取的遠端端點上部署模擬 API。為方便測試,請參閱 MeasurementAdTechServerSpec 和 MeasurementAdTechServer 範例專案。
要測試的功能
即將推出的新功能
彈性事件層級設定
建議您在啟動公用程式測試時採用事件層級報表的預設設定,但可能不適合所有用途。Attribution Reporting API 將支援更具彈性的選用設定,讓廣告技術可進一步控管事件層級報表的結構,並盡可能提高資料的實用性。Attribution Reporting API 將分兩個階段提供額外的彈性:
第 1 階段:精簡版彈性事件層級
我們會在 Attribution-Reporting-Register-Source
中將下列兩個選用參數新增至 JSON:
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 階段新增的參數外,我們也會在 Attribution-Reporting-Register-Source
的 JSON 中加入其他選用參數 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 ensures 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_specs
其中一個指定trigger_data
值的觸發條件進行比對。換句話說,如果觸發條件與這個來源相符,但trigger_data
不是來源設定中的值,系統就會忽略觸發條件。 - 特定觸發條件符合這個規格 (使用
event_report_windows
) 時。請注意,即使前述兩個比對條件失敗,觸發事件仍可與可匯總報表的來源比對。
- 這個規格適用的特定觸發事件資料。這個來源只能與具有
- 用於匯總歸因期內所有觸發條件的匯總及值區化的演算法。這可讓觸發條件指定
value
參數,即可針對特定規格進行加總,但以值區值回報。
觸發條件也支援在 event_trigger_data
的字典中加入選用值參數。
{
"event_trigger_data": [
{
"trigger_data": "2",
"value": 100, // Defaults to 1
"filters": ...
},
...
]
}
每個觸發事件登錄作業最多都會與最多一項觸發條件規格進行比對,並更新相關聯的摘要值。大致來說,系統會在觸發時間:
- 套用通用歸因篩選器。
- 針對每個觸發條件規格,請使用規格的
event_reporting_window
評估規格上的event_trigger_data
,以找出相符內容。如果任何觸發事件規格缺少event_report_windows
子欄位,頂層event_reporting_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>,
}
自訂設定範例
下列是預設設定以外的額外設定。在上述示例中,開發人員的取捨包括:
- 減少預設設定的部分維度 (#觸發事件、觸發資料基數、#windows),以增加另一個維度以維持雜訊等級
- 降低預設設定的部分維度 (#觸發事件、觸發資料基數,#windows),降低雜訊等級
回報觸發事件值區間
這個設定範例支援開發人員只想針對一個報表回溯期 (例如 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
設為計數,因此系統會忽略觸發值。如果登錄了 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 以外的值的觸發條件都不符合歸因資格。因此這個使用案例稱為「二進位檔」。
{
"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
,選擇要與合作夥伴廣告技術共用的鍵。您可以在來源登錄標頭 Attribution-Reporting-Register-Source
底下的選用 shared_aggregation_keys
欄位中宣告這些鍵:
"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"
}
]
新增兩個選用欄位,用於觸發登錄標頭。以下欄位能在可匯總報表鍵中啟用勝出的廣告技術 ID:
x_network_bit_mapping
:與廣告技術 ID 進行位元對應的註冊 IDx_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 AdTech identifier
// bits. eg. If AdTechA's sources wins the attribution then 0x1 here will be
// OR'd with the trigger key pieces to generate the final key piece.
"AdTechA-enrollment_id": "0x1", // Identifier bits in hex for A
"AdTechB-enrollment_id": "0x2" // Identifier bits in hex for B
}
…
}
以下是產生 AdTechB 來源報表時,產生的觸發鍵計算:
key_piece
:0x400 (010000000000)
key_offset
:12
- AdtechB 的
enrollment_id
值:2 (010)
(來自x_network_bit_mapping
) - 結果觸發金鑰:
0x400 | 0x2 << 12 = 0x2400
限制
如需 SDK 執行階段的開發中功能清單,請參閱「版本資訊」。
回報錯誤和問題
您的意見回饋對 Android 版 Privacy Sandbox 至關重要!如果您發現了任何問題,或希望針對 Android 版 Privacy Sandbox 提出改進意見,請告訴我們。