Panduan developer Attribution Reporting API

Saat Anda membaca dokumentasi Privacy Sandbox di Android, gunakan tombol Pratinjau Developer atau Beta untuk memilih versi program yang sedang Anda gunakan, karena petunjuknya dapat bervariasi.


Berikan masukan

Attribution Reporting API dirancang untuk memberikan privasi pengguna yang lebih baik dengan menghapus ketergantungan pada ID pengguna lintas pihak, dan untuk mendukung kasus penggunaan utama untuk atribusi dan pengukuran konversi di berbagai aplikasi. Panduan developer ini menjelaskan cara mengonfigurasi dan menguji Attribution Reporting API untuk mendaftarkan klik, penayangan, dan konversi iklan dengan memanggil metode yang mendaftarkan pemicu dan sumber peristiwa yang relevan untuk peristiwa tersebut.

Panduan ini menunjukkan cara menyiapkan endpoint server dan membuat aplikasi klien yang memanggil layanan tersebut. Pelajari lebih lanjut desain keseluruhan Attribution Reporting API dalam proposal desain.

Istilah Kunci

  • Sumber atribusi merujuk pada klik atau penayangan.
  • Pemicu adalah peristiwa yang dapat diatribusikan ke konversi.
  • Laporan berisi data tentang pemicu dan sumber atribusi yang sesuai. Laporan ini dikirim sebagai respons terhadap peristiwa pemicu. Attribution Reporting API mendukung laporan tingkat peristiwa dan laporan agregat.

Sebelum memulai

Untuk menggunakan Attribution Reporting API, selesaikan tugas sisi server dan sisi klien yang tercantum di bagian berikut.

Menyiapkan endpoint Attribution Reporting API

Attribution Reporting API memerlukan sekumpulan endpoint yang dapat Anda akses dari perangkat pengujian atau emulator. Buat satu endpoint untuk setiap tugas sisi server berikut:

Ada beberapa metode untuk menyiapkan endpoint yang diperlukan:

  • Cara tercepat untuk memulai dan menjalankan adalah men-deploy definisi layanan OpenAPI v3 dari repositori kode contoh kami ke platform tiruan atau microservice. Anda dapat menggunakan Postman, Prism, atau platform server tiruan lainnya yang menerima format ini. Deploy setiap endpoint dan lacak URI untuk digunakan di aplikasi. Untuk memverifikasi pengiriman laporan, lihat panggilan yang sebelumnya dilakukan ke platform tiruan atau tanpa server.
  • Jalankan server mandiri menggunakan contoh Kotlin berbasis Spring Boot. Deploy server ini di penyedia cloud atau infrastruktur internal Anda.
  • Gunakan definisi layanan sebagai contoh untuk mengintegrasikan endpoint ke dalam sistem yang ada.

Menerima pendaftaran sumber

Endpoint ini harus dapat ditangani dari URI yang mirip dengan yang berikut ini:

https://adtech.example/attribution_source

Saat mendaftarkan sumber atribusi, aplikasi klien akan memberikan URI untuk endpoint server ini. Kemudian, Attribution Reporting API akan membuat permintaan dan menyertakan salah satu header berikut:

  • Untuk peristiwa klik:

    Attribution-Reporting-Source-Info: navigation
    
  • Untuk peristiwa penayangan:

    Attribution-Reporting-Source-Info: event
    

Konfigurasikan endpoint server Anda untuk merespons hal-hal berikut:

// 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>

Berikut adalah contoh dengan nilai sampel yang ditambahkan:

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

Jika Attribution-Reporting-Redirects berisi URI partner teknologi iklan, Attribution Reporting API akan membuat permintaan yang serupa ke setiap URI. Setiap partner teknologi iklan harus mengonfigurasi server yang merespons dengan header ini:

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.

Menerima pendaftaran pemicu konversi

Endpoint ini harus dapat ditangani dari URI yang mirip dengan yang berikut ini:

https://adtech.example/attribution_trigger

