Guía para desarrolladores de la API de Attribution Reporting

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

La API de Attribution Reporting está diseñada para brindar una mayor privacidad del usuario, ya que quita la dependencia de los identificadores de usuario entre varias partes y admite casos de uso clave para la medición de atribución y conversión en apps. En esta guía para desarrolladores, se describe cómo configurar y probar las API de Attribution Reporting a fin de registrar clics, vistas y conversiones de anuncios mediante llamadas a métodos que registren los activadores y las fuentes relevantes para esos eventos.

En esta guía, aprenderás a configurar extremos del servidor y a compilar una app del cliente que llame a estos servicios. Más información sobre el diseño general de la API de Attribution Reporting en la propuesta de diseño.

Términos clave

  • Las fuentes de atribución hacen referencia a los clics o las vistas.
  • Los activadores son eventos que se pueden atribuir a las conversiones.
  • Los informes contienen datos sobre un activador y la fuente de atribución correspondiente. Estos informes se envían en respuesta a la activación de eventos. La API de Attribution Reporting admite los informes a nivel del evento y los informes agregables.

Antes de comenzar

Para usar la API de Attribution Reporting, completa las tareas del servidor y del cliente que se enumeran en las siguientes secciones.

Configura los extremos de la API de Attribution Reporting

La API de Attribution Reporting requiere un conjunto de extremos a los que puedes acceder desde un dispositivo de prueba o emulador. Crea un extremo para cada una de las siguientes tareas del servidor:

Existen varios métodos para configurar los extremos necesarios:

  • La forma más rápida de ponerse en marcha es implementar las definiciones del servicio OpenAPI v3 de nuestro repositorio de código de muestra en una plataforma de microservicios o de prueba. Puedes usar Postman, Prism o cualquier otra plataforma de servidor simulado que acepte este formato. Implementa cada extremo y realiza un seguimiento de los URI que se usarán en tu app. Para verificar la entrega del informe, consulta las llamadas realizadas anteriormente a la plataforma simulada o sin servidores.
  • Ejecuta tu propio servidor independiente con la muestra de Kotlin basada en Spring Boot. Implementa este servidor en tu proveedor de servicios en la nube o en tu infraestructura interna.
  • Usa las definiciones de servicio como ejemplos para integrar los extremos en tu sistema actual.

Acepta el registro de la fuente

Se debe poder acceder a este extremo desde un URI similar al siguiente:

https://adtech.example/attribution_source

Cuando una app del cliente registra una fuente de atribución, proporciona el URI para el extremo del servidor. Luego, la API de Attribution Reporting realiza una solicitud e incluye uno de los siguientes encabezados:

  • Para los eventos de clic:

    Attribution-Reporting-Source-Info: navigation
    
  • Para los eventos de vista:

    Attribution-Reporting-Source-Info: event
    

Configura tu extremo del servidor para que responda de la siguiente manera:

// 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]",
  "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": [{
    "id": "[key name]",
    "key_piece": "[key piece value]",
  },
  ..
  ]
}

// Specify additional ad tech URLs to register this source with.
Attribution-Reporting-Redirects: <Ad tech partner URIs; comma-separated>

Este es un ejemplo con valores de muestra agregados:

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

Si Attribution-Reporting-Redirects contiene URI de socios de tecnología publicitaria, la API de Attribution Reporting realiza una solicitud similar a cada URI. Cada socio de tecnología publicitaria debe configurar un servidor que responda con los siguientes encabezados:

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

Acepta el registro del activador de conversión

Se debe poder acceder a este extremo desde un URI similar al siguiente:

https://adtech.example/attribution_trigger

Cuando una app del cliente registra un evento activador, proporciona el URI para el extremo del servidor. Luego, la API de Attribution Reporting realiza una solicitud e incluye uno de los siguientes encabezados:

Configura tu extremo del servidor para que responda de la siguiente manera:

