Guida per gli sviluppatori dell'API Attribution Reporting

Mentre leggi la documentazione di Privacy Sandbox su Android, utilizza il pulsante Anteprima per sviluppatori o Beta per selezionare la versione del programma a cui stai lavorando, in quanto le istruzioni possono variare.


Inviare feedback

L'API Attribution Reporting è progettata per migliorare la privacy degli utenti eliminando il ricorso a identificatori di utenti trasversali e per supportare casi d'uso chiave per l'attribuzione e la misurazione delle conversioni nelle app. Questa guida per gli sviluppatori descrive come configurare e testare le API Attribution Reporting per registrare clic, visualizzazioni e conversioni sugli annunci richiamando metodi che registrano gli attivatori e le origini pertinenti di questi eventi.

Questa guida illustra come configurare gli endpoint server e creare un'app client che chiami questi servizi. Scopri di più sul design complessivo dell'API Attribution Reporting nella proposta di progettazione.

Termini chiave

  • Le origini dell'attribuzione si riferiscono a clic o visualizzazioni.
  • Gli attivatori sono eventi che possono essere attribuiti alle conversioni.
  • I report contengono dati su un attivatore e sulla corrispondente origine di attribuzione. Questi report vengono inviati in risposta a eventi di attivazione. L'API Attribution Reporting supporta report a livello di evento e report aggregabili.

Prima di iniziare

Per utilizzare l'API Attribution Reporting, completa le attività lato server e lato client elencate nelle seguenti sezioni.

Configurare gli endpoint dell'API Attribution Reporting

L'API Attribution Reporting richiede un insieme di endpoint a cui puoi accedere da un emulatore o un dispositivo di test. Crea un endpoint per ciascuna delle seguenti attività lato server:

Esistono diversi metodi per configurare gli endpoint richiesti:

  • Il modo più rapido per iniziare è eseguire il deployment delle definizioni del servizio OpenAPI v3 dal nostro repository di codice campione a una piattaforma fittizia o di microservizi. Puoi utilizzare Postman, Prism o qualsiasi altra piattaforma server fittizia che accetta questo formato. Esegui il deployment di ogni endpoint e tieni traccia degli URI da utilizzare nella tua app. Per verificare la consegna dei report, fai riferimento alle chiamate effettuate in precedenza alla piattaforma serverless o fittizia.
  • Esegui il tuo server autonomo utilizzando l'esempio Kotlin basato su Spring Boot. Esegui il deployment di questo server sul tuo cloud provider o sull'infrastruttura interna.
  • Utilizza le definizioni dei servizi come esempi per integrare gli endpoint nel tuo sistema esistente.

Accetta la registrazione dell'origine

Questo endpoint deve essere indirizzabile da un URI simile al seguente:

https://adtech.example/attribution_source

Quando un'app client registra un'origine di attribuzione, fornisce l'URI per questo endpoint del server. L'API Attribution Reporting effettua quindi una richiesta e include una delle seguenti intestazioni:

  • Per gli eventi di clic:

    Attribution-Reporting-Source-Info: navigation
    
  • Per gli eventi di visualizzazione:

    Attribution-Reporting-Source-Info: event
    

Configura l'endpoint del server in modo che risponda con quanto segue:

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

Di seguito è riportato un esempio con valori di esempio aggiunti:

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

Se Attribution-Reporting-Redirects contiene URI di partner di tecnologia pubblicitaria, l'API Attribution Reporting effettua una richiesta simile a ciascun URI. Ogni partner di tecnologia pubblicitaria deve configurare un server che risponda con queste intestazioni:

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.

Accetta la registrazione dell'attivatore di conversione

Questo endpoint deve essere indirizzabile da un URI simile al seguente:

https://adtech.example/attribution_trigger

Quando un'app client registra un evento di trigger, fornisce l'URI per questo endpoint del server. L'API Attribution Reporting effettua quindi una richiesta e include una delle seguenti intestazioni:

Configura l'endpoint del server in modo che risponda con quanto segue:

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

