Guida per gli sviluppatori dell'API Attribution Reporting

Mentre leggi Privacy Sandbox su Android documentazione, utilizza il pulsante Anteprima per sviluppatori o Beta per selezionare la versione del programma in uso, le istruzioni possono variare.


L'API Attribution Reporting è progettata per migliorare la privacy dell'utente tramite rimuovendo il ricorso a identificatori utente trasversali e 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 sugli annunci, visualizzazioni e conversioni richiamando metodi che registrano i trigger e origini di questi eventi.

Questa guida spiega come configurare gli endpoint del server e creare un'app client che chiami questi servizi. Scopri di più sul design complessivo dell'attribuzione L'API di reporting nella proposta di progettazione.

Termini chiave

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

Prima di iniziare

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

Configurare gli endpoint dell'API Attribution Reporting

L'API Attribution Reporting richiede un set 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 a lavorare è eseguire il deployment Definizioni del servizio OpenAPI v3 dal nostro codice campione di un repository in una piattaforma simulata o di microservizi. Puoi utilizzare la modalità Postman, Prisma o qualsiasi altro server fittizio che accetta questo formato. Esegui il deployment di ogni endpoint e tieni traccia degli URI da utilizzare nella tua app. Per verificare l'invio dei report, fai riferimento alle chiamate eseguite in precedenza alla piattaforma simulata o serverless.
  • Esegui il tuo server autonomo utilizzando il modello basato su Spring Boot Esempio di Kotlin. Esegui il deployment di questo server sul tuo cloud provider o interno dell'infrastruttura.
  • Utilizza le definizioni del servizio come esempi per integrare gli endpoint nel tuo di un sistema esistente.

Accetta registrazione 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, quindi, effettua una richiesta include una delle seguenti intestazioni:

  • Per gli eventi di clic:

    Attribution-Reporting-Source-Info: navigation
    
  • Per visualizzare gli eventi:

    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>

Ecco 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 gli URI dei partner di tecnologia pubblicitaria, l'API Attribution Reporting effettua una richiesta simile a ogni URI. Ogni partner di ad tech deve configurare un server che risponda con le seguenti 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 attivazione, 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>

Ecco 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 filtro. Questo gli ID chiave di aggregazione e le stringhe dei filtri non devono superare i 25 caratteri. In questo esempio, campaignCounts è costituito da 14 caratteri, quindi è un ID chiave di aggregazione valido, mentre 1234 è costituito da 4 caratteri, quindi è una stringa di filtro valida. Se l'ID della chiave di aggregazione o la stringa di filtro supera i 25 caratteri, l'attivatore viene ignorato.

Se Attribution-Reporting-Redirect contiene URI dei partner di tecnologia pubblicitaria, il valore L'API Attribution Reporting invia quindi una richiesta simile a ciascun URI. Ogni tecnologia pubblicitaria Il partner 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. Leggi l'articolo sull'iscrizione per una violazione delle norme sulla privacy Sandbox account per ulteriori informazioni sulla registrazione degli URI. (L'URI è dedotti dall'origine dei server utilizzati per accettare la registrazione di origine e attivare la registrazione.) Utilizzo degli URI di esempio per gli endpoint che accettano l'origine registrazione e accetta 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 ottenere ulteriori approfondimenti nei report sull'attribuzione. Scopri di più sulla loro configurazione.

Accettare i report aggregabili

Questo endpoint deve essere indirizzabile da un URI. Leggi l'articolo sull'iscrizione per una violazione delle norme sulla privacy Sandbox account per ulteriori informazioni sulla registrazione degli URI. (L'URI è dedotti dall'origine dei server utilizzati per accettare la registrazione di origine e attivare la registrazione.) Utilizzando gli URI di esempio per gli endpoint che accettano la registrazione della fonte e accettano la registrazione dell'attivatore, l'URI di questo endpoint è:

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

Entrambi i campi criptati e non criptati sono aggregabili report. I report criptati ti consentono di iniziare a eseguire test con il servizio di aggregazione, mentre il campo non criptato fornisce informazioni 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 ottenere ulteriori approfondimenti nei report sull'attribuzione. Scopri di più sulla loro configurazione.

Configura il client Android