Saat mendaftarkan peristiwa pemicu, aplikasi klien memberikan URI untuk endpoint server ini. Kemudian, Attribution Reporting API akan membuat permintaan dan menyertakan salah satu header berikut:

Konfigurasikan endpoint server Anda untuk merespons hal-hal berikut:

// 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>

Berikut adalah contoh dengan nilai sampel yang ditambahkan:

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

Per ID kunci agregasi dan string filter dibatasi hanya 25 byte. Artinya, ID kunci agregasi dan string filter tidak boleh melebihi 25 karakter. Dalam contoh ini, campaignCounts adalah 14 karakter sehingga merupakan ID kunci agregasi yang valid, dan 1234 adalah 4 karakter sehingga merupakan string filter yang valid. Jika ID kunci atau string filter agregasi melebihi 25 karakter, pemicu akan diabaikan.

Jika Attribution-Reporting-Redirect berisi URI partner teknologi iklan, Attribution Reporting API akan membuat permintaan yang serupa ke setiap URI. Setiap partner teknologi iklan harus mengonfigurasi server yang merespons dengan header ini:

// 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.

Menerima laporan tingkat peristiwa

Endpoint ini harus dapat ditangani dari URI. Lihat Mendaftar ke akun Privacy Sandbox untuk mengetahui informasi selengkapnya tentang mendaftarkan URI. (URI akan disimpulkan dari asal server yang digunakan untuk menerima pendaftaran sumber dan pendaftaran pemicu.) Dengan menggunakan contoh URI untuk endpoint yang menerima pendaftaran sumber dan menerima pendaftaran pemicu, URI endpoint ini adalah:

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

Konfigurasikan server ini untuk menerima permintaan JSON yang menggunakan format berikut:

{
  "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]",
}

Kunci debug memungkinkan insight tambahan dalam laporan atribusi Anda; pelajari lebih lanjut cara mengonfigurasinya.

Menerima laporan gabungan

Endpoint ini harus dapat ditangani dari URI. Lihat Mendaftar ke akun Privacy Sandbox untuk mengetahui informasi selengkapnya tentang mendaftarkan URI. (URI akan disimpulkan dari asal server yang digunakan untuk menerima pendaftaran sumber dan pendaftaran pemicu.) Dengan menggunakan contoh URI untuk endpoint yang menerima pendaftaran sumber dan menerima pendaftaran pemicu, URI endpoint ini adalah:

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

Kolom terenkripsi dan tidak terenkripsi diisi untuk laporan agregat. Laporan terenkripsi memungkinkan Anda untuk memulai pengujian dengan layanan agregasi, sementara kolom yang tidak dienkripsi memberikan insight tentang cara struktur key-value pair ditetapkan dalam data.

Konfigurasikan server ini untuk menerima permintaan JSON yang menggunakan format berikut:

{
  // 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]"
}

Kunci debug memungkinkan insight tambahan dalam laporan atribusi Anda; pelajari lebih lanjut cara mengonfigurasinya.

Menyiapkan klien Android