Di seguito è riportato un esempio con valori di esempio aggiunti:

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

Esiste un limite di 25 byte per ID chiave di aggregazione e stringa di filtro. Ciò significa che gli ID delle chiavi di aggregazione e le stringhe di filtro non devono superare i 25 caratteri. In questo esempio, campaignCounts contiene 14 caratteri, quindi è un ID chiave di aggregazione valido, mentre 1234 contiene 4 caratteri, quindi è una stringa di filtro valida. Se un ID chiave di aggregazione o una stringa di filtro supera i 25 caratteri, l'attivatore viene ignorato.

Se Attribution-Reporting-Redirect contiene URI di partner di tecnologia pubblicitaria, l'API Attribution Reporting effettua una richiesta simile a ciascun URI. Ogni partner di tecnologia pubblicitaria deve configurare un server che risponda con queste intestazioni:

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

Accettare i report a livello di evento

Questo endpoint deve essere indirizzabile da un URI. Per ulteriori informazioni sulla registrazione degli URI, consulta Registrazione per un account Privacy Sandbox. (L'URI viene dedotto dall'origine dei server utilizzati per accettare la registrazione dell'origine e la registrazione degli attivatori.) Utilizzando gli URI di esempio per gli endpoint che accettano la registrazione dell'origine e la registrazione del trigger, l'URI di questo endpoint è:

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

Configura questo server in modo che accetti richieste JSON che utilizzano il seguente formato:

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

Le chiavi di debug consentono di visualizzare ulteriori approfondimenti nei report sull'attribuzione. Scopri di più sulla loro configurazione.

Accetta i report aggregabili

Questo endpoint deve essere indirizzabile da un URI. Per ulteriori informazioni sulla registrazione degli URI, consulta Registrazione per un account Privacy Sandbox. (L'URI viene dedotto dall'origine dei server utilizzati per accettare la registrazione dell'origine e la registrazione degli attivatori.) Utilizzando gli URI di esempio per gli endpoint che accettano la registrazione dell'origine e la registrazione del trigger, l'URI di questo endpoint è:

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

Entrambi i campi criptati e non criptati vengono compilati per consentire di generare report aggregabili. I report criptati consentono di iniziare a eseguire test con il servizio di aggregazione, mentre il campo non criptato fornisce informazioni dettagliate sul modo in cui le coppie chiave-valore impostate strutturano i dati.

Configura questo server in modo che accetti richieste JSON che utilizzano il seguente formato:

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

Le chiavi di debug consentono di visualizzare ulteriori approfondimenti nei report sull'attribuzione. Scopri di più sulla loro configurazione.

Configura il client Android

L'app client registra le origini e gli attivatori di attribuzione e consente la generazione di report aggregabili a livello di evento. Per preparare un emulatore o un dispositivo client Android per l'utilizzo dell'API Attribution Reporting, segui questi passaggi:

  1. Configura il tuo ambiente di sviluppo per Privacy Sandbox su Android.
  2. Installa un'immagine di sistema su un dispositivo supportato oppure configura un emulatore che includa il supporto per Privacy Sandbox su Android.
  3. Abilita l'accesso all'API Attribution Reporting eseguendo il seguente comando ADB. L'API è disabilitata per impostazione predefinita.

    adb shell device_config put adservices ppapi_app_allow_list \"\*\"
    
  4. Se stai testando a livello locale l'API Attribution Reporting (ad esempio su un dispositivo a cui hai accesso fisicamente), esegui questo comando per disabilitare la registrazione:

    adb shell device_config put adservices disable_measurement_enrollment_check "true"
    
  5. Includi l'autorizzazione ACCESS_ADSERVICES_ATTRIBUTION nel file manifest Android e crea una configurazione di servizi pubblicitari per la tua app al fine di utilizzare le API Attribution Reporting:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
    
  6. (Facoltativo) Se prevedi di ricevere report di debug, includi l'autorizzazione ACCESS_ADSERVICES_AD_ID nel file manifest Android:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID" />
    
  7. Fai riferimento alla configurazione di un servizio pubblicitario nell'elemento <application> del manifest:

    <property android:name="android.adservices.AD_SERVICES_CONFIG"
              android:resource="@xml/ad_services_config" />
    
  8. Specifica la risorsa XML dei servizi pubblicitari a cui viene fatto riferimento nel manifest, ad esempio res/xml/ad_services_config.xml. Scopri di più sulle autorizzazioni per i servizi pubblicitari e sul controllo dell'accesso agli SDK.

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

Registra eventi annuncio

L'app deve registrare le origini e le conversioni nel momento in cui si verificano per garantire che vengano registrate correttamente. La classe MeasurementManager offre metodi per aiutarti a registrare gli eventi di origine dell'attribuzione e gli attivatori di conversione.

Registrare un evento di origine dell'attribuzione

Quando un annuncio viene visualizzato o selezionato, un'app del publisher chiama registerSource() per registrare un'origine di attribuzione come mostrato nello snippet di codice.

L'API Attribution Reporting supporta i seguenti tipi di eventi origine attribuzione:

  • Clic, che in genere registri con un metodo di callback simile a onClick(). L'evento di trigger corrispondente si verifica in genere subito dopo l'evento di clic. Questo tipo di evento fornisce ulteriori informazioni sull'interazione dell'utente ed è quindi un buon tipo di origine di attribuzione a cui assegnare una priorità elevata.
  • Visualizzazioni, che in genere registri con un metodo di callback simile a onAdShown(). L'evento di trigger corrispondente potrebbe verificarsi ore o giorni dopo l'evento di visualizzazione.

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

Dopo la registrazione, l'API invia una richiesta POST HTTP all'endpoint di servizio all'indirizzo specificato da attributionSourceUri. La risposta dell'endpoint include valori per destination, source_event_id, expiry e source_priority.

Se la tecnologia pubblicitaria di origine vuole condividere le registrazioni dell'origine, l'URI dell'origine dell'attribuzione originale può includere reindirizzamenti ad altri endpoint di tecnologia pubblicitaria. I limiti e le regole applicabili ai reindirizzamenti sono descritti in dettaglio nella proposta tecnica.

È stato aggiunto il supporto per i reindirizzamenti daisy-chain per registerSource e registerTrigger. Oltre all'intestazione della registrazione, il consumatore API ora può fornire un reindirizzamento HTTP come risposta del server che include un codice di stato 302 e un'intestazione "Location" con l'URL successivo da visitare per un'ulteriore registrazione.

Solo il campo "destination" fornito durante la prima visita viene utilizzato nella daisy-chain. Il numero di visite ha lo stesso limite delle intestazioni "Attribution-Reporting-redirect". Questo supporto dei reindirizzamenti si aggiunge al supporto esistente di "Attribution-Reporting-Reindirizzamento" e, se sono presenti entrambi, "Attribution-Reporting-Reindirizzamento" ottiene la preferenza.

Registrare un evento di attivatore di conversione

Per registrare un evento di attivatore di conversione, chiama registerTrigger() nella tua app:

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)

Dopo la registrazione, l'API invia una richiesta POST HTTP all'endpoint di servizio all'indirizzo specificato da attributionTriggerUri. La risposta dell'endpoint include valori per i report aggregati e sugli eventi.

Se la piattaforma di tecnologia pubblicitaria di origine consente la condivisione delle registrazioni degli attivatori, l'URI può includere reindirizzamenti agli URI che appartengono ad altre piattaforme di tecnologia pubblicitaria. I limiti e le regole applicabili ai reindirizzamenti sono descritti in dettaglio nella proposta tecnica.

Registra la misurazione tra app e web

Nel caso in cui sia un'app sia un browser svolgano un ruolo nel percorso dell'utente dalla sorgente all'attivazione, esistono piccole differenze nell'implementazione della registrazione degli eventi annuncio. Se un utente vede un annuncio in un'app e viene reindirizzato a un browser per una conversione, l'origine viene registrata dall'app e la conversione dal browser web. Analogamente, se un utente apre un browser web e viene indirizzato a un'app per la conversione, il browser registra la sorgente e l'app registra la conversione.

Poiché esistono differenze nel modo in cui le tecnologie pubblicitarie sono organizzate sul web e su Android, abbiamo aggiunto nuove API per registrare origini e trigger quando vengono applicati nei browser. La differenza principale tra queste API e le corrispondenti API basate su app è che prevediamo che il browser segua i reindirizzamenti, applichi eventuali filtri specifici del browser e trasmetta le registrazioni valide alla piattaforma chiamando registerWebSource() o registerWebTrigger().

Il seguente snippet di codice mostra un esempio della chiamata API effettuata dal browser per registrare un'origine di attribuzione prima di indirizzare l'utente a un'app:

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

Il seguente snippet di codice mostra un esempio della chiamata API effettuata dal browser per registrare una conversione dopo che l'utente è stato indirizzato dall'app:

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

Aggiungere rumore per la privacy

I report a livello di evento contengono destinazione, ID origine attribuzione e dati trigger. Vengono inviati nel formato originale (non criptato) all'origine dei report. Per proteggere la privacy dell'utente, è possibile aggiungere rumore per rendere più difficile l'identificazione di un singolo utente. I report a livello di evento con rumori vengono generati e inviati nel rispetto del framework di privacy differenziale. Di seguito sono riportati i valori di percentuale di rumore predefiniti per scenari diversi:

Tipo di origine

Valore destinazione origine

Probabilità di report disturbata per registrazione sorgente

Visualizza

App o web

0,0000025

Visualizza

App e Web

0,0000042

Clic

App o web

0,0024263

Clic

App e Web

0,0170218

Nella misurazione dell'attribuzione app-web, in cui le origini possono generare conversioni sia verso le destinazioni app che sul web, i report a livello di evento possono specificare se l'attivatore si è verificato nell'app o sul web. Per compensare questo ulteriore dettaglio, i report con rumore generati sono fino a 7 volte superiori per i clic e circa 1,7 volte per le visualizzazioni.

Alcune tecnologie pubblicitarie non richiedono report a livello di evento per specificare se il trigger si è verificato nell'app o nella destinazione web. I tecnici pubblicitari possono utilizzare il campo coarse_event_report_destinations sotto l'intestazione Attribution-Reporting-Register-Source per ridurre il rumore. Se un'origine con il campo coarse_event_report_destinations specificato si aggiudica l'attribuzione, il report risultante includerà le destinazioni web e app, indipendentemente da dove si è verificato l'attivatore effettivo.

Negli esempi seguenti, un utente fa clic su un annuncio e la relativa origine è registrata con l'API. L'utente effettua quindi la conversione sia nell'app dell'inserzionista sia sul sito web dell'inserzionista. Entrambe queste conversioni sono registrate come attivatori e attribuite al clic iniziale.

Un'intestazione HTTP di registrazione dell'origine basata su clic:

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

Viene registrato un trigger dall'app con il nome pacchetto com.advertiser.example:

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

Un trigger viene registrato da un browser del sito web con il dominio eTLD+1 https://advertiser.com:

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

Vengono generati i report a livello di evento risultanti. Supponendo che entrambi i trigger siano attribuiti all'origine, vengono generati i seguenti report a livello di evento:

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

Generare e inviare report

L'API Attribution Reporting invia report agli endpoint sul tuo server che accettano i report a livello di evento e i report aggregabili.

Forza l'esecuzione dei job di reporting

Dopo aver registrato un evento di origine dell'attribuzione o un evento di trigger, il sistema pianifica l'esecuzione del job di reporting. Per impostazione predefinita, questo job viene eseguito ogni 4 ore. A scopo di test, puoi forzare l'esecuzione dei job di reporting o ridurre gli intervalli tra i job.

Forza l'esecuzione del job di attribuzione:

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

Forza l'esecuzione del job di report a livello di evento:

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

Forza l'esecuzione del job di report aggregabile:

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

Controlla l'output in logcat per vedere quando sono stati eseguiti i job. Dovrebbe avere un aspetto simile al seguente:

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

Forzare l'invio dei report

Anche se il job di reporting deve essere eseguito, il sistema invia comunque i report in base ai tempi di invio pianificati, che vanno da un paio d'ore a diversi giorni. A scopo di test, puoi far avanzare l'orario di sistema del dispositivo affinché sia successivo ai ritardi pianificati per avviare l'invio del report.

Verificare i report sul server

Una volta inviati i report, verifica la consegna controllando i report ricevuti e i log del server applicabili, come la cronologia del server fittizia o il sistema personalizzato.

Decodificare il report aggregato

Quando ricevi un report aggregato, il campo debug_cleartext_payload contiene una versione non criptata del report aggregato. Questa versione del report non è criptata, ma deve comunque essere decodificata.

Di seguito è riportato un esempio di decodifica dei contenuti del campo debug_cleartext_payload in due passaggi: il primo utilizzando la decodifica in Base 64 e il secondo utilizzando la decodifica 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);
});