L'app del cliente registra le origini e gli attivatori di attribuzione e attiva la generazione di report aggregabili a livello di evento. Per preparare un client Android un emulatore o un dispositivo per utilizzare l'API Attribution Reporting, procedi nel seguente modo:

  1. Configura il tuo ambiente di sviluppo per Privacy Sandbox su Android.
  2. Installa un'immagine di sistema su un dispositivo supportato oppure configurare un emulatore che supporti Privacy Sandbox su Android.
  3. Attiva l'accesso all'API Attribution Reporting eseguendo la classe successivo al comando ADB. (L'API è disabilitata per impostazione predefinita).

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

    adb shell device_config put adservices disable_measurement_enrollment_check "true"
  5. Includi l'autorizzazione ACCESS_ADSERVICES_ATTRIBUTION nel tuo Android File manifest e crea una configurazione di servizi pubblicitari per l'app utilizza le API Attribution Reporting:

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

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_AD_ID" />
    
  7. Fare riferimento a una configurazione di servizi pubblicitari nell'elemento <application> di il tuo 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 file manifest, ad esempio res/xml/ad_services_config.xml. Scopri di più su autorizzazioni dei servizi pubblicitari e controllo accesso SDK.

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

Registrare eventi relativi agli annunci

La tua app deve registrare le sorgenti e le conversioni man mano che si verificano per garantire che vengano segnalate correttamente. La classe MeasurementManager include metodi per registrare gli eventi relativi alle origini dell'attribuzione e attivatori di conversione.

Registra un evento origine attribuzione

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

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

  • Clic, che in genere registri in un metodo di callback simile a onClick(). L'evento di trigger corrispondente di solito si verifica subito dopo evento di clic. Questo tipo di evento fornisce maggiori 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 in un metodo di callback simile a onAdShown(). L'evento di trigger corrispondente può 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 del servizio all'indirizzo specificato da attributionSourceUri. La risposta dell'endpoint include i valori per destination, source_event_id, expiry e source_priority.

Se la tecnologia pubblicitaria di origine desidera condividere le registrazioni dell'origine, l'URI di origine dell'attribuzione può includere reindirizzamenti ad altri endpoint ad tech. Limiti le regole applicabili ai reindirizzamenti sono descritte nel dettaglio proposta tecnica.

È stato aggiunto il supporto per i reindirizzamenti daisy-chain per registerSource e registerTrigger. Oltre all'intestazione di registrazione, il consumatore dell'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.

Nell'intera catena viene utilizzato solo il campo "destinazione" fornito nella primissima visita. Il numero di visite presenta lo stesso limite del "Attribuzione-Report-Reindirizzamento" intestazioni. Questo supporto del reindirizzamento viene aggiunto all'elemento "Attribution-Reporting-Redirect" esistente assistenza e se entrambi sono presente, "Attribution-Reporting- Redirect" ottiene la preferenza.

Registra un evento di trigger di conversione

Per registrare un evento di attivazione della 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 del servizio all'indirizzo specificato da attributionTriggerUri. La risposta dell'endpoint include i valori per i report sugli eventi e aggregati.

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

Registra la misurazione cross-app e web

Se sia un'app sia un browser svolgono un ruolo nel percorso dell'utente dall'origine all'attivatore, esistono sottili differenze nell'implementazione della registrazione degli eventi correlati agli annunci. Se un utente visualizza un annuncio in un'app e viene reindirizzato a un browser per una conversione, la sorgente viene registrata dall'app e la conversione dal browser web. Analogamente, se un utente inizia su un browser e viene indirizzato a un'app per la conversione, il browser registra 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 le origini e gli attivatori quando si verificano sui browser. La differenza principale tra queste API e le API basate su app è che ci aspettiamo che il browser segua i reindirizzamenti, applichi filtri specifici per i browser e trasferire le registrazioni valide alla piattaforma chiamata registerWebSource() o registerWebTrigger().

Il seguente snippet di codice mostra un esempio della chiamata API che il 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 che il 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);

Aggiunta di rumore per la privacy

I report a livello di evento contengono dati su destinazione, ID origine attribuzione e trigger. Vengono inviati nel formato originale (non criptato) ai report origine dati. Per proteggere la privacy dell'utente, è possibile aggiungere rumore per renderlo più difficile per identificare un singolo utente. Vengono generati report a livello di evento con rumore inviate in conformità con il framework sulla privacy differenziale. Di seguito sono riportati i valori predefiniti della percentuale di rumore per diversi scenari:

Tipo di origine

Valore della destinazione della sorgente

Probabilità di report con rumore per registrazione di origine

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 da app a web, dove le sorgenti possono generare conversioni sia le destinazioni web sia quelle app, i report a livello di evento possono specificare se si è verificato un attivatore su app o web. Per compensare questo ulteriore dettaglio, i report con rumore generato sono fino a circa 7 volte per i clic e di circa 1,7 volte per le visualizzazioni.