Aplikasi klien mendaftarkan sumber dan pemicu atribusi, serta mengaktifkan pembuatan laporan tingkat peristiwa dan gabungan. Untuk menyiapkan perangkat klien atau emulator Android untuk menggunakan Attribution Reporting API, lakukan hal berikut:

  1. Menyiapkan lingkungan pengembangan Anda untuk Privacy Sandbox di Android.
  2. Menginstal image sistem ke perangkat yang didukung atau menyiapkan emulator yang menyertakan dukungan untuk Privacy Sandbox di Android.
  3. Aktifkan akses ke Attribution Reporting API dengan menjalankan perintah ADB berikut. (API tersebut dinonaktifkan secara default.)

    adb shell device_config put adservices ppapi_app_allow_list \"\*\"
    
  4. Jika Anda menguji Attribution Reporting API secara lokal (seperti menguji pada perangkat yang aksesnya Anda miliki secara fisik), jalankan perintah ini untuk menonaktifkan pendaftaran:

    adb shell device_config put adservices disable_measurement_enrollment_check "true"
    
  5. Sertakan izin ACCESS_ADSERVICES_ATTRIBUTION dalam file Manifes Android Anda dan buat konfigurasi layanan iklan agar aplikasi Anda dapat menggunakan Attribution Reporting API:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
    
  6. (Opsional) Jika berencana untuk menerima laporan debug, sertakan izin ACCESS_ADSERVICES_AD_ID dalam file Manifes Android Anda:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID" />
    
  7. Referensikan konfigurasi layanan iklan di elemen <application> manifes Anda:

    <property android:name="android.adservices.AD_SERVICES_CONFIG"
              android:resource="@xml/ad_services_config" />
    
  8. Tentukan resource XML layanan iklan yang dirujuk dalam manifes, seperti res/xml/ad_services_config.xml. Pelajari izin layanan iklan dan kontrol akses SDK lebih lanjut.

    <ad-services-config>
        <attribution allowAllToAccess="true" />
    </ad-services-config>
    

Mendaftarkan peristiwa iklan

Aplikasi Anda harus mendaftarkan sumber dan konversi saat keduanya terjadi untuk memastikan sumber dan konversi tersebut dilaporkan dengan benar. Class MeasurementManager memiliki metode untuk membantu Anda mendaftarkan peristiwa sumber atribusi dan pemicu konversi.

Mendaftarkan peristiwa sumber atribusi

Saat iklan ditayangkan atau diklik, aplikasi penayang akan memanggil registerSource() untuk mendaftarkan sumber atribusi seperti yang ditampilkan dalam cuplikan kode.

Attribution Reporting API mendukung jenis peristiwa sumber atribusi berikut:

  • Klik, yang biasanya Anda daftarkan dalam metode callback yang mirip dengan onClick(). Peristiwa pemicu yang sesuai biasanya akan segera terjadi setelah peristiwa klik. Jenis peristiwa ini memberikan lebih banyak informasi interaksi pengguna, dan oleh karena itu, merupakan jenis sumber atribusi yang baik untuk memberikan prioritas yang tinggi.
  • Penayangan, yang biasanya Anda daftarkan dalam metode callback yang mirip dengan onAdShown(). Peristiwa pemicu yang sesuai mungkin terjadi beberapa jam atau hari setelah peristiwa penayangan.

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);

Setelah pendaftaran, API mengeluarkan permintaan POST HTTP ke endpoint layanan di alamat yang ditentukan oleh attributionSourceUri. Respons endpoint menyertakan nilai untuk destination, source_event_id, expiry, dan source_priority.

Jika teknologi iklan asal ingin membagikan pendaftaran sumber, URI sumber atribusi asli dapat menyertakan pengalihan ke endpoint teknologi iklan lainnya. Batas dan aturan yang berlaku untuk pengalihan dijelaskan secara terperinci di proposal teknis.

Dukungan telah ditambahkan untuk pengalihan daisy-chain untuk registerSource dan registerTrigger. Selain header pendaftaran, konsumen API kini dapat menyediakan pengalihan HTTP sebagai respons server yang menyertakan kode status 302 dan header "Location" dengan URL berikutnya yang akan dikunjungi untuk pendaftaran tambahan.

Hanya kolom "destination" yang disediakan dalam kunjungan pertama yang digunakan di seluruh daisy-chain. Jumlah kunjungan memiliki batas yang sama dengan header "Attribution-Reporting-Redirect". Dukungan pengalihan ini merupakan tambahan untuk dukungan "Attribution-Reporting-Redirect" yang sudah ada, dan jika keduanya ada, "Attribution-Reporting-Redirect" akan mendapatkan preferensi.

Mendaftarkan peristiwa pemicu konversi

Untuk mendaftarkan peristiwa pemicu konversi, panggil registerTrigger() di aplikasi Anda:

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)

