Attribution Reporting API デベロッパー ガイド

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

Attribution Reporting API は、クロスパーティ ユーザー ID への依存をなくすことでユーザーのプライバシーを向上させ、アプリを対象としたアトリビューションとコンバージョン測定の主要なユースケースをサポートするように設計されています。このデベロッパー ガイドでは、Attribution Reporting API を設定およびテストし、広告のクリック、ビュー、コンバージョンの登録を、このようなイベントに関連するトリガーとソースを登録するメソッドを呼び出すことによって行う方法を説明します。

このガイドでは、サーバー エンドポイントをセットアップし、これらのサービスを呼び出すクライアント アプリを作成する方法について説明します。Attribution Reporting API の全体的な設計について詳しくは、設計案をご覧ください。

主な用語

  • 「アトリビューション ソース」とは、クリックまたはビューのことです。
  • 「トリガー」とは、コンバージョンに関連付けることができるイベントです。
  • 「レポート」には、トリガーと対応するアトリビューション ソースに関するデータが含まれています。このレポートは、トリガー イベントに応答して送信されます。Attribution Reporting API では、イベントレベル レポート集計可能レポートをサポートしています。

準備

Attribution Reporting API を使用するには、以下のセクションに記載されているサーバー側のタスクとクライアント側のタスクを完了してください。

Attribution Reporting API 用エンドポイントのセットアップ

Attribution Reporting API には、テストデバイスまたはエミュレータからアクセスできる一連のエンドポイントが必要です。次のサーバー側タスクごとに 1 つのエンドポイントを作成します。

必要なエンドポイントをセットアップする方法は、いくつかあります。

  • 最も早いのは、サンプルコード リポジトリからモックまたはマイクロサービスのプラットフォームに 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]",
  "source_event_id": "[64 bit unsigned integer]",
  "expiry": "[64 bit signed integer]",
  "source_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
// reports.
Attribution-Reporting-Register-Aggregatable-Source:
[{
  "id": "[key name]",
  "key_piece": "[key piece value]",
 },
 ..
]
// Specify additional ad tech URLs to register this source with.
Attribution-Reporting-Redirects: <Ad tech partner URIs; comma-separated>

サンプル値を追加した例を次に示します。

Attribution-Reporting-Register-Source: {
  "destination": "android-app://com.example.advertiser",
  "source_event_id": "234",
  "expiry": "60000",
  "source_priority": "5",
  "filter_data": {
    "product_id": ["1234"]
  }
}
Attribution-Reporting-Register-Aggregatable-Source:
[{
// Generates a "0x159" key piece named (low order bits of the key) for the key
// named "campaignCounts".
  "id": "campaignCounts",
// User saw an ad from campaign 345 (out of 511).
  "key_piece": "0x159",
},
{
// Generates a "0x5" key piece (low order bits of the key) for the key named "geoValue"
  "id": "geoValue",
// Source-side geo region = 5 (US), out of a possible ~100 regions.
  "key_piece": "0x5",
}]
Attribution-Reporting-Redirects: https://adtechpartner1.example?their_ad_click_id=567, https://adtechpartner2.example?their_ad_click_id=890

Attribution-Reporting-Redirects に広告テクノロジー パートナーの URI が含まれている場合、Attribution Reporting API は各 URI に同様のリクエストを実行します。各広告テクノロジー パートナーは、次のヘッダーで応答するサーバーを設定する必要があります。