Alcune tecnologie pubblicitarie non richiedono report a livello di evento per specificare se l'attivatore nella destinazione app o web. I professionisti del marketing digitale possono utilizzare il campo coarse_event_report_destinations sotto l'intestazione Attribution-Reporting-Register-Source per ridurre il rumore. Se una fonte con il campo coarse_event_report_destinations specificato vince l'attribuzione, il il report risultante include sia destinazioni app che web senza distinzione nel punto in cui si è verificato l'effettivo trigger.

Nei seguenti esempi, un utente fa clic su un annuncio e la sorgente viene registrata. con l'API. L'utente esegue poi la conversione sia nell'app dell'inserzionista che sito web dell'inserzionista. Entrambe queste conversioni vengono registrate come attivatori e attribuite al clic iniziale.

Un'intestazione HTTP di registrazione dell'origine basata sui 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"
}

Dall'app viene registrato un trigger con il nome del pacchetto com.advertiser.example:

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

Un trigger viene registrato da un browser sul 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 gli attivatori vengano 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 pubblicare report

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

Forza l'esecuzione dei job di reporting

Dopo aver registrato un evento di origine dell'attribuzione o un evento attivatore, il parametro nel sistema pianifica l'esecuzione del job di reporting. Per impostazione predefinita, questo job viene eseguito ogni 4 nell'orario lavorativo locale del TAM. Ai fini del test, puoi forzare l'esecuzione dei job di generazione di report o accorciare 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 reporting a livello di evento:

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

Forzare l'aggregazione del job di generazione dei report:

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

Forza la consegna dei report

Anche se l'esecuzione del job di reporting viene forzata, il sistema invia comunque i report in base ai tempi di consegna pianificati, che vanno da un paio di da alcune ore a diversi giorni. Per scopi di test, puoi anticipare l'ora di sistema del dispositivo in modo che sia successiva ai ritardi pianificati per avviare l'invio dei report.

Verificare i report sul server

Una volta inviati i report, verifica l'invio controllando i report ricevuti, i log del server applicabili, ad esempio la cronologia del server simulato o il tuo sistema personalizzato.

Decodificare il report aggregato

Quando ricevi un report aggregato, il campo debug_cleartext_payload contiene una versione non criptata del report aggregato. Sebbene questa versione del report non sia criptata, deve comunque essere decodificata.

Di seguito è riportato un esempio di decodifica dei contenuti del campo debug_cleartext_payload in due passaggi: il primo utilizza la decodifica Base 64 e il secondo 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 mostra l'origine della registrazione e attivare la registrazione.

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

  • MeasurementAdTechServerSpec include le definizioni del servizio OpenAPI, di cui è possibile eseguire il deployment su piattaforme fittizie o di microservizi supportate.
  • MeasurementAdTechServer include un'implementazione di riferimento di una simulazione basato sull'app Spring Boot per Google App Engine.

Prerequisiti

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

Funzionalità da testare

Funzionalità in arrivo

Configurazione flessibile a livello di evento

Si consiglia la configurazione predefinita per i report a livello di evento per iniziare test di utilità, ma potrebbe non essere l'ideale per tutti i casi d'uso. L'API Attribution Reporting supporterà configurazioni facoltative e più flessibili, in modo che le tecnologie pubblicitarie abbiano un maggiore controllo sulla struttura dei report a livello di evento e possano massimizzare l'utilità dei dati. Questa maggiore flessibilità nell'API Attribution Reporting in due fasi:

  • Fase 1: configurazione flessibile a livello di evento 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 eseguire l'ottimizzazione per ricevere report nelle finestre di reporting 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 aggiunti nella Fase 1, aggiungeremo parametro facoltativo aggiuntivo trigger_specs al 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. per registrazione di origine. Per ogni specifica dell'attivatore, specifichiamo completamente:

  • Una serie di criteri di corrispondenza:
    • I dati di attivazione specifici a cui si applica questa specifica. Questa origine è idonea per essere associata solo agli attivatori che hanno uno dei valori trigger_data specificati in trigger_specs. In altre parole, se l'attivatore corrisponde a questa origine, ma il relativo 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 associato a una sorgente per i report aggregabili nonostante non soddisfi i due criteri di corrispondenza menzionati in precedenza.
  • Un algoritmo specifico per riepilogare e suddividere in bucket tutti i trigger all'interno finestra di attribuzione. In questo modo, gli attivatori possono specificare un parametro value che viene sommato per una determinata specifica, ma viene riportato come valore raggruppato.

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

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