Setelah pendaftaran, API mengeluarkan permintaan POST HTTP ke endpoint layanan di alamat yang ditentukan oleh attributionTriggerUri. Respons endpoint mencakup nilai untuk laporan peristiwa dan gabungan.

Jika platform teknologi iklan asal memungkinkan pendaftaran pemicu dibagikan, URI dapat menyertakan pengalihan ke URI yang merupakan bagian dari platform teknologi iklan lainnya. Batas dan aturan yang berlaku untuk pengalihan dijelaskan dalam proposal teknis.

Mendaftarkan pengukuran lintas aplikasi dan web

Jika aplikasi dan browser memainkan peran dalam perjalanan pengguna dari sumber ke pemicu, ada sedikit perbedaan dalam penerapan pendaftaran peristiwa iklan. Jika pengguna melihat iklan pada aplikasi dan dialihkan ke browser untuk konversi, sumber akan didaftarkan oleh aplikasi, dan konversi oleh browser web. Demikian pula, jika pengguna memulai di browser web dan diarahkan ke aplikasi untuk dikonversi, browser akan mendaftarkan sumbernya dan aplikasi akan mendaftarkan konversi.

Karena ada perbedaan dalam cara pengaturan teknologi iklan di web dan Android, kami telah menambahkan API baru untuk mendaftarkan sumber dan pemicu saat pendaftaran dilakukan di browser. Perbedaan utama antara API ini dan API berbasis aplikasi yang sesuai adalah browser akan mengikuti pengalihan, menerapkan filter khusus browser, dan meneruskan pendaftaran yang valid ke platform dengan memanggil registerWebSource() atau registerWebTrigger().

Cuplikan kode berikut menampilkan contoh panggilan API yang dibuat browser untuk mendaftarkan sumber atribusi sebelum mengarahkan pengguna ke aplikasi:

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);

Cuplikan kode berikut menampilkan contoh panggilan API yang dilakukan browser untuk mendaftarkan konversi setelah pengguna diarahkan dari aplikasi:

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);

Menambahkan derau untuk privasi

Laporan tingkat peristiwa berisi data tujuan, ID sumber atribusi, dan pemicu. Seluruhnya dikirim dalam format asli (tidak terenkripsi) ke origin pelaporan. Untuk melindungi privasi pengguna, kami dapat menambahkan derau agar lebih sulit mengidentifikasi masing-masing pengguna. Laporan tingkat peristiwa dengan derau dibuat dan dikirim sesuai dengan framework privasi diferensial. Berikut adalah nilai persentase derau default untuk berbagai skenario:

Jenis sumber

Nilai tujuan sumber

Probabilitas laporan bising per pendaftaran sumber

Lihat

Aplikasi atau web

0,0000025

Lihat

Aplikasi dan web

0,0000042

Klik

Aplikasi atau web

0,0024263

Klik

Aplikasi dan web

0,0170218

Dalam pengukuran atribusi aplikasi ke web, tempat sumber dapat mendorong konversi ke tujuan aplikasi dan web, laporan tingkat peristiwa dapat menentukan apakah pemicu terjadi di aplikasi atau web. Sebagai kompensasi atas detail tambahan ini, laporan derau yang dihasilkan hingga ~7x untuk klik dan ~1,7x untuk penayangan.

Beberapa teknologi iklan tidak memerlukan laporan tingkat peristiwa untuk menentukan apakah pemicu terjadi di tujuan aplikasi atau web. Teknologi iklan dapat menggunakan kolom coarse_event_report_destinations di bawah header Attribution-Reporting-Register-Source untuk mengurangi derau. Jika sumber dengan kolom coarse_event_report_destinations yang ditentukan memenangkan atribusi, laporan yang dihasilkan akan menyertakan tujuan aplikasi dan web tanpa membedakan tempat sebenarnya pemicu terjadi.

