Attribution Reporting API 開發人員指南's 指南

詳閱 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 服務定義部署至模擬或微服務平台。您可以使用 PostmanPrism 或其他接受此格式的模擬伺服器平台。部署每個端點,並持續追蹤在您的應用程式中使用的 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 帳戶 (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 用戶端裝置或模擬器,請採取下列行動:

  1. 設定 Android 版 Privacy Sandbox 開發環境
  2. 將系統映像檔安裝到支援裝置上設定支援 Android 版 Privacy Sandbox 的模擬器
  3. 執行下列 ADB 指令,啟用 Attribution Reporting API 存取權 (這個 API 預設為停用)。

    adb shell device_config put adservices ppapi_app_allow_list \"\*\"
  4. 如果要在本機端測試 Attribution Reporting API (例如在您能實際操作的裝置上測試),請執行下列指令來停用註冊功能:

    adb shell device_config put adservices disable_measurement_enrollment_check "true"
  5. 在 Android 資訊清單檔案中加入 ACCESS_ADSERVICES_ATTRIBUTION 權限,並建立應用程式的廣告服務設定,從而使用 Attribution Reporting API:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
    
  6. (選用) 如果打算接收偵錯報表,請在 Android 資訊清單檔案中加入 ACCESS_ADSERVICES_AD_ID 權限:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID" />
    
  7. 在資訊清單的 <application> 元素中參照廣告服務設定:

    <property android:name="android.adservices.AD_SERVICES_CONFIG"
              android:resource="@xml/ad_services_config" />
    
  8. 指定資訊清單中參照的廣告服務 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, expirysource_priority 的值。

如果發起呼叫的廣告技術希望共用來源登錄資料,那麼原始歸因來源 URI 可以包含至其他廣告技術端點的重新導向。如要進一步瞭解重新導向適用的限制和規則,請參閱技術提案

API 已支援 registerSourceregisterTrigger 的串連重新導向。除了登錄標頭以外,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 專案。此範例應用程式會示範歸因來源登錄和觸發條件登錄。

對於伺服器端點,請考慮使用下列參考資源或您的自訂解決方案:

必要條件

使用可從測試裝置或模擬器存取的遠端端點,部署模擬 API。為方便測試,請參考 MeasurementAdTechServerSpecMeasurementAdTechServer 範例專案。

要測試的功能

即將推出的新功能

彈性事件層級設定

如要開始實用性測試,建議採用事件層級報表的預設設定,但這不一定適用於所有情境。Attribution Reporting API 支援更為彈性的選用設定,讓廣告技術能進一步掌控事件層級報表的結構,最大限度地利用資料。Attribution Reporting API 將分兩階段導入彈性設定:

  • 第 1 階段:精簡彈性事件層級設定;涵蓋第 2 階段的部分設定。
  • 第 2 階段:完整版彈性事件層級設定。

第 1 階段:精簡彈性事件層級

我們會在 JSON 的 Attribution-Reporting-Register-Source 中新增下列兩個選用參數:

  • max_event_level_reports
  • event_report_windows
{
  ...
  // Optional. This is a parameter that acts across all trigger types for the
  // lifetime of this source. It restricts the total number of event-level
  // reports that this source can generate. After this maximum is hit, the
  // source is no longer capable of producing any new data. The use of
  // priority in the trigger attribution algorithm in the case of multiple
  // attributable triggers remains unchanged. Defaults to 3 for navigation
  // sources and 1 for event sources
  "max_event_level_reports": <int>,

  // Optional. Represents a series of time windows, starting at 0. Reports
  // for this source will be delivered an hour after the end of each window.
  // Time is encoded as seconds after source registration. If
  // event_report_windows is omitted, will use the default windows. This
  // field is mutually exclusive with the existing `event_report_window` field.
  // // End time is exclusive.
  "event_report_windows": {
    "start_time": <int>,
    "end_times": [<int>, ...]
  }
}

自訂設定範例

如果開發人員想進行最佳化,從而在較早的報表回溯期接收報表,即可採用這個範例設定。

{
  ...
  "max_event_level_reports": 2,
  "event_report_windows": {
    "end_times": [7200, 43200, 86400] // 2 hours, 12 hours, 1 day in seconds
  }
}

第 2 階段:完全彈性事件層級

除了在第 1 階段新增的參數外,我們也會在 JSON 的 Attribution-Reporting-Register-Source 中新增額外的選用參數 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>,
}