Test

Per iniziare a utilizzare l'API Attribution Reporting, puoi utilizzare il progetto MeasurementSampleApp su GitHub. Questa app di esempio illustra la registrazione dell'origine di attribuzione e la registrazione degli attivatori.

Per gli endpoint server, prendi in considerazione le seguenti risorse di riferimento o la tua soluzione personalizzata:

  • MeasurementAdTechServerSpec include definizioni di servizi OpenAPI, di cui è possibile eseguire il deployment su una simulazione supportata o su piattaforme di microservizi.
  • MeasurementAdTechServer include un'implementazione di riferimento di un server fittizio basato sull'app Spring Boot per Google App Engine.

Prerequisiti

Esegui il deployment di API fittizie su endpoint remoti accessibili dall'emulatore o dal dispositivo di test. Per semplificare i test, consulta i progetti di esempio MeasurementAdTechServerSpec e MeasurementAdTechServer.

Funzionalità da testare

  • Origini di attribuzione dell'allenamento e registrazioni dell'attivatore di conversione. Verifica che gli endpoint lato server rispondano con il formato corretto.
  • Eseguire i job di reporting.
  • Verifica la consegna dei report nel backend o nella console del server di test.

Funzionalità in arrivo

Configurazione flessibile a livello di evento

La configurazione predefinita per i report a livello di evento è consigliata per l'avvio dei test di utilità, ma potrebbe non essere ideale per tutti i casi d'uso. L'API Attribution Reporting supporterà configurazioni facoltative e più flessibili in modo che i tecnici pubblicitari abbiano un maggiore controllo sulla struttura dei loro report a livello di evento e siano in grado di massimizzare l'utilità dei dati. Questa ulteriore flessibilità verrà introdotta nell'API Attribution Reporting in due fasi:

  • Fase 1: configurazione a livello di evento flessibile Lite; un sottoinsieme della fase 2.
  • Fase 2: versione completa della configurazione flessibile a livello di evento.