Pada contoh berikut, pengguna mengklik iklan dan sumber tersebut didaftarkan dengan API. Pengguna kemudian melakukan konversi di aplikasi pengiklan dan situs pengiklan. Kedua konversi ini terdaftar sebagai pemicu dan diatribusikan ke klik awal.

Header HTTP pendaftaran sumber berbasis klik:

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"
}

Pemicu didaftarkan dari aplikasi dengan nama paket com.advertiser.example:

Attribution-Reporting-Register-Trigger: {
    "event_trigger_data": [{
    "trigger_data": "1",
    "priority": "1"
    }],
}

Pemicu didaftarkan dari browser dari situs dengan domain eTLD+1 https://advertiser.com:

Attribution-Reporting-Register-Trigger: {
    "event_trigger_data": [{
    "trigger_data": "2",
    "priority": "2"
    }],
}

Hasil laporan tingkat peristiwa akan dibuat. Dengan asumsi kedua pemicu tersebut diatribusikan ke sumber, laporan tingkat peristiwa berikut akan dibuat:

  {
    "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
  }

Membuat dan mengirimkan laporan

Attribution Reporting API mengirimkan laporan ke endpoint di server Anda yang menerima laporan tingkat peristiwa dan laporan agregat.

Memaksa tugas pelaporan agar berjalan

Setelah Anda mendaftarkan peristiwa sumber atribusi atau mendaftarkan peristiwa pemicu, sistem akan menjadwalkan tugas pelaporan untuk dijalankan. Secara default, tugas ini berjalan setiap 4 jam. Untuk tujuan pengujian, Anda dapat memaksa tugas pelaporan untuk dijalankan atau mempersingkat interval antartugas.

Memaksa tugas atribusi untuk dijalankan:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 5

Memaksa tugas pelaporan tingkat peristiwa untuk dijalankan:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 3

Memaksa tugas pelaporan gabungan untuk dijalankan:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 7

Memeriksa output di logcat untuk melihat kapan tugas telah berjalan. Output tersebut harus terlihat seperti berikut:

JobScheduler: executeRunCommand(): com.google.android.adservices.api/0 5 s=false f=true

Memaksa pengiriman laporan

Meskipun tugas pelaporan dipaksa untuk dijalankan, sistem masih akan mengirimkan laporan sesuai dengan waktu pengiriman terjadwal yang berkisar dari beberapa jam hingga beberapa hari. Untuk tujuan pengujian, Anda dapat meningkatkan waktu sistem perangkat menjadi setelah keterlambatan yang dijadwalkan untuk memulai pengiriman laporan.

Memverifikasi laporan di server

Setelah laporan dikirim, verifikasi pengiriman dengan memeriksa laporan yang diterima, log server yang berlaku, seperti histori server tiruan atau sistem kustom.

Mendekode laporan agregat

Saat menerima laporan gabungan, kolom debug_cleartext_payload akan menyimpan versi laporan gabungan yang tidak dienkripsi. Meskipun versi laporan tidak dienkripsi, versi ini masih perlu didekode.

Di bawah ini adalah contoh decoding konten kolom debug_cleartext_payload dalam dua langkah: langkah pertama menggunakan decoding Base 64, dan langkah kedua menggunakan decoding 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);
});

Pengujian

Untuk membantu Anda memulai Attribution Reporting API, Anda dapat menggunakan project MeasurementSampleApp di GitHub. Aplikasi contoh ini menunjukkan pendaftaran sumber atribusi dan pendaftaran pemicu.

Untuk endpoint server, pertimbangkan resource referensi berikut atau solusi kustom Anda:

  • MeasurementAdTechServerSpec mencakup definisi layanan OpenAPI yang dapat di-deploy ke platform tiruan atau microservice yang didukung.
  • MeasurementAdTechServer menyertakan implementasi referensi server tiruan berdasarkan aplikasi Spring Boot untuk Google App Engine.

Prasyarat

Deploy API tiruan di endpoint jarak jauh yang dapat diakses dari perangkat pengujian atau emulator. Untuk memudahkan pengujian, lihat project contoh MeasurementAdTechServerSpec dan MeasurementAdTechServer.