// 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.
    // Note: "source_type" can be used as a key to filter based on the source's
    // type "navigation" or "event".
    // The first "Event-Trigger" that matches, based on "filters" and
    // "not_filters", is used for report generation. If there are no matches,
    // no report is generated.
    "filters": {
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from "filters" or the attribution source's
      // "filter_data", it isn't 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 the attribution source's
      // "filter_data", it isn't used during matching.
      "[key name 2]": ["key2 value 1", "key2 value 2"],
    }
  }],
  // Specify a list of dictionaries that generates aggregation keys.
  "aggregabtable_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" and "not_filters" are optional fields, similar to the 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
  // that they're generated.
  "aggregabtable_values": [
     // Each source event can contribute a maximum of L1 = 2^16 to the aggregate
     // histogram.
    {
     "[key_name]": [value]
    },
    ..
  ]
}
// Specify additional Adtech URLs to register this trigger with.
Attribution-Reporting-Redirects: <Ad tech partner URIs, comma-separated>

Este es un ejemplo con valores de muestra agregados:

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": {
      "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": {
      "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"]
    },
    {
      // 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", "nonMatchingIdsListedHereAreIgnored"]
    }
  ],
  "aggregatable_values": [
    {
      // Privacy budget for each key is L1 / 2 = 2^15 (32768).
      // Conversion count was 1.
      // Scale the count to use the full budget allocated: 1 * 32768 = 32768.
      "campaignCounts": 32768,

      // Purchase price was $52.
      // Purchase values for the app range from $1 to $1,024 (integers only).
      // Scaling factor applied is 32768 / 1024 = 32.
      // For $52 purchase, scale the value by 32 ($52 * 32 = $1,664).
      "geoValue": 1664
    }
  ]
}
Attribution-Reporting-Redirects:https://adtechpartner.example?app_install=567

Si Attribution-Reporting-Redirects contiene URI de socios de tecnología publicitaria, la API de Attribution Reporting realiza una solicitud similar a cada URI. Cada socio de tecnología publicitaria debe configurar un servidor que responda con los siguientes encabezados:

// 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]",
    // "filters" and "not_filters" are optional fields which allow configuring
    // for configuring different event trigger data based on the attribution]
    // source's "filter_data". Note that "source_type" can be used as a key to
    // filter based on the source's type "navigation" or "event".
    // The first "Event-Trigger" that matches, based on "filters" and
    // "not_filters", is used for report generation. If there are no matches,
    // no report is generated.
    "filters": {
      "[key name 1]": ["key1 value 1", "key1 value 2"],
      // If a key is missing from "filters" or the attribution source's
      // "filter_data", it isn't 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 the attribution source's
      // "filter_data", it isn't 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" and "not_filters" are optional fields, similar to the 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-Redirects header is ignored for ad tech partners.

Acepta informes a nivel del evento

Se debe poder acceder a este extremo desde un URI. Hasta que Privacy Sandbox en Android ofrezca compatibilidad para inscribir tu propio URI de notificación, el URI se infiere de eTLD+1 de los servidores que se usan para aceptar el registro de la fuente y del activador. Con los URIs de ejemplo para extremos, que aceptan el registro de la fuente y aceptan el registro del activador, el URI de este extremo es el siguiente:

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

Configura este servidor para que acepte solicitudes JSON que usan el siguiente 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"
}

Acepta informes agregables

Se debe poder acceder a este extremo desde un URI. Hasta que Privacy Sandbox en Android ofrezca compatibilidad para inscribir tu propio URI de notificación de conversión, el URI se infiere desde el origen de los servidores que se usan para aceptar el registro de la fuente y del activador. Con los URIs de ejemplo para extremos, que aceptan el registro de la fuente y aceptan el registro del activador, el URI de este extremo es el siguiente:

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

Actualmente, los campos encriptados y no encriptados se propagan para los informes agregables. Los informes encriptados te permiten comenzar a realizar pruebas con el servicio de agregación, mientras que el campo sin encriptar proporciona estadísticas sobre la forma en que los pares clave-valor establecidos estructuran los datos.