Fase 1: livello di evento flessibile Lite

Aggiungeremo i seguenti due parametri facoltativi al JSON in 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>, ...]
  }
}

Esempio di configurazione personalizzata

Questa configurazione di esempio supporta uno sviluppatore che vuole ottimizzare per la ricezione di report in finestre di report precedenti.

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

Fase 2: livello di evento completamente flessibile

Oltre ai parametri che sono stati aggiunti nella fase 1, aggiungeremo un parametro facoltativo aggiuntivo trigger_specs al codice JSON in 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>, ...]
  }
}

Questa configurazione specifica completamente lo spazio di output dei report a livello di evento in base alla registrazione dell'origine. Per ogni specifica di trigger, specifichiamo in modo completo:

  • Un insieme di criteri di corrispondenza:
    • I dati trigger specifici a cui si applica questa specifica. Questa origine può essere abbinata solo ai trigger che hanno uno dei valori trigger_data specificati in trigger_specs. In altre parole, se l'attivatore corrisponde a questa origine, ma il suo trigger_data non è uno dei valori nella configurazione dell'origine, l'attivatore viene ignorato.
    • Quando un attivatore specifico corrisponde a questa specifica (utilizzando event_report_windows). Tieni presente che l'attivatore potrebbe comunque essere abbinato a un'origine aggregabile di report nonostante i due criteri di corrispondenza menzionati in precedenza non vadano a buon fine.
  • Un algoritmo specifico per il riepilogo e il bucketing di tutti i trigger all'interno di una finestra di attribuzione. In questo modo, gli attivatori possono specificare un parametro value che viene sommato per una determinata specifica, ma riportato come valore in bucket.