Ogni registrazione dell'attivatore corrisponderà a un massimo di una specifica dell'attivatore e aggiornerà il valore di riepilogo associato. A livello generale, al momento del trigger:

  • Applicare filtri di attribuzione globali.
  • Per ogni specifica dell'attivatore, valuta il event_trigger_data nella specifica per trovare una corrispondenza utilizzando il event_reporting_window della specifica. Il valore event_reporting_windows di primo livello funge da valore predefinito nel caso in cui una specifica dell'attivatore sia il sottocampo event_report_windows mancante.
  • Viene scelta la prima specifica corrispondente per l'attribuzione, mentre il valore di riepilogo incrementato di value.

Quando il valore event_report_window per una specifica viene completato, ne mapperemo il riepilogo a un bucket e invia un report a livello di evento per ogni incremento bucket di riepilogo causato dai valori trigger 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 le configurazioni equivalenti per le origini di navigazione e per gli eventi correnti delle API. Soprattutto per le sorgenti di navigazione, spiega perché i livelli di rumore sono così alti rispetto alle origini di eventi per mantengono gli stessi valori epsilon: le sorgenti di navigazione hanno un output molto più grande spazio.

È possibile che esistano più configurazioni equivalenti, dato che alcuni parametri possono essere impostati come predefiniti o potati.

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>,
}
Origini 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>,
}

Configurazioni personalizzate di esempio

Di seguito sono riportate alcune configurazioni aggiuntive rispetto ai valori predefiniti. In tutti questi esempi, i compromessi che uno sviluppatore può offrire sono:

  • riduzione di alcune dimensioni della configurazione predefinita (#trigger, dati di attivazione cardinalità, #windows) per aumentarne un'altra al fine di preservare il livello di rumore
  • riduzione di alcune dimensioni della configurazione predefinita (#trigger, dati di attivazione cardinalità, #windows) per un livello di rumore ridotto

Bucket di valori di trigger dei report

Questa configurazione di esempio supporta uno sviluppatore che vuole ottimizzare per il valore solo per una finestra di reporting (ad es. 7 giorni), con meno transazioni per ridurre il rumore. In questo esempio, qualsiasi attivatore che imposta 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]
  }],
}

Gli attivatori possono essere registrati con un set di campi value, che vengono sommati e in bucket. Ad esempio, se ci sono tre attivatori entro 7 giorni dall'origine registrazioni 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}] }

La somma dei valori è 8 + 50 + 45 = 103. Ciò genera i seguenti report dopo 14 giorni e 1 ora:

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

// Report 3
{
  ...
  "trigger_summary_bucket": [100, MAX_INT]
}
Conteggi degli attivatori dei report

Questo esempio mostra come uno sviluppatore può configurare un'origine per ottenere un conteggio attiva fino a 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]
  }],
}

Gli attivatori attribuiti con trigger_data impostato su 0 vengono conteggiati e limitati a 10. Il valore dell'attivatore viene ignorato perché summary_window_operator è impostato come conteggio. Se Quattro attivatori sono stati registrati e attribuiti all'origine; il report nel seguente modo:

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

Questa configurazione di esempio supporta uno sviluppatore che vuole sapere se nei primi 10 giorni si è verificata almeno una conversione (indipendentemente dal valore), ma vuole ricevere report a intervalli più frequenti rispetto a quello predefinito. Anche in questo esempio, qualsiasi attivatore che imposta 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]
  }],
}
Varia 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 diversi casi d'uso che potrebbero avere per questa estensione dell'API e aggiorneremo questa spiegazione con configurazioni di esempio per questi casi d'uso.

Attribuzione su più reti senza reindirizzamenti

Gli esperti di ad tech devono utilizzare i reindirizzamenti per registrare più attivatori delle origini di attribuzione e per eseguire l'attribuzione cross-network. Questa funzionalità consente di supportare l'attribuzione tra reti quando i reindirizzamenti non sono possibili tra le reti. Ulteriori informazioni.

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

I tecnici pubblicitari possono scegliere tra le aggregation_keys nelle loro origini registrate che che intende condividere con i partner ad tech. Queste chiavi possono essere dichiarate nel campo facoltativo shared_aggregation_keys, situato sotto l'intestazione Attribution-Reporting-Register-Source di registrazione dell'origine:

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

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

Ecco 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 attivano l'identificatore della tecnologia pubblicitaria vincente nelle chiavi dei report aggregabili:

  • x_network_bit_mapping: mappatura dei bit dell'ID registrazione all'identificatore ad tech
  • x_network_data: offset (spostamento a sinistra) per l'operazione OR x_network_bit_mapping della tecnologia pubblicitaria vincente con il componente 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
  }
  
}

Di seguito viene riportato il calcolo della parte chiave dell'attivatore risultante durante la generazione di un report per Fonte 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 di implementazione per il runtime dell'SDK, consulta le note di rilascio.

Segnalare bug e problemi

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