Fungsi yang akan diuji

  • Menggunakan pendaftaran sumber atribusi dan pemicu konversi. Pastikan endpoint sisi server merespons dengan format yang benar.
  • Menjalankan tugas pelaporan.
  • Memverifikasi pengiriman laporan di backend atau konsol server pengujian Anda.

Fitur mendatang

Konfigurasi tingkat peristiwa fleksibel

Konfigurasi default untuk pelaporan tingkat peristiwa disarankan untuk memulai pengujian utilitas, tetapi mungkin tidak ideal untuk semua kasus penggunaan. Attribution Reporting API akan mendukung konfigurasi opsional yang lebih fleksibel sehingga teknologi iklan meningkatkan kontrol terhadap struktur laporan tingkat peristiwa dan dapat memaksimalkan utilitas data. Fleksibilitas tambahan ini akan diperkenalkan ke Attribution Reporting API dalam dua fase:

  • Fase 1: Konfigurasi tingkat peristiwa fleksibel lite; bagian dari Fase 2.
  • Fase 2: Versi penuh konfigurasi tingkat peristiwa fleksibel.

Fase 1: Tingkat peristiwa fleksibel lite

Kami akan menambahkan dua parameter opsional berikut ke JSON di 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>, ...]
  }
}

Contoh konfigurasi kustom

Contoh konfigurasi ini mendukung developer yang ingin mengoptimalkan penerimaan laporan pada periode pelaporan sebelumnya.

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

Fase 2: Tingkat peristiwa fleksibel penuh

Selain parameter yang ditambahkan pada Fase 1, kami akan menambahkan parameter opsional tambahan trigger_specs ke JSON di Attribution-Reporting-Register-Source.

{
  // A trigger spec is a set of matching criteria, along with a scheme to
  // generate bucketized output based on accumulated values across multiple
  // triggers within the specified event_report_window. There will be a limit on
  // the number of specs possible to define for a source.
  "trigger_specs": [{
    // This spec will only apply to registrations that set one of the given
    // trigger data values (non-negative integers) in the list.
    // trigger_data will still appear in the event-level report.
    "trigger_data": [<int>, ...]

    // Represents a series of time windows, starting at the source registration
    // time. Reports for this spec will be delivered an hour after the end of
    // each window. Time is encoded as seconds after source registration.
    // end_times must consist of strictly increasing positive integers.
    //
    // Note: specs with identical trigger_data cannot have overlapping windows;
    // this 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>, ...]
  }
}

Konfigurasi ini sepenuhnya menentukan ruang output laporan tingkat peristiwa, per pendaftaran sumber. Untuk setiap spesifikasi pemicu, kami sepenuhnya menentukan:

  • Serangkaian kriteria yang cocok:
    • Data pemicu tertentu yang diterapkan dengan spesifikasi ini. Sumber ini memenuhi syarat untuk dicocokkan hanya dengan pemicu yang memiliki salah satu nilai trigger_data yang ditentukan di trigger_specs. Dengan kata lain, jika pemicu akan cocok dengan sumber ini, tetapi trigger_data-nya bukan salah satu dari nilai dalam konfigurasi sumber, pemicu akan diabaikan.
    • Saat pemicu tertentu cocok dengan spesifikasi ini (menggunakan event_report_windows). Perhatikan bahwa pemicu masih dapat dicocokkan dengan sumber untuk laporan agregat meskipun dua kriteria pencocokan yang disebutkan sebelumnya gagal.
  • Algoritma spesifik untuk meringkas dan menjadikan semua pemicu satu bucket dalam periode atribusi. Hal ini memungkinkan pemicu menentukan parameter value yang akan diringkas untuk spesifikasi tertentu, tetapi dilaporkan sebagai nilai dalam bucket.

Pemicu juga akan mendukung penambahan parameter nilai opsional di kamus dalam event_trigger_data.

{
  "event_trigger_data": [
    {
      "trigger_data": "2",
      "value": 100,  // Defaults to 1
      "filters": ...
    },
    ...
  ]
}

Setiap pendaftaran pemicu akan cocok dengan maksimal satu spesifikasi pemicu dan memperbarui nilai ringkasan yang terkait. Pada level yang tinggi, pada waktu pemicu, kami akan:

  • Menerapkan filter atribusi global.
  • Untuk setiap spesifikasi pemicu, evaluasi event_trigger_data pada spesifikasi untuk menemukan kecocokan, menggunakan event_reporting_window spesifikasi. event_reporting_windows level teratas bertindak sebagai nilai default jika spesifikasi pemicu adalah sub-kolom event_report_windows yang tidak ada.
  • Spesifikasi pertama yang cocok dipilih untuk atribusi, dan nilai ringkasan ditambah dengan value.

Jika event_report_window untuk spesifikasi selesai, kami akan memetakan nilai ringkasannya ke bucket, dan mengirim laporan tingkat peristiwa untuk setiap penambahan dalam bucket ringkasan yang disebabkan oleh nilai pemicu yang diatribusikan. Laporan akan dilengkapi dengan satu kolom tambahan, yaitu trigger_summary_bucket.

{
  ...
  "trigger_summary_bucket": [<bucket start>, <bucket end>],
}

Konfigurasi yang setara dengan versi saat ini

Berikut konfigurasi yang setara untuk masing-masing peristiwa dan sumber navigasi API saat ini. Khusus untuk sumber navigasi, konfigurasi ini menggambarkan alasan level derau sangat tinggi dibandingkan dengan sumber peristiwa untuk mempertahankan nilai epsilon yang sama: sumber navigasi memiliki ruang output yang jauh lebih besar.

Mungkin saja ada beberapa konfigurasi yang setara, mengingat beberapa parameter dapat ditetapkan sebagai default atau di-pruning.

Sumber peristiwa yang setara
// 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>,
}
Sumber navigasi yang setara
// 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>,
}