Gli attivatori supporteranno anche l'aggiunta di un parametro di valore facoltativo nei dizionari all'interno di event_trigger_data.

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

Ogni registrazione di trigger corrisponderà a un massimo di una specifica e il relativo valore di riepilogo associato verrà aggiornato. In linea generale, al momento dell'attivazione:

  • Applicare i filtri di attribuzione globali.
  • Per ogni specifica di trigger, valuta il valore event_trigger_data nella specifica per trovare una corrispondenza, utilizzando il valore event_reporting_window della specifica. Il livello event_reporting_windows di primo livello agisce come valore predefinito nel caso in cui qualsiasi specifica di trigger sia il sottocampo event_report_windows mancante.
  • La prima specifica corrispondente viene scelta per l'attribuzione e il valore di riepilogo viene incrementato di value.

Quando il valore event_report_window di una specifica viene completato, il relativo valore di riepilogo verrà mappato a un bucket e verrà inviato un report a livello di evento per ogni incremento nel bucket di riepilogo causato dai valori degli attivatori attribuiti. I report includeranno un campo aggiuntivo, trigger_summary_bucket.

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

Configurazioni equivalenti alla versione corrente

Di seguito sono riportate configurazioni equivalenti per le origini dell'evento attuale e della navigazione delle API, rispettivamente. In particolare per le sorgenti di navigazione, questo illustra perché i livelli di rumore sono così elevati rispetto alle origini eventi da mantenere gli stessi valori di epsilon: le origini di navigazione hanno uno spazio di output molto più ampio.