自訂設定範例

以下是預設值以外的其他設定。在所有這類範例中,開發人員需要權衡的項目包括:

  • 是否要減少預設設定的部分維度 (#triggers、觸發事件資料基數、#windows),以便增加其他維度來維持雜訊等級
  • 是否要減少預設設定的部分維度 (#triggers、觸發事件資料基數、#windows),從而降低雜訊等級

回報觸發事件值區

如果開發人員想最佳化單一報表回溯期的值資料,即可採用這個範例設定來縮減報表回溯期,減少雜訊。在此範例中,將 trigger_data 設為 0 以外值的觸發事件都不符合歸因資格。

{
  "trigger_specs": [
  {
    "trigger_data": [0],
    "event_report_windows": {
      "end_times": [604800, 1209600] // 7 days, 14 days represented in seconds
    },
    "summary_window_operator": "value_sum",
    "summary_buckets": [5, 10, 100]
  }],
}

觸發事件可透過設定 value 欄位加以登錄,相關值將加總並分組。舉例來說,如果在登錄來源後的 7 天內有三個觸發事件,值分別是 1、3 和 4。

{ "event_trigger_data": [{"trigger_data": "0", "value": 1}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 3}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 4}] }

這些值將加總為 8,並在 7 天 + 1 小時後於下列報表中回報:

// Report 1
{
  ...
  "trigger_summary_bucket": [5, 9]
}

後續 7 天登錄的觸發事件如下:

{ "event_trigger_data": [{"trigger_data": "0", "value": 50}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 45}] }

這些值加總的算式為 8 + 50 + 45 = 103。14 天 + 1 小時後產生的報表如下:

// Report 2
{
  ...
  "trigger_summary_bucket": [10, 99]
},

// Report 3
{
  ...
  "trigger_summary_bucket": [100, MAX_INT]
}
回報觸發事件數量

以下示範了開發人員該如何設定來源,才能一次取得最多 10 個觸發事件的資料。

{
  "trigger_specs": [
  {
    "trigger_data": [0],
    "event_report_windows": {
      "end_times": [604800] // 7 days represented in seconds
    },
    // This field could be omitted to save bandwidth since the default is "count"
    "summary_window_operator": "count",
    "summary_buckets": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  }],
}

系統會採計 trigger_data 設為 0 的歸因觸發事件,上限為 10 個觸發事件。由於 summary_window_operator 設為 count,因此系統會忽略觸發事件值。如果有 4 個登錄的觸發事件歸因至來源,報表將如下所示:

// Report 1
{
  ...
  "trigger_summary_bucket": [1, 1]
}
// Report 2
{
  ...
  "trigger_summary_bucket": [2, 2]
}
// Report 3
{
  ...
  "trigger_summary_bucket": [3, 3]
}
// Report 4
{
  ...
  "trigger_summary_bucket": [4, 4]
}
「二進位制」回報頻率更高

如果開發人員想瞭解在前 10 天內是否發生至少一次轉換 (無論值為何),並在比預設更短的間隔內收到報表,即可採用這個範例設定。另外,在此範例中,將 trigger_data 設為 0 以外值的觸發事件同樣不符合歸因資格。正因如此,這種做法稱為「二進位制」

{
  "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 與廣告技術 ID 的位元對應
  • x_network_data:勝出廣告技術的 x_network_bit_mapping 偏移 (左側偏移),「或」包含觸發事件鍵的作業
例子:
"Attribution-Reporting-Register-Trigger": {
  "attribution_config": [...],
  "aggregatable_trigger_data": [
    {
     "key_piece": "0x400",
     "source_keys": ["campaignCounts"]
      "x_network_data" : {
        "key_offset" : 12 // [64 bit unsigned integer]
      }
    }
    
  ]
  
  "x_network_bit_mapping": {
   // This mapping is used to generate trigger key pieces with 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_piece0x400 (010000000000)
  • key_offset12
  • AdtechB 的 enrollment_id 值:2 (010) (來自 x_network_bit_mapping)
  • 觸發事件鍵結果:0x400 | 0x2 << 12 = 0x2400

限制

如要查看目前針對 SDK 執行階段開發的功能,請參閱「版本資訊」。

回報錯誤和問題

您的意見回饋對 Android 版 Privacy Sandbox 至關重要!如果您發現了任何問題,或希望針對 Android 版 Privacy Sandbox 提出改進意見,請告訴我們