Contoh konfigurasi kustom

Berikut beberapa konfigurasi tambahan selain default. Dalam semua contoh ini, kompromi developer mencakup:

  • mengurangi beberapa dimensi konfigurasi default (#pemicu, kardinalitas data pemicu, #jendela) untuk meningkatkan dimensi lainnya guna mempertahankan level derau
  • mengurangi beberapa dimensi konfigurasi default (#pemicu, kardinalitas data pemicu, #jendela) untuk mengurangi level derau

Melaporkan bucket nilai pemicu

Contoh konfigurasi ini mendukung developer yang ingin mengoptimalkan data nilai hanya untuk satu periode pelaporan (mis. 7 hari), dengan mengorbankan periode pelaporan yang lebih sedikit untuk mengurangi derau. Dalam contoh ini, pemicu apa pun yang menetapkan trigger_data ke nilai selain 0 tidak memenuhi syarat untuk atribusi.

{
  "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]
  }],
}

Pemicu dapat didaftarkan dengan kumpulan kolom value, yang dijumlahkan dan dibuat bucket. Misalnya, jika ada tiga pemicu dalam waktu 7 hari sejak pendaftaran sumber dengan nilai 1, 3, dan 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}] }

Nilainya dijumlahkan menjadi 8 dan dilaporkan dalam laporan berikut setelah 7 hari + 1 jam:

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

Dalam 7 hari berikutnya, pemicu berikut akan didaftarkan:

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

Nilai-nilainya dijumlahkan menjadi 8 + 50 + 45 = 103. Hal ini menghasilkan laporan berikut pada 14 hari + 1 jam:

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

// Report 3
{
  ...
  "trigger_summary_bucket": [100, MAX_INT]
}
Melaporkan jumlah pemicu

Contoh ini menunjukkan cara developer dapat mengonfigurasi sumber untuk mendapatkan jumlah pemicu hingga 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]
  }],
}