Attribution-Reporting-Register-Source: {
  "destination": "[app package name]",
  "source_event_id": "[64 bit unsigned integer]",
  "expiry": "[64 bit signed integer]",
  "source_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-Reporting-Register-Aggregatable-Source:
[{
  "id": "[key name]",
  "key_piece": "[key piece value]",
 },
 ..
]
// The Attribution-Reporting-Redirects header is ignored for ad tech partners.

コンバージョン トリガーの登録を受け入れる

このエンドポイントは、次の例のような URI からアドレス指定可能である必要があります。

https://adtech.example/attribution_trigger

クライアント アプリがトリガー イベントを登録するとき、このサーバー エンドポイントの URI を指定します。次に Attribution Reporting API がリクエストを行い、その際に次のいずれかのヘッダーを含めます。

以下を返すようにサーバー エンドポイントを設定します。

// Metadata associated with trigger.
Attribution-Reporting-Register-Event-Trigger:
[{
    // 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]",
    "trigger_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.

    // Note: "source_type" can be used as a key to filter based on the source's
    // type "navigation" or "event". The first Event-Trigger that matches (based
    // on the filters/not_filters) will be used for report generation. If none
    // of the event-trigger matches, 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"],
    }
}]

// Specify a list of dictionaries that generates aggregation keys.
Attribution-Reporting-Register-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.
Attribution-Reporting-Register-Aggregatable-Values:
[
   // Each source event can contribute a maximum of L1 = 2^16 to the aggregate
   // histogram.
  {
   "[key_name]": [value]
  }
]
// Specify additional Adtech URLs to register this trigger with.
Attribution-Reporting-Redirects: <Ad tech partner URIs, comma-separated>

サンプル値を追加した例を次に示します。

Attribution-Reporting-Register-Event-Trigger: [{
    "trigger_data": "1122", // Returns 010 for CTCs and 0 for VTCs in reports.
    "trigger_priority": "3",
    "deduplication_key": "3344"
    "filters": {
      "product_id": ["1234"],
      "source_type": ["event"]
    }
},
{
    "trigger_data": "4", // Returns 100 for CTCs and 0 for VTCs in reports.
    "trigger_priority": "3",
    "deduplication_key": "3344"
    "filters": {
      "product_id": ["1234"],
      "source_type": ["navigation"]
    }
}
]
Attribution-Reporting-Register-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
  // will take up 9 bits in the resulting key.
    "key_piece": "0x400",// Conversion type purchase = 2
    // Apply this key piece to:
    "source_keys": ["campaignCounts"]
  },
  {
  // 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 will take up 7 bits of space in the resulting key.
  "key_piece": "0xA80",
  // Apply this key piece to:
  "source_keys": ["geoValue", "nonMatchingIdsListedHereAreIgnored"]
  }
]
Attribution-Reporting-Register-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
  }
]
Attribution-Reporting-Redirects:https://adtechpartner.example?app_install=567

Attribution-Reporting-Redirects に広告テクノロジー パートナーの URI が含まれている場合、Attribution Reporting API は各 URI に同様のリクエストを実行します。各広告テクノロジー パートナーは、次のヘッダーで応答するサーバーを設定する必要があります。

// Metadata associated with trigger.
Attribution-Reporting-Register-Event-Trigger:
[{
    // 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]",
    "trigger_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.
    // Note: "source_type" can be used as a key to filter based on the source's
    // type "navigation" or "event".
    // The first Event-Trigger that matches (based on the filters/not_filters)
    // will be used for report generation. If none of the event-trigger
    // matches, 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"],
    }
}]

// Specify a list of dictionaries that generates aggregation keys.
Attribution-Reporting-Register-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.
Attribution-Reporting-Register-Aggregatable-Values:
[
   // Each source event can contribute a maximum of L1 = 2^16 to the aggregate
   // histogram.
  {
   "[key_name]": [value]
  }
]
// The Attribution-Reporting-Redirects header is ignored for ad tech partners.

イベントレベル レポートを受け入れる

このエンドポイントは、次の URI からアドレス指定できる必要があります。Android 版プライバシー サンドボックスが独自のポストバック URI の登録をサポートするまで、この URI は、ソースの登録とトリガーの登録の受け入れに使用されるサーバーの eTLD+1 から推定されます。このエンドポイントの URI は、ソースの登録を受け入れるエンドポイントと、トリガーの登録を受け入れるエンドポイントの URI の例を使用すると、次のようになります。

https://adtech.example/.well-known/attribution-reporting/report-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"
}

集約可能レポートを受け入れる