Configura este servidor para que acepte solicitudes JSON que usan el siguiente 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]"
}

Configura el cliente de Android

La app del cliente registra los activadores y las fuentes de atribución, y habilita la generación de informes agregables y a nivel del evento. Si deseas preparar un dispositivo o emulador cliente de Android para usar la API de Attribution Reporting, haz lo siguiente:

  1. Configura tu entorno de desarrollo para Privacy Sandbox en Android.
  2. Instala una imagen del sistema en un dispositivo compatible o configura un emulador que incluya compatibilidad con Privacy Sandbox en Android.
  3. Habilita el acceso a la API de Attribution Reporting mediante la ejecución del siguiente comando adb (la API está inhabilitada de forma predeterminada).

    adb shell device_config put adservices ppapi_app_allow_list \"*\"
    
  4. Incluye el permiso ACCESS_ADSERVICES_ATTRIBUTION y crea una configuración de servicios de anuncios para que tu app use las APIs de Attribution Reporting, como se muestra en el siguiente fragmento de código:

    <uses-permission android:name="android.permission.ACCESS_ADSERVICES_ATTRIBUTION" />
    
  5. Especifica el recurso XML de servicios de anuncios al que se hace referencia en el manifiesto, como res/xml/ad_services_config.xml. Obtén más información sobre los permisos de los servicios de anuncios y el control de acceso al SDK.

    <property android:name="android.adservices.AD_SERVICES_CONFIG"
          android:resource="@xml/ad_services_config" />
    
  6. Haz referencia a una configuración de servicios de anuncios en el elemento <application> de tu manifiesto:

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

Registra eventos de anuncios

Tu app deberá registrar fuentes y conversiones a medida que ocurran para asegurarse de que se informen de forma correcta. La clase MeasurementManager cuenta con métodos para ayudarte a registrar eventos de fuente de atribución y activadores de conversión.

Registra un evento de fuente de atribución

Cuando se ve un anuncio o se hace clic en este, una app de publicador llama a registerSource() para registrar una fuente de atribución, como se muestra en el fragmento de código.

La API de Attribution Reporting admite los siguientes tipos de eventos de fuentes de atribución:

  • Clics, que suelen registrarse en un método de devolución de llamada similar a onClick(). Por lo general, el evento activador correspondiente ocurre poco después del evento de clic. Este tipo de evento proporciona más información sobre la interacción del usuario y, por lo tanto, representa un buen tipo de fuente de atribución para darle una prioridad alta.
  • Vistas, que suelen registrarse en un método de devolución de llamada similar a onAdShown(). El evento de activación correspondiente puede ocurrir horas o días después del evento de vista.

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

Después del registro, la API emite una solicitud HTTP POST al extremo del servicio en la dirección que especifica attributionSourceUri. La respuesta del extremo incluye valores para destination, source_event_id, expiry y source_priority.

Si la tecnología publicitaria de origen desea compartir los registros de la fuente, el URI de la fuente de atribución original puede incluir redireccionamientos a otros extremos de tecnología publicitaria. Los límites y las reglas que rigen para los redireccionamientos se detallan en la propuesta técnica.

Registra un evento de activador de conversión

Para registrar un evento de activador de conversión, llama a registerTrigger() en tu 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)

Después del registro, la API emite una solicitud HTTP POST al extremo del servicio en la dirección que especifica attributionTriggerUri. La respuesta del extremo incluye valores para los informes agregados y de eventos.

Si la plataforma de tecnología publicitaria de origen permite que se compartan registros de activadores, el URI puede incluir redireccionamientos a URI que pertenezcan a otras plataformas de tecnología publicitaria. Los límites y las reglas que rigen para los redireccionamientos se detallan en la propuesta técnica.

Registra la medición web y entre apps