Pemicu atribusi dengan trigger_data yang disetel ke 0 dihitung dan dibatasi hingga 10. Nilai pemicu diabaikan karena summary_window_operator disetel ke penghitungan. Jika 4 pemicu didaftarkan dan diatribusikan ke sumber, laporan akan terlihat seperti ini:

// 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]
}
Biner dengan pelaporan yang lebih sering

Contoh konfigurasi ini mendukung developer yang ingin mengetahui apakah setidaknya satu konversi terjadi dalam 10 hari pertama (terlepas dari nilainya), tetapi ingin menerima laporan dengan interval yang lebih sering daripada default. Perlu diingat, pemicu apa pun di contoh ini yang menetapkan trigger_data ke nilai selain 0 tidak memenuhi syarat untuk atribusi. Inilah alasan kasus penggunaan ini disebut sebagai biner.

{
  "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]
  }],
}
Memvariasikan spesifikasi pemicu dari sumber ke sumber
{
  "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
}

Sebaiknya developer menyarankan berbagai kasus penggunaan yang mungkin mereka miliki untuk ekstensi API ini, dan kami akan memperbarui penjelasan ini dengan contoh konfigurasi untuk kasus penggunaan tersebut.

Atribusi lintas-jaringan tanpa pengalihan

Teknologi iklan harus menggunakan pengalihan untuk mendaftarkan beberapa pemicu sumber atribusi dan untuk melakukan atribusi lintas jaringan. Fitur ini membantu mendukung atribusi lintas jaringan saat pengalihan tidak memungkinkan di seluruh jaringan. Pelajari lebih lanjut.

Teknologi iklan dapat mengirim konfigurasi dalam respons pendaftaran pemicu berdasarkan sumber mana yang didaftarkan oleh teknologi iklan lain yang dipilih untuk menghasilkan sumber turunan; sumber turunan ini kemudian digunakan untuk atribusi. Laporan agregat dibuat jika pemicu diatribusikan ke sumber turunan. Pembuatan laporan peristiwa untuk sumber turunan tidak didukung.

Teknologi iklan dapat memilih dari aggregation_keys di sumber terdaftar mereka yang ingin mereka bagikan kepada teknologi iklan partner. Kunci ini dapat dideklarasikan dalam kolom shared_aggregation_keys opsional yang terletak di bawah header pendaftaran sumber Attribution-Reporting-Register-Source:

"shared_aggregation_keys": ["[key name1]", "[key name2]"]

Sumber turunan dihasilkan berdasarkan konfigurasi di bawah header pendaftaran pemicu 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]"
    }
  ]

Berikut adalah versi dengan nilai contoh yang ditambahkan:

  "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"
    }
  ]

Dua kolom opsional baru ditambahkan untuk memicu header pendaftaran. Kolom ini memungkinkan ID teknologi iklan pemenang di kunci laporan agregat:

  • x_network_bit_mapping: ID pendaftaran ke pemetaan bit ID teknologi iklan
  • x_network_data: Offset (geser kiri) untuk operasi OR x_network_bit_mapping teknologi iklan pemenang dengan bagian kunci pemicu
Contoh:
"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
  }
  …
}

Berikut adalah penghitungan bagian kunci pemicu yang dihasilkan saat membuat laporan untuk sumber AdTechB:

  • key_piece: 0x400 (010000000000)
  • key_offset: 12
  • Nilai enrollment_id AdtechB: 2 (010) (dari x_network_bit_mapping)
  • Bagian Kunci Pemicu yang Dihasilkan: 0x400 | 0x2 << 12 = 0x2400

Batasan

Untuk daftar kemampuan yang sedang berlangsung untuk Runtime SDK, lihat catatan rilis.

Melaporkan bug dan masalah

Masukan Anda adalah bagian penting dari Privacy Sandbox di Android. Beri tahu kami jika Anda menemukan masalah atau memiliki ide untuk meningkatkan Privacy Sandbox di Android.