このエンドポイントは、次の URI からアドレス指定できる必要があります。Android 版プライバシー サンドボックスが独自のポストバック URI の登録をサポートするまで、この URI は、ソースの登録とトリガーの登録の受け入れに使用されるサーバーのオリジンから推定されます。このエンドポイントの URI は、ソースの登録を受け入れるエンドポイントと、トリガーの登録を受け入れるエンドポイントの URI の例を使用すると、次のようになります。

https://adtech.example/.well-known/attribution-reporting/report-aggregate-attribution

次の形式を使用する JSON リクエストを受け入れるように、このサーバーを設定します。

{
  // Info that the aggregation services also need encoded in JSON
  // for use with AEAD. Line breaks added for readability.
  "shared_info": "{
     \"api\":\"attribution-reporting\",
     \"attribution_destination\": \"android-app://com.advertiser.example.advertiser\",
     \"scheduled_report_time\":\"[timestamp in seconds]\",
     \"source_registration_time\": \"[timestamp in seconds]\",
     \"version\":\"[api version]\",
     \"report_id\":\"[UUID]\",
     \"reporting_origin\":\"https://reporter.example\" }",

  // In the current Developer Preview release, The "payload" and "key_id" fields
  // are not used because the platform 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 版プライバシー サンドボックス用に開発環境をセットアップします。
  2. サポート対象のデバイスにシステム イメージをインストールするか、Android 版プライバシー サンドボックスのサポートを含むエミュレータをセットアップします。

広告イベントを登録する

アプリで適切にレポートされるように、ソースとコンバージョンの発生時に登録する必要があります。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 には他の広告テクノロジー エンドポイントへのリダイレクトを含めることができます。リダイレクトに適用される制限やルールは、技術提案で詳しく説明しています。

コンバージョン トリガー イベントを登録する

コンバージョン トリガー イベントを登録するには、アプリで 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 へのリダイレクトを含めることができます。リダイレクトに適用される制限やルールは、技術提案で詳しく説明しています。

レポートを生成して配信する

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

レポートの強制配信

レポートジョブが強制的に実行される場合でも、システムはスケジュールされた配信時間(数時間から数日の範囲)に従ってレポートを送信します。テスト目的で、デバイスのシステム時刻をスケジュールされた遅延時刻より後になるように進めて、レポート配信を開始させることができます。

サーバーでレポートを確認する

レポートが送信されたら、受信したレポート、モックサーバーの履歴やカスタム システムなどの該当するサーバーログをチェックして、配信を確認します。

テスト

Attribution Reporting API の使用を開始する際は、GitHub の MeasurementSampleApp プロジェクトを使用してください。このサンプルアプリでは、アトリビューション ソースの登録とトリガーの登録を行います。

サーバー エンドポイントについては、次のリファレンス資料やカスタム ソリューションを検討してください。

  • MeasurementAdTechServerSpec には、サポートされているモックまたはマイクロサービスのプラットフォームにデプロイ可能な OpenAPI サービス定義が含まれています。
  • MeasurementAdTechServer には、Google App Engine 用の Spring Boot アプリをベースにしたモックサーバーのリファレンス実装が含まれています。

前提条件

テストデバイスまたはエミュレータからアクセス可能なリモート エンドポイントにモック API をデプロイします。テストを簡単に行うために、MeasurementAdTechServerSpecMeasurementAdTechServer のサンプル プロジェクトを参照してください。

テストする機能

  • アトリビューション ソースとコンバージョン トリガーの登録を行います。サーバーサイド エンドポイントが正しい形式で応答することを確認します。
  • レポートジョブを実行します。
  • テストサーバーのバックエンドまたはコンソールで、レポートの配信を確認します

制限事項

SDK ランタイムに関する開発中の機能の一覧については、リリースノートをご覧ください。

バグと問題を報告する

皆様からのフィードバックは、Android 版プライバシー サンドボックスに欠かせない要素です。問題が見つかった場合や Android 版プライバシー サンドボックスを改善するためのアイデアがありましたらお知らせください。