Lorsque vous lisez la documentation concernant la Privacy Sandbox sur Android, cliquez sur le bouton Preview développeur ou Bêta pour sélectionner la version du programme que vous utilisez, car les instructions peuvent varier.
L'API Attribution Reporting est conçue pour améliorer la confidentialité des utilisateurs en supprimant la dépendance aux identifiants utilisateur multipartites, et pour prendre en charge des cas d'utilisation clés de l'attribution et de la mesure des conversions dans les applications. Ce guide du développeur vous explique comment configurer et tester les API Attribution Reporting pour enregistrer les clics, les vues et les conversions de vos annonces, en appelant des méthodes qui enregistrent les déclencheurs et les sources pertinents pour de tels événements.
Ce guide vous explique comment configurer des points de terminaison de serveur et créer une application cliente qui appelle ces services. Pour en savoir plus sur la conception globale de l'API Attribution Reporting, consultez la proposition de conception.
Mots clés
- Les sources d'attribution font référence aux vues ou aux clics.
- Les déclencheurs sont des événements qui peuvent être attribués aux conversions.
- Les rapports contiennent des données sur un déclencheur et la source d'attribution correspondante. Ces rapports sont envoyés en réponse à des événements déclencheurs. L'API Attribution Reporting est compatible avec les rapports au niveau des événements et les rapports agrégables.
Avant de commencer
Pour utiliser l'API Attribution Reporting, effectuez les tâches côté serveur et côté client indiquées dans les sections suivantes.
Configurer les points de terminaison de l'API Attribution Reporting
L'API Attribution Reporting nécessite un ensemble de points de terminaison auxquels vous pouvez accéder depuis un appareil de test ou un émulateur. Créez un point de terminaison pour chacune des tâches suivantes côté serveur :
- Enregistrer une source d'attribution (vue ou clic)
- Enregistrer un déclencheur (conversion)
- Accepter les rapports au niveau des événements
- Accepter les rapports agrégables
Il existe plusieurs méthodes pour configurer les points de terminaison requis :
- Le moyen le plus rapide est de déployer les définitions de service OpenAPI v3 depuis notre dépôt d'exemple de code sur une plate-forme fictive ou de microservices. Vous pouvez utiliser Postman, Prism ou toute autre plate-forme fictive de serveur qui accepte ce format. Déployez chaque point de terminaison et effectuez le suivi des URI à utiliser dans votre application. Pour vérifier la diffusion du rapport, reportez-vous aux appels précédemment effectués vers la plate-forme fictive ou sans serveur.
- Exécutez votre propre serveur autonome à l'aide de l'exemple Kotlin basé sur Spring Boot. Déployez ce serveur sur votre fournisseur de services cloud ou sur votre infrastructure interne.
- Utilisez les définitions de service comme exemples pour intégrer les points de terminaison dans votre système existant.
Accepter l'enregistrement de la source
Ce point de terminaison doit être adressable à partir d'un URI semblable à celui-ci :
https://adtech.example/attribution_source
Lorsqu'une application cliente enregistre une source d'attribution, elle fournit l'URI de ce point de terminaison du serveur. L'API Attribution Reporting envoie ensuite une requête et inclut l'un des en-têtes suivants :
Pour les événements de clic :
Attribution-Reporting-Source-Info: navigation
Pour les événements de vue :
Attribution-Reporting-Source-Info: event
Configurez le point de terminaison de votre serveur pour qu'il réponde comme suit :
// 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>
Voici un exemple concret :
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
Si Attribution-Reporting-Redirects
contient les URI de partenaires de technologie publicitaire, l'API Attribution Reporting envoie une requête semblable à chaque URI. Chaque partenaire de technologie publicitaire doit configurer un serveur qui répond avec ces en-têtes :
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.
Accepter l'enregistrement du déclencheur de conversion
Ce point de terminaison doit être adressable à partir d'un URI semblable à celui-ci :
https://adtech.example/attribution_trigger
Lorsqu'une application cliente enregistre un événement déclencheur, elle fournit l'URI de ce point de terminaison du serveur. L'API Attribution Reporting envoie ensuite une requête et inclut l'un des en-têtes suivants :
Configurez le point de terminaison de votre serveur pour qu'il réponde comme suit :
// 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>
Voici un exemple concret :
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
La limite est de 25 octets par ID de clé d'agrégation et par chaîne de filtre. Cela signifie que les ID de clé d'agrégation et les chaînes de filtre ne doivent pas dépasser 25 caractères. Dans cet exemple, campaignCounts
est composé de 14 caractères. Il s'agit donc d'un ID de clé d'agrégation valide. 1234
, qui compte 4 caractères, est une chaîne de filtre valide.
Si un ID de clé d'agrégation ou une chaîne de filtre dépasse 25 caractères, le déclencheur est ignoré.
Si Attribution-Reporting-Redirect
contient les URI de partenaires de technologie publicitaire, l'API Attribution Reporting envoie une requête semblable à chaque URI. Chaque partenaire de technologie publicitaire doit configurer un serveur qui répond avec ces en-têtes :
// 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.
Accepter les rapports au niveau des événements
Ce point de terminaison doit être adressable à partir d'un URI. Pour en savoir plus sur l'enregistrement des URI, consultez Créer un compte Privacy Sandbox. Notez que l'URI est déduit de l'origine des serveurs utilisés pour accepter l'enregistrement de la source et déclencher l'enregistrement. En utilisant les exemples d'URI pour les points de terminaison qui acceptent l'enregistrement de la source et l'enregistrement du déclencheur, l'URI de ce point de terminaison est le suivant :
https://adtech.example/.well-known/attribution-reporting/report-event-attribution
Configurez ce serveur pour accepter les requêtes JSON qui utilisent le format suivant :
{
"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]",
}
Les clés de débogage permettent d'obtenir des informations supplémentaires dans vos rapports sur l'attribution. Découvrez comment les configurer.
Accepter les rapports agrégables
Ce point de terminaison doit être adressable à partir d'un URI. Pour en savoir plus sur l'enregistrement des URI, consultez Créer un compte Privacy Sandbox. Notez que l'URI est déduit de l'origine des serveurs utilisés pour accepter l'enregistrement de la source et déclencher l'enregistrement. En utilisant les exemples d'URI pour les points de terminaison qui acceptent l'enregistrement de la source et l'enregistrement du déclencheur, l'URI de ce point de terminaison est le suivant :
https://adtech.example/.well-known/attribution-reporting/report-aggregate-attribution
Les champs chiffrés et non chiffrés sont renseignés pour les rapports agrégables. Les rapports chiffrés vous permettent de commencer les tests avec le service d'agrégation, tandis que le champ non chiffré fournit des informations sur la façon dont les paires clé/valeur définies structurent les données.
Configurez ce serveur pour accepter les requêtes JSON qui utilisent le format suivant :
{
// 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]"
}
Les clés de débogage permettent d'obtenir des informations supplémentaires dans vos rapports sur l'attribution. Découvrez comment les configurer.
Configurer le client Android
L'application cliente enregistre les sources et les déclencheurs d'attribution, et permet de générer des rapports au niveau des événements et agrégables. Pour préparer un appareil client ou un émulateur Android à l'aide de l'API Attribution Reporting, procédez comme suit :
- Configurez votre environnement de développement pour la Privacy Sandbox sur Android.
- Installez une image système sur un appareil compatible ou configurez un émulateur compatible avec la Privacy Sandbox sur Android.
Activez l'accès à l'API Attribution Reporting en exécutant la commande ADB suivante. (L'API est désactivée par défaut.)
adb shell device_config put adservices ppapi_app_allow_list \"\*\"
Si vous testez l'API Attribution Reporting en local (par exemple, sur un appareil auquel vous avez accès physiquement), exécutez la commande suivante pour désactiver l'inscription :
adb shell device_config put adservices disable_measurement_enrollment_check "true"
Incluez l'autorisation
ACCESS_ADSERVICES_ATTRIBUTION
dans le fichier manifeste Android et créez une configuration de services publicitaires pour votre appli afin d'utiliser les API Attribution Reporting :<uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
(Facultatif) Si vous prévoyez de recevoir des rapports de débogage, incluez l'autorisation
ACCESS_ADSERVICES_AD_ID
dans votre fichier manifeste Android :<uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID" />
Référencer une configuration de services publicitaires dans l'élément
<application>
de votre fichier manifeste :<property android:name="android.adservices.AD_SERVICES_CONFIG" android:resource="@xml/ad_services_config" />
Spécifiez la ressource XML des services publicitaires référencée dans le fichier manifeste, telle que
res/xml/ad_services_config.xml
. En savoir plus sur les autorisations des services publicitaires et le contrôle des accès au SDK<ad-services-config> <attribution allowAllToAccess="true" /> </ad-services-config>
Enregistrer des événements d'annonce
Votre application devrait enregistrer les sources et les conversions au fur et à mesure pour qu'elles soient correctement rapportées. La classe MeasurementManager
inclut des méthodes vous permettant d'enregistrer des événements de source d'attribution et des déclencheurs de conversion.
Enregistrer un événement de source d'attribution
Lorsqu'une personne voit une annonce ou clique dessus, une application d'éditeur appelle registerSource()
pour enregistrer une source d'attribution, comme illustré dans l'extrait de code.
L'API Attribution Reporting est compatible avec les types d'événements de source d'attribution suivants :
- Clics, que vous enregistrez généralement dans une méthode de rappel semblable à
onClick()
. L'événement déclencheur correspondant se produit généralement peu de temps après l'événement de clic. Ce type d'événement fournit plus d'informations sur l'interaction utilisateur et constitue donc un bon type de source d'attribution pour octroyer un niveau de priorité élevé. Vues, que vous enregistrez généralement dans une méthode de rappel semblable à
onAdShown()
. L'événement de déclenchement correspondant peut se produire des heures ou des jours après l'événement de vue.
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);
Après l'enregistrement, l'API envoie une requête HTTP POST au point de terminaison de service à l'adresse spécifiée par attributionSourceUri
. La réponse du point de terminaison inclut des valeurs pour destination, source_event_id, expiry
et source_priority
.
Si la technologie publicitaire d'origine souhaite partager les enregistrements de la source, l'URI de la source d'attribution d'origine peut inclure des redirections vers d'autres points de terminaison de la technologie publicitaire. Les limites et les règles applicables aux redirections sont détaillées dans la proposition technique.
Nous avons ajouté la prise en charge des redirections en série pour registerSource
et registerTrigger
. En plus de l'en-tête d'enregistrement, le client de l'API peut désormais fournir une redirection HTTP en tant que réponse du serveur. Elle comprend un code d'état 302 et un en-tête "Location" avec l'URL suivante qui permettra un enregistrement supplémentaire.
Actuellement, seul le champ "destination" fourni lors de la première visite est utilisé lors des interconnexions en série. Le nombre de visites est limité comme dans les en-têtes "Attribution-Reporting-Redirect". Cette prise en charge des redirections s'ajoute à la prise en charge existante d'"Attribution-Reporting-Redirect". Si les deux sont présentes, "Attribution-Reporting-Redirect" prévaut.
Enregistrer un événement déclencheur de conversion
Pour enregistrer un événement de déclencheur de conversion, appelez registerTrigger()
dans votre application :
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)
Après l'enregistrement, l'API envoie une requête HTTP POST au point de terminaison de service à l'adresse spécifiée par attributionTriggerUri
. La réponse du point de terminaison inclut les valeurs des événements et des rapports d'agrégation.
Si la plate-forme de technologie publicitaire d'origine autorise le partage des enregistrements de déclencheurs, l'URI peut inclure des redirections vers des URI appartenant à d'autres plates-formes de technologie publicitaire. Les limites et les règles applicables aux redirections sont détaillées dans la proposition technique.
Enregistrer des mesures multi-applications et Web
Dans le cas où une application et un navigateur jouent tous deux un rôle dans le parcours utilisateur, de la source au déclencheur, il existe de légères différences dans l'implémentation des enregistrements d'événements d'annonce. Si un utilisateur voit une annonce dans une application et est redirigé vers un navigateur pour une conversion, la source est enregistrée par l'application et la conversion par le navigateur Web. De même, si un utilisateur démarre dans un navigateur Web et qu'il est redirigé vers une application pour la conversion, le navigateur enregistre la source et l'application enregistre la conversion.
Étant donné qu'il existe des différences dans l'organisation des technologies publicitaires sur le Web et sur Android, nous avons ajouté de nouvelles API pour enregistrer les sources et les déclencheurs lorsqu'ils se produisent dans les navigateurs. La principale différence entre ces API et les API basées sur les applications correspondantes est que le navigateur doit suivre les redirections, appliquer des filtres spécifiques au navigateur et transmettre les enregistrements valides à la plate-forme en appelant registerWebSource()
ou registerWebTrigger()
.
L'extrait de code suivant présente un exemple d'appel d'API par le navigateur pour enregistrer une source d'attribution avant de rediriger l'utilisateur vers une application :
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);
L'extrait de code suivant présente un exemple d'appel d'API par le navigateur pour enregistrer une conversion après que l'utilisateur a été redirigé depuis l'application :
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);
Ajouter du bruit pour préserver la confidentialité
Les rapports au niveau des événements contiennent la destination, l'ID de la source d'attribution et les données du déclencheur. Ils sont envoyés au format d'origine (non chiffré) à l'origine du rapport. Pour protéger la confidentialité des utilisateurs, des bruits peuvent être ajoutés pour rendre l'identification des utilisateurs plus difficile. Les rapports au niveau des événements sont générés et envoyés conformément au framework de confidentialité différentielle. Voici les valeurs par défaut du pourcentage de bruit pour différents scénarios :
Type de source |
Valeur de destination source |
Probabilité de signalement par enregistrement de la source |
Afficher |
Application ou site Web |
0,0000025 |
Afficher |
Application et site Web |
0,0000042 |
Clic |
Application ou site Web |
0,0024263 |
Clic |
Application et site Web |
0,0170218 |
Dans la mesure de l'attribution Application/Web, les sources peuvent générer des conversions à la fois dans l'appli et sur le Web. Pour les rapports au niveau des événements, il est donc possible de spécifier si le déclencheur s'est produit dans l'appli ou sur le Web. Pour compenser ces détails supplémentaires, les rapports générés sont multipliés par 7 environ pour les clics et par 1,7 pour les vues.
Certaines technologies publicitaires n'exigent pas de rapports au niveau des événements pour spécifier si le déclencheur s'est produit au niveau de la destination d'appli ou Web. Les technologies publicitaires peuvent utiliser le champ coarse_event_report_destinations
sous l'en-tête Attribution-Reporting-Register-Source
pour réduire le bruit. Si une source avec le champ coarse_event_report_destinations
spécifié remporte l'attribution, le rapport obtenu inclut à la fois les destinations Web et d'appli, sans distinction de l'emplacement du déclencheur réel.
Dans les exemples suivants, un utilisateur clique sur une annonce et cette source est enregistrée avec l'API. L'utilisateur effectue ensuite une conversion à la fois dans l'appli de l'annonceur et sur le site Web de l'annonceur. Ces deux conversions sont enregistrées en tant que déclencheurs et attribuées au clic initial.
Un en-tête HTTP d'enregistrement source basé sur les clics :
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"
}
Un déclencheur est enregistré à partir de l'appli avec le nom de package com.advertiser.example
:
Attribution-Reporting-Register-Trigger: {
"event_trigger_data": [{
"trigger_data": "1",
"priority": "1"
}],
}
Un déclencheur est enregistré à partir d'un navigateur du site Web avec le domaine eTLD+1 https://advertiser.com
:
Attribution-Reporting-Register-Trigger: {
"event_trigger_data": [{
"trigger_data": "2",
"priority": "2"
}],
}
Les rapports obtenus au niveau des événements sont générés. En supposant que les deux déclencheurs soient attribués à la source, les rapports suivants sont générés au niveau des événements :
{
"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
}
Générer et diffuser des rapports
L'API Attribution Reporting envoie des rapports aux points de terminaison de votre serveur qui acceptent les rapports au niveau des événements et des rapports agrégables.
Forcer l'exécution des tâches de création de rapports
Une fois que vous avez enregistré un événement de source d'attribution ou de déclencheur, le système planifie l'exécution de la tâche de création de rapports. Par défaut, cette tâche s'exécute toutes les quatre heures. À des fins de test, vous pouvez forcer les tâches de création de rapports à s'exécuter ou raccourcir les intervalles entre les tâches.
Forcer l'exécution de la tâche d'attribution :
adb shell cmd jobscheduler run -f com.google.android.adservices.api 5
Forcer l'exécution de la tâche de création de rapports au niveau des événements :
adb shell cmd jobscheduler run -f com.google.android.adservices.api 3
Forcer l'exécution de la tâche de création de rapports agrégables :
adb shell cmd jobscheduler run -f com.google.android.adservices.api 7
Vérifiez le résultat dans logcat pour voir quand les tâches ont été exécutées. Le résultat devrait ressembler à ceci :
JobScheduler: executeRunCommand(): com.google.android.adservices.api/0 5 s=false f=true
Forcer la diffusion des rapports
Même si l'exécution de la tâche de création de rapport est forcée, le système envoie toujours des rapports en fonction des délais de diffusion planifiés, qui peuvent aller de quelques heures à plusieurs jours. À des fins de test, vous pouvez repousser l'heure du système de l'appareil après les délais planifiés pour lancer la diffusion du rapport.
Vérifier les rapports sur votre serveur
Une fois les rapports envoyés, vérifiez leur diffusion en consultant les rapports reçus, les journaux de serveur applicables tels que l'historique du serveur fictif ou votre système personnalisé.
Décoder votre rapport agrégable
Lorsque vous recevez un rapport agrégable, le champ debug_cleartext_payload
contient une version non chiffrée de ce rapport. Même si cette version de votre rapport n'est pas chiffrée, vous devez la décoder.
Vous trouverez ci-dessous un exemple de décodage du contenu du champ debug_cleartext_payload
en deux étapes : la première à l'aide du décodage en base 64 et l'autre à l'aide du décodage 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);
});
Tests
Pour commencer à utiliser l'API Attribution Reporting, vous pouvez utiliser le projet MeasurementSampleApp sur GitHub. Cet application exemple illustre l'enregistrement de la source d'attribution et du déclencheur.
Pour les points de terminaison du serveur, utiliser les ressources de référence suivantes ou votre solution personnalisée :
- MeasurementAdTechServerSpec inclut les définitions de service OpenAPI, qui peuvent être déployées sur une plate-forme fictive ou sur des plates-formes de microservices compatibles.
- MeasurementAdTechServer inclut une implémentation de référence d'un serveur fictif basé sur l'application Spring Boot pour Google App Engine.
Conditions préalables
Déployez des API fictives sur des points de terminaison distants accessibles depuis votre appareil de test ou votre émulateur. Pour faciliter les tests, reportez-vous aux exemples de projets MeasurementAdTechServerSpec et MeasurementAdTechServer.
Fonctionnalité à tester
- Utiliser les enregistrements de sources d'attribution et de déclencheurs de conversion. Vérifier que les points de terminaison côté serveur répondent au format approprié.
- Exécuter des tâches de création de rapports.
- Vérifier la diffusion des rapports sur le backend ou la console de votre serveur de test.
Fonctionnalités à venir
Configuration flexible au niveau des événements
La configuration par défaut pour la création de rapports au niveau des événements est recommandée pour démarrer les tests d'utilité, mais elle n'est pas forcément idéale pour tous les cas d'utilisation. L'API Attribution Reporting prend en charge des configurations facultatives et plus flexibles afin que les technologies publicitaires aient davantage de contrôle sur la structure de leurs rapports au niveau des événements et puissent maximiser l'utilité des données. Cette flexibilité supplémentaire sera introduite dans l'API Attribution Reporting en deux phases :
- Phase 1 : Configuration flexible allégée au niveau des événements ; un sous-ensemble de la phase 2.
- Phase 2 : Configuration flexible complète au niveau des événements.
Phase 1 : Configuration flexible allégée au niveau des événements
Nous allons ajouter les deux paramètres facultatifs suivants au fichier JSON dans 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>, ...]
}
}
Exemple de configuration personnalisée
Cet exemple de configuration s'adresse à un développeur qui souhaite optimiser la réception de rapports à des périodes de référence antérieures.
{
...
"max_event_level_reports": 2,
"event_report_windows": {
"end_times": [7200, 43200, 86400] // 2 hours, 12 hours, 1 day in seconds
}
}
Phase 2 : Configuration flexible complète au niveau des événements
En plus des paramètres ajoutés lors de la phase 1, nous allons ajouter un paramètre facultatif supplémentaire trigger_specs
au fichier JSON dans 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>, ...]
}
}
Cette configuration spécifie de manière exhaustive l'espace de sortie des rapports au niveau des événements, sur la base de l'enregistrement source. Pour chaque spécification de déclencheur, nous spécifions de manière exhaustive :
- Un ensemble de critères de correspondance :
- Les données de déclencheur spécifiques auxquelles cette spécification s'applique. Cette source ne peut être mise en correspondance qu'avec les déclencheurs qui disposent d'une des valeurs
trigger_data
spécifiées danstrigger_specs
. En d'autres termes, si le déclencheur correspond à cette source, mais que sontrigger_data
n'est pas l'une des valeurs présentes dans la configuration de la source, le déclencheur est ignoré. - Le moment où un déclencheur spécifique correspond à cette spécification (à l'aide de
event_report_windows
). Notez que le déclencheur peut toujours être mis en correspondance avec une source de rapports agrégables même si les deux critères de correspondance mentionnés précédemment ne sont pas respectés.
- Les données de déclencheur spécifiques auxquelles cette spécification s'applique. Cette source ne peut être mise en correspondance qu'avec les déclencheurs qui disposent d'une des valeurs
- Un algorithme spécifique permettant de résumer et de regrouper dans des ensembles tous les déclencheurs au cours d'une période d'attribution. Cela permet aux déclencheurs de spécifier un paramètre
value
qui est additionné pour une spécification donnée, mais rapporté comme une valeur faisant partie d'un ensemble.
Les déclencheurs accepteront aussi l'ajout d'un paramètre de valeur facultatif dans les dictionnaires au sein d'event_trigger_data
.
{
"event_trigger_data": [
{
"trigger_data": "2",
"value": 100, // Defaults to 1
"filters": ...
},
...
]
}
Chaque enregistrement de déclencheur correspondra au maximum à une spécification de déclencheur et mettra à jour sa valeur de résumé associée. De manière générale, au moment du déclenchement, nous effectuerons les actions suivantes :
- Appliquer des filtres d'attribution globaux.
- Pour chaque spécification de déclencheur, évaluer l'
event_trigger_data
de la spécification pour trouver une correspondance, à l'aide de l'event_reporting_window
de la spécification. Leevent_reporting_windows
de niveau supérieur sert de valeur par défaut si une spécification de déclencheur correspond au sous-champevent_report_windows
manquant. - La première spécification correspondante est choisie pour l'attribution, et la valeur de résumé est incrémentée de
value
.
Lorsque l'event_report_window
d'une spécification est terminée, nous mappons sa valeur récapitulative à un ensemble et envoyons un rapport au niveau des événements pour chaque incrément de l'ensemble récapitulatif causé par les valeurs de déclencheur attribuées. Les rapports incluront un champ supplémentaire : trigger_summary_bucket
.
{
...
"trigger_summary_bucket": [<bucket start>, <bucket end>],
}
Configurations équivalentes à la version actuelle
Voici des configurations équivalentes pour l'événement en cours et les sources de navigation de l'API. En particulier pour les sources de navigation, cela illustre pourquoi les niveaux de bruit sont si élevés par rapport aux sources d'événements pour conserver les mêmes valeurs d'epsilon : les sources de navigation disposent d'un espace de sortie beaucoup plus important.
Il est possible que plusieurs configurations soient équivalentes, étant donné que certains paramètres peuvent être définis comme valeurs par défaut ou élagués.
Sources d'événements équivalentes
// 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>,
}
Sources de navigation équivalentes
// 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>,
}
Exemples de configurations personnalisées
Vous trouverez ci-dessous d'autres configurations, différentes des configurations par défaut. Dans tous ces exemples, des compromis existent pour le développeur :
- Réduire une dimension de la configuration par défaut (nombre de déclencheurs, cardinalité des données de déclencheur, nombre de périodes de référence) pour en augmenter une autre afin de préserver le niveau de bruit
- Réduire une dimension de la configuration par défaut (nombre de déclencheurs, cardinalité des données de déclencheur, nombre de périodes de référence) pour réduire le niveau de bruit
Ensembles de valeurs de déclencheur de rapport
Cet exemple de configuration s'adresse à un développeur qui souhaite optimiser les données de valeur pour une seule période de référence (par exemple, sept jours), réduisant ainsi le nombre de périodes de référence pour réduire le bruit. Dans cet exemple, tout déclencheur qui définit trigger_data
sur une valeur autre que 0 ne peut pas être attribué.
{
"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]
}],
}
Les déclencheurs peuvent être enregistrés en définissant le champ value
, puis additionnés et regroupés en ensembles. (Par exemple, s'il existe trois déclencheurs dans les sept jours suivant les enregistrements de la source, avec les valeurs 1, 3 et 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}] }
Les valeurs sont additionnées (pour un résultat de 8) et signalées dans les rapports suivants après sept jours et une heure :
// Report 1
{
...
"trigger_summary_bucket": [5, 9]
}
Au cours des sept jours suivants, les déclencheurs suivants sont enregistrés :
{ "event_trigger_data": [{"trigger_data": "0", "value": 50}] }
{ "event_trigger_data": [{"trigger_data": "0", "value": 45}] }
Les valeurs sont additionnées (8 + 50 + 45 = 103). Cela nous donne les rapports suivants à 14 jours + 1 heure :
// Report 2
{
...
"trigger_summary_bucket": [10, 99]
},
// Report 3
{
...
"trigger_summary_bucket": [100, MAX_INT]
}
Nombre de déclencheurs de rapport
Cet exemple montre comment un développeur peut configurer une source pour obtenir un nombre de déclencheurs jusqu'à 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]
}],
}
Les déclencheurs attribués avec trigger_data
défini sur 0 sont comptabilisés et plafonnés à 10.
La valeur du déclencheur est ignorée, car summary_window_operator
est défini sur "count". Si quatre déclencheurs sont enregistrés et attribués à la source, le rapport se présente comme suit :
// 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]
}
Cas binaire avec des rapports plus fréquents
Cet exemple de configuration s'adresse à un développeur qui souhaite savoir si au moins une conversion s'est produite au cours des 10 premiers jours (quelle que soit sa valeur), mais qui souhaite recevoir des rapports à des intervalles plus fréquents que le paramètre par défaut. Là encore, dans cet exemple, tout déclencheur qui définit trigger_data
sur une valeur autre que 0 ne peut pas être attribué. C'est pourquoi ce cas d'utilisation est qualifié de binaire.
{
"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]
}],
}
Faire varier les spécifications de déclencheur d'une source à l'autre
{
"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
}
Nous encourageons les développeurs à suggérer différents cas d'utilisation pour cette extension d'API. Nous mettrons à jour cette page explicative avec des exemples de configurations pour ces cas d'utilisation.
Attribution multiréseau sans redirections
Les technologies publicitaires doivent utiliser des redirections pour enregistrer plusieurs déclencheurs de sources d'attribution et effectuer des attributions multiréseaux. Cette fonctionnalité permet d'effectuer des attributions multiréseaux où les redirections ne sont pas possibles entre les réseaux. En savoir plus
Les technologies publicitaires peuvent envoyer une configuration dans la réponse d'enregistrement du déclencheur en fonction des sources enregistrées par d'autres technologies publicitaires sélectionnées pour générer des sources dérivées. Ces sources dérivées sont ensuite utilisées pour l'attribution. Des rapports d'agrégation sont générés si le déclencheur est attribué à une source dérivée. Il n'est pas possible de générer des rapports sur les événements pour les sources dérivées.
Dns leurs sources enregistrées, les technologies publicitaires peuvent choisir les aggregation_keys
qu'ils prévoient de partager avec les technologies publicitaires partenaires. Ces clés peuvent être déclarées dans le champ facultatif shared_aggregation_keys
, situé sous l'en-tête d'enregistrement de la source Attribution-Reporting-Register-Source
:
"shared_aggregation_keys": ["[key name1]", "[key name2]"]
Les sources dérivées sont générées en fonction de la configuration figurant dans l'en-tête du déclencheur 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]"
}
]
Voici une version avec des exemples de valeurs ajoutés :
"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"
}
]
Deux champs facultatifs sont ajoutés pour déclencher l'en-tête d'enregistrement. Ces champs activent l'identifiant de la technologie publicitaire gagnante dans les clés des rapports agrégables :
x_network_bit_mapping
: mise en correspondance de l'ID d'inscription et du bit d'identifiant publicitairex_network_data
: décalage (décalage gauche) pour l'opérationx_network_bit_mapping
de la technologie publicitaire gagnante avec l'élément de la clé du déclencheur
Exemple :
"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
}
…
}
Voici le calcul de l'élément de la clé du déclencheur généré lorsque vous créez un rapport pour la source AdTechB :
key_piece
:0x400 (010000000000)
key_offset
:12
- Valeur
enrollment_id
d'AdTechB :2 (010)
(à partir dex_network_bit_mapping
) - Clé de déclencheur générée :
0x400 | 0x2 << 12 = 0x2400
Limites
Pour obtenir la liste des fonctionnalités en cours de développement pour le SDK Runtime, consultez les notes de version.
Signaler des bugs et des problèmes
Vos commentaires sont essentiels pour la Privacy Sandbox sur Android. Signalez-nous les problèmes que vous rencontrez et vos idées pour améliorer Privacy Sandbox sur Android.