È possibile che ci siano più configurazioni equivalenti, dato che alcuni parametri possono essere impostati come predefiniti o eliminati.

Origini eventi equivalenti
// 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>,
}
Sorgenti di navigazione equivalenti
// 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>,
}

Esempi di configurazioni personalizzate

Di seguito sono riportate alcune configurazioni aggiuntive diverse da quelle predefinite. In tutti questi esempi, i compromessi dello sviluppatore includono:

  • riducendo alcune dimensioni della configurazione predefinita (#triggers, cardinalità dei dati di attivazione, #windows) per aumentarne un'altra per preservare il livello di rumore
  • riducendo alcune dimensioni della configurazione predefinita (#triggers, cardinalità dei dati di attivazione, #windows) per ridurre il livello di rumore

Bucket dei valori dell'attivatore del report

Questa configurazione di esempio supporta uno sviluppatore che vuole ottimizzare in base ai dati sul valore solo per una finestra di report (ad es. 7 giorni), scambiando meno finestre di report con meno rumore. In questo esempio, qualsiasi attivatore che imposti trigger_data su un valore diverso da 0 non è idoneo per l'attribuzione.

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

Puoi registrare i trigger con il set di campi value, che vengono sommati e suddivisi in bucket. Ad esempio, se sono presenti tre attivatori entro 7 giorni dalle registrazioni dell'origine con valori 1, 3 e 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}] }

I valori vengono sommati a 8 e riportati nei seguenti report dopo 7 giorni + 1 ora:

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

Nei 7 giorni successivi, vengono registrati i seguenti attivatori:

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

I valori vengono sommati a 8 + 50 + 45 = 103. A 14 giorni + 1 ora, verranno così generati i seguenti report:

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

// Report 3
{
  ...
  "trigger_summary_bucket": [100, MAX_INT]
}
Report conteggi trigger

Questo esempio mostra come uno sviluppatore può configurare un'origine per ottenere un conteggio massimo di attivatori.

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

Gli attivatori attribuiti con trigger_data impostato su 0 sono conteggiati e limitati a 10. Il valore dell'attivatore viene ignorato perché summary_window_operator è impostato su Conteggio. Se vengono registrati quattro attivatori e attribuiti alla sorgente, il report avrà il seguente aspetto:

// 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]
}
Binario con report più frequenti

Questa configurazione di esempio supporta uno sviluppatore che vuole sapere se nei primi dieci giorni si è verificata almeno una conversione (indipendentemente dal valore), ma vuole ricevere i report a intervalli più frequenti rispetto a quello predefinito. Anche in questo caso, qualsiasi attivatore che imposti trigger_data su un valore diverso da 0 non è idoneo per l'attribuzione. Per questo motivo questo caso d'uso è definito binario.

{
  "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]
  }],
}
Variare le specifiche dei trigger dall'origine all'origine
{
  "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
}