En el caso de que una app y un navegador desempeñen un papel en el recorrido que realiza el usuario desde la fuente hasta el activador, hay diferencias sutiles en la implementación del registro de eventos de anuncios. Si un usuario ve un anuncio en una app y se lo redirecciona a un navegador para generar una conversión, la app registra la fuente y el navegador web genera la conversión. Del mismo modo, si un usuario se inicia en un navegador web y se lo dirige a una app para la conversión, el navegador registra la fuente y la app registra la conversión.

Dado que existen diferencias en la forma en que se organizan las AdTech en la Web y en Android, agregamos nuevas APIs para registrar fuentes y activadores cuando se realizan en navegadores. La diferencia clave entre estas APIs y las APIs basadas en apps correspondientes es que esperamos que el navegador siga los redireccionamientos, aplique filtros específicos del navegador y pase los registros válidos a la plataforma con la llamada a registerWebSource() o registerWebTrigger().

En el siguiente fragmento de código, se muestra un ejemplo de la llamada a la API que realiza el navegador para registrar una fuente de atribución antes de dirigir al usuario a una 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 adtech.
    .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 adtech.
    .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);

En el siguiente fragmento de código, se muestra un ejemplo de la llamada a la API que realiza el navegador para registrar una conversión después de que se dirige al usuario desde la 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 adtech.
    .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 adtech.
    .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);

Genera y publica informes

La API de Attribution Reporting envía informes a los extremos de tu servidor que aceptan informes a nivel del evento y agregables.

Fuerza la ejecución de los trabajos de informes

Después de registrar un evento de fuente de atribución o de un activador, el sistema programa la ejecución de la tarea de informes. De forma predeterminada, esta tarea se ejecuta cada 4 horas. Si deseas realizar pruebas, puedes forzar la ejecución de las tareas de informes o reducir los intervalos entre estas.

Fuerza la ejecución de la tarea de atribución:

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

Fuerza la ejecución de la tarea de informe a nivel del evento:

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

Fuerza la ejecución de la tarea de informe agregable:

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

Verifica el resultado en logcat para comprobar cuándo se ejecutaron las tareas. Debería verse similar a lo siguiente:

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

Fuerza la entrega de informes

Incluso si se fuerza la ejecución de la tarea de informes, el sistema envía informes según sus tiempos de entrega programados, que varían de un par de horas a varios días. Si deseas realizar pruebas, puedes aplazar el tiempo del sistema del dispositivo para después de las demoras programadas a fin de iniciar la entrega del informe.

Verifica los informes en tu servidor

Una vez que se envían los informes, comprueba la entrega mediante la revisión de los informes recibidos, los registros del servidor aplicables, como el historial de servidor simulado o tu sistema personalizado.

Prueba

Para ayudarte a comenzar a usar la API de Attribution Reporting, puedes usar el proyecto MeasurementSampleApp en GitHub. Esta app de ejemplo muestra el registro de la fuente de atribución y del activador.

Para los extremos del servidor, considera los siguientes recursos de referencia o tu solución personalizada:

  • MeasurementAdTechServerSpec incluye definiciones del servicio de OpenAPI, que se pueden implementar en una plataforma simulada o de microservicios compatible.
  • MeasurementAdTechServer incluye una implementación de referencia de un servidor simulado basado en la app de Spring Boot para Google App Engine.

Requisitos previos

Implementa APIs de prueba en extremos remotos a los que se puede acceder desde tu dispositivo de prueba o emulador. Para facilitar las pruebas, consulta los proyectos de muestra MeasurementAdTechServerSpec y MeasurementAdTechServer.

Funcionalidad para realizar pruebas

  • Registra la fuente de atribución y el activador de conversión. Verifica que los extremos del servidor respondan con el formato correcto.
  • Ejecuta las tareas de informes
  • Verifica la entrega de informes en el backend o la consola del servidor de prueba.

Limitaciones

A fin de obtener una lista de las funciones en curso para el entorno de ejecución del SDK, consulta las notas de la versión.

Informa errores y problemas

Tus comentarios son una parte fundamental de Privacy Sandbox en Android. Avísanos si tienes problemas o ideas para mejorar Privacy Sandbox en Android.