Invitiamo gli sviluppatori a suggerire possibili casi d'uso diversi per questa estensione API e aggiorneremo questo esplicativo con configurazioni di esempio per tali casi d'uso.

Attribuzione su più reti senza reindirizzamenti

Le tecnologie pubblicitarie dovrebbero usare i reindirizzamenti per registrare più attivatori di origini di attribuzione e per eseguire l'attribuzione su più reti. Questa funzionalità supporta l'attribuzione su più reti in cui i reindirizzamenti non sono attuabili su più reti. Scopri di più.

I tecnici pubblicitari possono inviare la configurazione nella risposta di registrazione dell'attivatore in base alle origini registrate da altre tecnologie pubblicitarie selezionate per generare le origini derivate. Queste origini derivate vengono quindi utilizzate per l'attribuzione. I report aggregati vengono generati se il trigger viene attribuito a un'origine derivata. La generazione di report sugli eventi per le origini derivate non è supportata.

I tecnici pubblicitari possono scegliere tra aggregation_keys nelle origini registrate che intendono condividere con le tecnologie pubblicitarie dei partner. Queste chiavi possono essere dichiarate nel campo shared_aggregation_keys facoltativo, che si trova sotto l'intestazione della registrazione di origine Attribution-Reporting-Register-Source:

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

Le origini derivate vengono generate in base alla configurazione sotto l'intestazione di registrazione del trigger 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]"
    }
  ]

Di seguito è riportata una versione con valori di esempio aggiunti:

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

Vengono aggiunti due nuovi campi facoltativi per attivare l'intestazione della registrazione. Questi campi abilitano le chiavi dei report aggregabili con l'identificatore della tecnologia pubblicitaria vincente:

  • x_network_bit_mapping: ID di registrazione alla mappatura dei bit dell'identificatore ad tech
  • x_network_data: offset (Maiusc a sinistra) per l'operazione x_network_bit_mapping della tecnologia pubblicitaria vincente con l'elemento chiave dell'attivatore
Esempio:
"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
  }
  …
}

Ecco il calcolo della parte chiave dell'attivatore risultante quando viene generato un report per l'origine di AdTechB:

  • key_piece: 0x400 (010000000000)
  • key_offset: 12
  • Valore enrollment_id di AdtechB: 2 (010) (da x_network_bit_mapping)
  • Elemento chiave dell'attivatore risultante: 0x400 | 0x2 << 12 = 0x2400

Limitazioni

Per un elenco delle funzionalità in corso per SDK Runtime, consulta le note di rilascio.

Segnalare bug e problemi

Il tuo feedback è una parte fondamentale di Privacy Sandbox su Android. Comunicaci eventuali problemi riscontrati o idee per migliorare Privacy Sandbox su Android.