A medida que leas la documentación de Privacy Sandbox en Android, usa el botón Versión preliminar para desarrolladores o Beta para seleccionar la versión del programa con la que estás trabajando, ya que las instrucciones pueden variar.
La API de Protected Audience en Android (que anteriormente se denominaba FLEDGE) incluye la API de Custom Audience y la de Ad Selection. Las plataformas de tecnología publicitaria y los anunciantes pueden usar estas APIs para publicar anuncios personalizados según la participación anterior en la app limitando el uso compartido de identificadores entre apps y el uso compartido de la información sobre la interacción en la app del usuario con terceros.
La API de Custom Audience se centra en la abstracción de "público personalizado", que representa a un grupo de usuarios con intenciones comunes. Un anunciante puede registrar un usuario con un público personalizado y asociar anuncios relevantes con este. Esta información se almacena de forma local y puede ayudar a definir las ofertas de los anunciantes, el filtrado y la renderización de anuncios.
La API de Ad Selection proporciona un framework que permite que varios desarrolladores ejecuten una subasta a nivel local para un público personalizado. Para lograrlo, el sistema tiene en cuenta los anuncios relevantes asociados con el público personalizado y realiza un procesamiento adicional en anuncios que una plataforma de tecnología publicitaria muestra en el dispositivo.
Las plataformas de tecnología publicitaria pueden integrar estas APIs para implementar el remarketing que preserva la privacidad del usuario. En versiones futuras, se planea admitir casos de uso adicionales, como anuncios de instalación de aplicación. Obtén más información sobre la API de Protected Audience en Android en la propuesta de diseño.
En esta guía, se describe cómo trabajar con la API de Protected Audience en Android para hacer lo siguiente:
- Administrar públicos personalizados
- Configurar y ejecutar la selección de anuncios en un dispositivo
- Informar impresiones de anuncios
Antes de comenzar
Antes de comenzar, completa lo siguiente:
- Configura tu entorno de desarrollo para Privacy Sandbox en Android.
- Instala una imagen del sistema en un dispositivo compatible o configura un emulador que incluya compatibilidad con Privacy Sandbox en Android.
En una terminal, habilita el acceso a la API de Protected Audience (inhabilitada de forma predeterminada) con el siguiente comando adb.
adb shell device_config put adservices ppapi_app_allow_list \"*\"
Incluye un permiso
ACCESS_ADSERVICES_CUSTOM_AUDIENCE
en el manifiesto de tu app:<uses-permission android:name="android.permission.ACCESS_ADSERVICES_CUSTOM_AUDIENCE" />
Haz referencia a una configuración de servicios de anuncios en el elemento
<application>
de tu manifiesto:<property android:name="android.adservices.AD_SERVICES_CONFIG" android:resource="@xml/ad_services_config" />
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.<ad-services-config> <custom-audiences allowAllToAccess="true" /> </ad-services-config>
De forma predeterminada, la API de Ad Selection aplica límites a la cantidad máxima de memoria que una secuencia de comandos de informes de impresiones o subastas puede asignar. La función de limitación de memoria requiere la versión 105.0.5195.58 de WebView o una posterior. La plataforma aplica una verificación de versión, y las llamadas a las APIs de
selectAds
yreportImpression
fallan si no se satisface. Existen dos alternativas para configurar esta opción:La primera es ejecutar el siguiente comando adb para inhabilitar esta verificación:
adb device_config put fledge_js_isolate_enforce_max_heap_size false
La segunda es instalar WebView Beta desde Google Play Store. Debe ser igual a la versión que se mencionó antes o posterior.
Únete a un público personalizado
Un público personalizado representa a un grupo de usuarios con intenciones o intereses comunes, según lo decide la app de un anunciante. Una app o un SDK pueden usar un público personalizado para indicar un público en particular, por ejemplo, una persona que dejó artículos en un carrito de compras. Para crear un público personalizado o unirte a uno de forma asíncrona, haz lo siguiente:
- Inicializa el objeto
CustomAudienceManager
. - Especifica parámetros clave, como el paquete del comprador y un nombre relevante, para crear un objeto
CustomAudience
. Luego, inicializa el objetoJoinCustomAudienceRequest
con el objetoCustomAudience
. - Llama a
joinCustomAudience()
asíncrono con el objetoJoinCustomAudienceRequest
y los objetosExecutor
yOutcomeReceiver
relevantes.
Kotlin
val customAudienceManager: CustomAudienceManager =
context.getSystemService(CustomAudienceManager::class.java)
// Initialize a custom audience.
val audience = CustomAudience.Builder()
.setBuyer(buyer)
.setName(name)
...
.build()
// Initialize a custom audience request.
val joinCustomAudienceRequest: JoinCustomAudienceRequest =
JoinCustomAudienceRequest.Builder().setCustomAudience(audience).build()
// Request to join a custom audience.
customAudienceManager.joinCustomAudience(joinCustomAudienceRequest,
executor,
outcomeReceiver)
Java
CustomAudienceManager customAudienceManager =
context.getSystemService(CustomAudienceManager.class);
// Initialize a custom audience.
CustomAudience audience = new CustomAudience.Builder()
.setBuyer(buyer)
.setName(name)
...
.build();
// Initialize a custom audience request.
JoinCustomAudienceRequest joinCustomAudienceRequest =
new JoinCustomAudienceRequest.Builder().setCustomAudience(audience).build();
// Request to join a custom audience.
customAudienceManager.joinCustomAudience(joinCustomAudienceRequest,
executor,
outcomeReceiver);
La combinación de los siguientes parámetros identifica de manera única cada objeto CustomAudience
en un dispositivo:
owner
: Nombre del paquete de la app del propietario. Se le asigna de forma implícita el nombre del paquete de la app que realiza la llamada.buyer
: Identificador de la red de publicidad del comprador que administra los anuncios para este público personalizado.name
: Identificador o nombre arbitrario para el público personalizado.
Llamar a joinCustomAudience()
de forma continua con una instancia diferente de CustomAudience
actualiza cualquier CustomAudience
existente con owner, buyer
que coincida y los parámetros name
. Para ayudar a preservar la privacidad, el resultado de la API no distingue entre "creación" y "actualización".
Además, se debe crear CustomAudience
con estos parámetros obligatorios:
- URL de actualización diaria: URL HTTPS que se consulta a diario en segundo plano para actualizar con relación a un público personalizado los indicadores de ofertas del usuario, los datos de ofertas de confianza, y las URLs de renderización y los metadatos para anuncios.
- URL de lógica de ofertas: URL HTTPS que se consulta durante la selección de anuncios para recuperar la lógica de ofertas de JavaScript de un comprador. Consulta las firmas de las funciones necesarias en JavaScript.
- IDs de renderización de anuncios: Un ID arbitrario establecido por la tecnología publicitaria del comprador. Esta es una optimización para generar la carga útil de B&A.
Entre los parámetros opcionales para un objeto CustomAudience
, se pueden incluir los siguientes:
- Hora de activación: Un público personalizado solo puede participar en la selección de anuncios y en las actualizaciones diarias después de su hora de activación. Por ejemplo, esto puede ser útil para atraer a los usuarios inactivos de una app.
- Hora de vencimiento: Momento en el futuro en el que se quita el público personalizado del dispositivo.
- Indicadores de ofertas del usuario: Cadena JSON que contiene indicadores del usuario, como la configuración regional preferida del usuario, que consume la lógica de ofertas de JavaScript de un comprador para generar ofertas durante el proceso de selección de anuncios. Este formato permite que las plataformas de tecnología publicitaria vuelvan a usar el código en distintas plataformas y facilita el consumo de funciones de JavaScript.
- Datos de ofertas de confianza: URL HTTPS y lista de cadenas que se usan durante el proceso de selección de anuncios y recuperan los indicadores de ofertas de un servicio de pares clave-valor de confianza.
- Anuncios: Lista de objetos
AdData
correspondientes a los anuncios que participan en la selección de anuncios. Cada objetoAdData
consta de lo siguiente:- URL de renderización: URL HTTPS que se consulta para renderizar el anuncio final.
- Metadatos: Objeto JSON serializado como una cadena que contiene información que consumirá la lógica de ofertas del comprador durante el proceso de selección de anuncios.
- Filtros de anuncios: Clase que contiene toda la información necesaria para el filtrado de anuncios de instalación de aplicaciones y la limitación de frecuencia durante la selección de anuncios.
Este es un ejemplo de la creación de una instancia del objeto CustomAudience
:
Kotlin
// Minimal initialization of a CustomAudience object
val customAudience: CustomAudience = CustomAudience.Builder()
.setBuyer(AdTechIdentifier.fromString("my.buyer.domain.name"))
.setName("example-custom-audience-name")
.setDailyUpdateUrl(Uri.parse("https://DAILY_UPDATE_URL"))
.setBiddingLogicUrl(Uri.parse("https://BIDDING_LOGIC_URL"))
.build()
Java
// Minimal initialization of a CustomAudience object
CustomAudience customAudience = CustomAudience.Builder()
.setBuyer(AdTechIdentifier.fromString("my.buyer.domain.name"))
.setName("example-custom-audience-name")
.setDailyUpdateUrl(Uri.parse("https://DAILY_UPDATE_URL"))
.setBiddingLogicUrl(Uri.parse("https://BIDDING_LOGIC_URL"))
.build();
Controla los resultados de joinCustomAudience()
El método joinCustomAudience()
asíncrono usa el objeto OutcomeReceiver
para indicar el resultado de la llamada a la API.
- La devolución de llamada
onResult()
indica que el público personalizado se creó o se actualizó de forma correcta. - La devolución de llamada
onError()
indica dos condiciones posibles.- Si
JoinCustomAudienceRequest
se inicializa con argumentos no válidos,AdServicesException
indicaIllegalArgumentException
como la causa. - Todos los demás errores recibirán
AdServicesException
conIllegalStateException
como la causa.
- Si
Este es un ejemplo de control del resultado de joinCustomAudience()
:
Kotlin
var callback: OutcomeReceiver<Void, AdServicesException> =
object : OutcomeReceiver<Void, AdServicesException> {
override fun onResult(result: Void) {
Log.i("CustomAudience", "Completed joinCustomAudience")
}
override fun onError(error: AdServicesException) {
// Handle error
Log.e("CustomAudience", "Error executing joinCustomAudience", error)
}
};
Java
OutcomeReceiver callback = new OutcomeReceiver<Void, AdServicesException>() {
@Override
public void onResult(@NonNull Void result) {
Log.i("CustomAudience", "Completed joinCustomAudience");
}
@Override
public void onError(@NonNull AdServicesException error) {
// Handle error
Log.e("CustomAudience", "Error executing joinCustomAudience", error);
}
};
Abandona un público personalizado
Si el usuario ya no satisface los criterios comerciales para un público personalizado determinado, una app o un SDK puede llamar a leaveCustomAudience()
para quitar el público personalizado del dispositivo. Para quitar CustomAudience
según sus parámetros únicos, haz lo siguiente:
- Inicializa el objeto
CustomAudienceManager
. - Inicializa
LeaveCustomAudienceRequest
conbuyer
yname
del público personalizado. Para obtener más información sobre estos campos de entrada, consulta "Únete a un público personalizado". - Llama al método asíncrono
leaveCustomAudience()
con el objetoLeaveCustomAudienceRequest
y los objetosExecutor
yOutcomeReceiver
relevantes.
Kotlin
val customAudienceManager: CustomAudienceManager =
context.getSystemService(CustomAudienceManager::class.java)
// Initialize a LeaveCustomAudienceRequest
val leaveCustomAudienceRequest: LeaveCustomAudienceRequest =
LeaveCustomAudienceRequest.Builder()
.setBuyer(buyer)
.setName(name)
.build()
// Request to leave a custom audience
customAudienceManager.leaveCustomAudience(
leaveCustomAudienceRequest,
executor,
outcomeReceiver)
Java
CustomAudienceManager customAudienceManager =
context.getSystemService(CustomAudienceManager.class);
// Initialize a LeaveCustomAudienceRequest
LeaveCustomAudienceRequest leaveCustomAudienceRequest =
new LeaveCustomAudienceRequest.Builder()
.setBuyer(buyer)
.setName(name)
.build();
// Request to leave a custom audience
customAudienceManager.leaveCustomAudience(
leaveCustomAudienceRequest,
executor,
outcomeReceiver);
De manera similar a cuando se llama a joinCustomAudience()
, el objeto OutcomeReceiver
indica el final de una llamada a la API. Para ayudar a proteger la privacidad, un resultado de error no diferencia entre errores internos y argumentos no válidos. Se llama a la devolución de llamada onResult()
cuando se completa la llamada a la API, independientemente de si un público personalizado se quita de forma correcta o no.
Ejecuta la selección de anuncios
Si deseas usar la API de Protected Audience para seleccionar anuncios, llama al método selectAds()
:
- Inicializa un objeto
AdSelectionManager
. - Compila un objeto
AdSelectionConfig
. - Llama al método asíncrono
selectAds()
con el objetoAdSelectionConfig
y los objetosExecutor
yOutcomeReceiver
relevantes.
Kotlin
val adSelectionManager: AdSelectionManager =
context.getSystemService(AdSelectionManager::class.java)
// Initialize AdSelectionConfig
val adSelectionConfig: AdSelectionConfig =
AdSelectionConfig.Builder().setSeller(seller)
.setDecisionLogicUrl(decisionLogicUrl)
.setCustomAudienceBuyers(customAudienceBuyers)
.setAdSelectionSignals(adSelectionSignals)
.setSellerSignals(sellerSignals)
.setPerBuyerSignals(perBuyerSignals)
.setBuyerContextualAds(
Collections.singletonMap(
contextualAds.getBuyer(), contextualAds
)
).build()
// Run ad selection with AdSelectionConfig
adSelectionManager.selectAds(
adSelectionConfig, executor, outcomeReceiver
)
Java
AdSelectionManager adSelectionManager =
context.getSystemService(AdSelectionManager.class);
// Initialize AdSelectionConfig
AdSelectionConfig adSelectionConfig =
new AdSelectionConfig.Builder()
.setSeller(seller)
.setDecisionLogicUrl(decisionLogicUrl)
.setCustomAudienceBuyers(customAudienceBuyers)
.setAdSelectionSignals(adSelectionSignals)
.setSellerSignals(sellerSignals)
.setPerBuyerSignals(perBuyerSignals)
.setBuyerContextualAds(
Collections.singletonMap(contextualAds.getBuyer(), contextualAds)
)
.build();
// Run ad selection with AdSelectionConfig
adSelectionManager.selectAds(adSelectionConfig, executor, outcomeReceiver);
El método selectAds()
requiere una entrada AdSelectionConfig
, en la que debes especificar los siguientes parámetros obligatorios:
- Vendedor: Es el identificador de la red de publicidad del vendedor que inicia la selección de anuncios.
- URL de lógica de decisión: Es una URL HTTPS que se consulta para obtener la lógica de JavaScript de la red de publicidad del vendedor.
- URL HTTPS: Se consulta para obtener la lógica de JavaScript de la red de publicidad del vendedor. Consulta las firmas de las funciones necesarias.
- URI compilado previamente: Sigue el formato de selección de anuncios de FLEDGE.
Se arroja
IllegalArgumentException
si se pasa un URI compilado previamente no compatible o con un formato incorrecto.
- Compradores de públicos personalizados: Es una lista completa de identificadores de redes de publicidad de compradores que el vendedor permite para participar en el proceso de selección de anuncios.
Estos identificadores de compradores corresponden al
CustomAudience.getBuyer()
de los públicos personalizados participantes.
De manera opcional, los siguientes parámetros se pueden especificar para una selección de anuncios más personalizada:
- Indicadores de la selección de anuncios: Es un objeto JSON, serializado como una cadena, que contiene indicadores que consumirá la lógica de ofertas de JavaScript del comprador que se recupera de
CustomAudience.getBiddingLogicUrl()
. - Indicadores del vendedor: Es un objeto JSON, serializado como una cadena, que contiene indicadores que consumen la lógica de decisión recuperada de JavaScript del vendedor desde
AdSelectionConfig.getDecisionLogicUrl()
. - Indicadores por comprador: Es un mapa de objetos JSON, serializado como cadenas, que contiene los indicadores que consumirá la lógica de ofertas de JavaScript de compradores específicos que se recupera de
CustomAudience.getBiddingLogicUrl()
. Estos indicadores son identificados por los campos del comprador de los públicos personalizados que participan. - Anuncios contextuales: Es un conjunto de candidatos de anuncios que se recopilan directamente de los compradores durante una subasta que ocurre fuera de una subasta de Protected Audience.
Una vez que se selecciona un anuncio, los resultados, las ofertas y los indicadores se conservan de forma interna para la generación de informes. La devolución de llamada OutcomeReceiver.onResult()
muestra un AdSelectionOutcome
que contiene lo siguiente:
- Una URL de renderización para el anuncio ganador, que se obtiene de
AdData.getRenderUrl()
- Un ID de selección de anuncios único para el usuario del dispositivo, que se utiliza para informar la impresión de anuncios
Si la selección de anuncios no se puede completar correctamente debido a argumentos no válidos, tiempos de espera o un consumo excesivo de recursos, la devolución de llamada OutcomeReceiver.onError()
proporciona AdServicesException
con los siguientes comportamientos:
- Si la selección de anuncios se inicia con argumentos no válidos,
AdServicesException
indicaráIllegalArgumentException
como la causa. - Todos los demás errores recibirán
AdServicesException
conIllegalStateException
como la causa.
Anuncios contextuales
Protected Audience puede incorporar anuncios contextuales en una subasta protegida.
Los anuncios contextuales deben seleccionarse en el servidor de tecnología publicitaria, firmarse y mostrarse al dispositivo fuera de las APIs de Protected Audience. Los anuncios contextuales se pueden incluir en la subasta a través de AdSelectionConfig
. En ese momento, si se verifican sus firmas, funcionarán igual que en los anuncios integrados en el dispositivo, lo que incluye la elegibilidad para el filtrado negativo de anuncios. Una vez que se complete la subasta de Protected Audience, deberás invocar a reportImpression()
. De esta manera, se llama a reportWin()
en el anuncio contextual ganador, siguiendo el mismo patrón que los informes de impresiones, para recibir el anuncio ganador en un dispositivo. Cada anuncio contextual necesita un comprador, una oferta, un vínculo a la lógica de informes, una URL de renderización y los metadatos del anuncio.
Para implementar anuncios contextuales en la app, la app de destino debe crear un objeto SignedContextualAds
:
Kotlin
val signedContextualAds: SignedContextualAds =
Builder().setBuyer(AdTechIdentifier.fromString(mBiddingLogicUri.getHost()))
//Pass in your valid app install ads
.setDecisionLogicUri(mContextualLogicUri)
.setAdsWithBid(appInstallAd)
.setSignature(signature)
.build()
Java
SignedContextualAds signedContextualAds = new SignedContextualAds.Builder()
.setBuyer(AdTechIdentifier.fromString(mBiddingLogicUri.getHost()))
.setDecisionLogicUri(mContextualLogicUri)
//Pass in your valid app install ads
.setAdsWithBid(appInstallAd)
.setSignature(signature)
.build();
El objeto SignedContextualAds
resultante se puede pasar cuando se crea la AdSelectionConfig
:
Kotlin
val adSelectionConfig = AdSelectionConfig.Builder()
.setPerBuyerSignedContextualAds(signedContextualAds)
// Other fields for your config
.build()
Java
AdSelectionConfig adSelectionConfig = new AdSelectionConfig.Builder()
.setPerBuyerSignedContextualAds(signedContextualAds)
//Other fields for your config
.build();
Filtrado de anuncios de instalación de aplicaciones
El filtrado de anuncios de instalación de aplicaciones te ayuda a filtrar anuncios de instalación para apps que ya están instaladas en un dispositivo.
El primer paso de este proceso es definir qué anunciantes tienen la capacidad de filtrar en el paquete instalado. Esto debe ocurrir en la app a la que quieres segmentar con un anuncio.
Kotlin
//Create a request for setting the app install advertisers
val adtech = AdTechIdentifier.fromString("your.enrolled.uri")
val adtechSet = setOf(adtech)
val request = SetAppInstallAdvertisersRequest(adtechSet)
//Set the app install advertisers in the ad selection manager
mAdSelectionManager.setAppInstallAdvertisers(
request,
mExecutor,
object : OutcomeReceiver<Any?, Exception?>() {
fun onResult(@NonNull ignoredResult: Any?) {
Log.v("[your tag]", "Updated app install advertisers")
}
fun onError(@NonNull error: Exception?) {
Log.e("[your tag]", "Failed to update app install advertisers", error)
}
})
Java
//Create a request for setting the app install advertisers
AdTechIdentifier adtech = AdTechIdentifier.fromString("your.enrolled.uri");
Set<AdTechIdentifier> adtechSet = Collections.singleton(adtech);
SetAppInstallAdvertisersRequest request = new SetAppInstallAdvertisersRequest(adtechSet);
//Set the app install advertisers in the ad selection manager
mAdSelectionManager.setAppInstallAdvertisers(
request,
mExecutor,
new OutcomeReceiver<Object, Exception>() {
@Override
public void onResult(@NonNull Object ignoredResult) {
Log.v("[your tag]", "Updated app install advertisers");
}
@Override
public void onError(@NonNull Exception error) {
Log.e("[your tag]", "Failed to update app install advertisers", error);
}
});
Cuando se ejecuta el código anterior, los anunciantes que se pasan pueden filtrar las apps instaladas que especificas durante la generación de ofertas. Si necesitas quitar el acceso de un anunciante al estado de instalación de esta app, vuelve a ejecutar este código sin la información del anunciante.
El siguiente paso es configurar el filtrado de anuncios en la aplicación del publicador. La parte que publica el anuncio dentro de la app del publicador (lo más probable es que sea un SDK del proveedor) debe inicializar su objeto AdFilters
con información sobre qué anuncios están relacionados con la app que quiere filtrar:
Kotlin
// Instantiate AdFilters object with package names.
val filters: AdFilters = Builder().setAppInstallFilters(
Builder().setPackageNames(setOf("example.target.app")).build()
).build()
Java
// Instantiate AdFilters object with package names.
AdFilters filters = new AdFilters.Builder()
.setAppInstallFilters(
new AppInstallFilters.Builder()
.setPackageNames(Collections.singleton("example.target.app"))
.build())
.build();
Los publicadores orientados a la demanda también pueden establecer un AdFilter
para los anuncios que existen dentro de sus públicos personalizados.
También se puede pasar AdFilters
cuando se crea una instancia de un objeto AdData
nuevo:
Kotlin
// Instantiate an AdData object with the AdFilters created in the
// previous example.
val appInstallAd: AdData =
Builder().setMetadata("{ ... }") // Valid JSON string
.setRenderUri(Uri.parse("www.example-dsp1.com/.../campaign123.html"))
.setAdFilters(filters).build()
Java
// Instantiate an AdData object with the AdFilters created in the
// previous example.
AdData appInstallAd = new AdData.Builder()
.setMetadata("{ ... }") // Valid JSON string
.setRenderUri(Uri.parse("www.example-dsp1.com/.../campaign123.html"))
.setAdFilters(filters)
.build();
Filtrado de limitación de frecuencia
El filtrado de limitación de frecuencia permite que las tecnologías publicitarias limiten la cantidad de veces que se muestra un anuncio. Este filtrado reduce la sobreexposición del anuncio y optimiza la selección de anuncios alternativos para una campaña publicitaria determinada.
Un filtro de limitación de frecuencia tiene dos componentes principales: el tipo de evento de anuncio y la clave de contador de anuncios. Los tipos de eventos de anuncios disponibles que se pueden utilizar son los siguientes:
- Win: Un evento de ganancia indica que el anuncio ganó una subasta. La API de Protected Audience actualiza automáticamente los eventos de ganancia, y el desarrollador no puede llamarlos de forma directa. Solo los anuncios dentro de un público personalizado determinado pueden ver los datos de ganancias.
- Impresión: Independiente de
reportImpression
, un llamador integrado en el dispositivo (SSP o MMP) usaupdateAdCounterHistogram()
para invocar eventos de impresión en el punto del código que elige. Los eventos de impresión son visibles para todos los anuncios que pertenecen a una DSP determinada y no se limitan a los anuncios en el mismo público personalizado. - Vista: El llamador integrado en el dispositivo (SSP o MMP) invoca el evento en un punto del código que elige con una llamada a
updateAdCounterHistogram()
. Los eventos de vista son visibles para todos los anuncios que pertenecen a una DSP determinada y no se limitan a los anuncios del mismo público personalizado. - Clic: El llamador integrado en el dispositivo (SSP o MMP) invoca el evento en un punto del código que elige con una llamada a
updateAdCounterHistogram()
. Los eventos de clic son visibles para todos los anuncios que pertenecen a una DSP determinada y no se limitan a los anuncios del mismo público personalizado.
En la app del publicador, una SSP o MMP que tienen presencia en el dispositivo invocan eventos de anuncios. Cuando se llama a updateAdCounterHistogram()
, se incrementa el contador de un filtro de limitación de frecuencia para que las subastas futuras tengan información actualizada sobre la exposición de un usuario a un anuncio determinado. Los tipos de eventos de anuncios no están vinculados de manera forzosa a la acción del usuario correspondiente y son lineamientos que se proporcionan para ayudar a los llamadores a estructurar su sistema de eventos. Para aumentar los contadores de anuncios en el momento de un evento, el actor integrado en el dispositivo proporciona el ID de selección de anuncio de la subasta de anuncios ganadora.
Las claves de contador de anuncios son números enteros arbitrarios de 32 bits firmados que asigna la tecnología publicitaria de un comprador y corresponden a un conjunto determinado de anuncios, según lo define la DSP. Dado que las claves de contador de anuncios se limitan solo a anuncios que pertenecen a una DSP específica, se pueden seleccionar sin superponerse con histogramas de otra tecnología publicitaria. Las claves de contador de anuncios se usan para incrementar los identificadores específicos de la DSP en los anuncios de una DSP o en un público personalizado determinado para filtrar los anuncios de subastas futuras.
Las claves de contador se pueden aprovechar para priorizar los anuncios que es más probable que sean interesantes para un usuario determinado según sus interacciones con otros anuncios de la tecnología publicitaria de un comprador específico. Por ejemplo, un anuncio que recibió un alto nivel de participación por ganar subastas de anuncios, vistas y clics representa un dato inferido. A modo de ejemplo, un anuncio de palos de golf para zurdos podría indicar que el usuario no estaría interesado en los palos para diestros. Un filtro de limitación de frecuencia configurado para una clave de contador asignada a anuncios para zurdos podría filtrar los anuncios de palos para diestros.
Para utilizar la limitación de frecuencia en tu subasta, primero debes crear objetos KeyedFrequencyCap
, como se muestra a continuación:
Kotlin
// Value used when incrementing frequency counter
val adCounterKey = 123
// Frequency cap exceeded after 2 counts
val keyedFrequencyCapForImpression: KeyedFrequencyCap = Builder(
adCounterKey, 2, Duration.ofSeconds(10)
).build()
// Frequency cap exceeded after 1 counts
val keyedFrequencyCapForImpression: KeyedFrequencyCap = Builder(
adCounterKey, 1, Duration.ofSeconds(10)
).build()
Java
// Value used when incrementing frequency counter
int adCounterKey = 123;
// Frequency cap exceeded after 2 counts
KeyedFrequencyCap keyedFrequencyCapForImpression =
new KeyedFrequencyCap.Builder(
adCounterKey, 2, Duration.ofSeconds(10)
).build();
// Frequency Cap exceeded after 1 counts
KeyedFrequencyCap keyedFrequencyCapForClick =
new KeyedFrequencyCap.Builder(
adCounterKey, 1, Duration.ofSeconds(10)
).build();
Cuando se hayan creado los objetos KeyedFrequencyCap
, podrás pasarlos a un objeto AdFilters
.
Kotlin
val filters: AdFilters = Builder()
.setFrequencyCapFilters(
Builder()
.setKeyedFrequencyCapsForImpressionEvents(
ImmutableObject.of(keyedFrequencyCapForImpression)
)
.setKeyedFrequencyCapsForClickEvents(
ImmutableObject.of(keyedFrequencyCapForClick)
)
).build()
Java
AdFilters filters = new AdFilters.Builder()
.setFrequencyCapFilters(new FrequencyCapFilters.Builder()
.setKeyedFrequencyCapsForImpressionEvents(
ImmutableObject.of(keyedFrequencyCapForImpression)
)
.setKeyedFrequencyCapsForClickEvents(
ImmutableObject.of(keyedFrequencyCapForClick)
)
).build();
Cuando el objeto AdFilters
se completa con filtros de limitación de frecuencia, se puede pasar cuando se crea el público personalizado:
Kotlin
// Initialize a custom audience.
val audience: CustomAudience = Builder()
.setBuyer(buyer)
.setName(name)
.setAds(
listOf(
Builder()
.setRenderUri(renderUri)
.setMetadata(JSONObject().toString())
.setAdFilters(filters)
.setAdCounterKeys(adCounterKeys)
.build()
)
).build()
Java
// Initialize a custom audience.
CustomAudience audience = new CustomAudience.Builder()
.setBuyer(buyer)
.setName(name)
.setAds(Collections.singletonList(new AdData.Builder()
.setRenderUri(renderUri)
.setMetadata(new JSONObject().toString())
.setAdFilters(filters)
.setAdCounterKeys(adCounterKeys)
.build()))
.build();
Cuando los filtros de limitación de frecuencia se implementan en un público personalizado, la SSP puede invocar los eventos de clic, vista o impresión necesarios.
Kotlin
val callerAdTech: AdTechIdentifier = mAdSelectionConfig.getSeller()
val request: UpdateAdCounterHistogramRequest = Builder(
adSelectionId,
FrequencyCapFilters.AD_EVENT_TYPE_CLICK, //CLICK, VIEW, or IMPRESSION
callerAdTech
).build()
Java
AdTechIdentifier callerAdTech = mAdSelectionConfig.getSeller();
UpdateAdCounterHistogramRequest request =
new UpdateAdCounterHistogramRequest.Builder(
adSelectionId,
FrequencyCapFilters.AD_EVENT_TYPE_CLICK, //CLICK, VIEW, or IMPRESSION
callerAdTech
).build();
Los anuncios que alcanzaron los límites predeterminados del filtro de limitación de frecuencia se filtran fuera de la subasta. El filtrado se produce antes de que se ejecute la lógica de ofertas para las subastas integradas en el dispositivo y a medida que la carga útil se genera para las subastas de servicios de ofertas y subastas. Este kit de herramientas les brinda a las tecnologías publicitarias la flexibilidad para usar las interacciones entre los usuarios y los anuncios de sus públicos personalizados para enfocar la segmentación de anuncios y minimizar la sobreexposición.
Cómo crear firmas
Algoritmo de firma y generación de claves
Usa el algoritmo de ECDSA para firmar tus anuncios. El tipo de clave debe ser P-256 ECDSA (también conocido como "secp256r1" o "prime256v1"). Estos son algunos ejemplos de cómo acceder en varios idiomas:
Java
import java.security.*;
public class ECDSASignatureManager {
private static KeyPair generateKeyPair() throws Exception {
// Specify the curve name P-256
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1");
// Initialize the KeyPairGenerator
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(ecSpec);
// Generate the KeyPair
return keyPairGenerator.generateKeyPair();
}
public byte[] sign(byte[] data, byte[] privateKey) throws Exception {
Signature ecdsa = Signature.getInstance("SHA256withECDSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PrivateKey aPrivateKey = keyFactory.generatePrivate(keySpec);
ecdsa.initSign(aPrivateKey);
ecdsa.update(data);
return ecdsa.sign();
}
}
JavaScript
const crypto = require('crypto');
function generateKeyPair() {
const keyPair = crypto.generateKeyPairSync('ec', {
// Specifies ECDSA algorithm
namedCurve: 'prime256v1',
publicKeyEncoding: { type: 'spki', format: 'der' },
privateKeyEncoding: { type: 'pkcs8', format: 'der'}
});
return {
publicKey: keyPair.publicKey,
privateKey: keyPair.privateKey
};
}
function signContextualAds(data, privateKey) {
// Convert the private key from PKCS8 to PEM format
const base64PrivateKey = Buffer.from(privateKey).toString('base64');
const pemPrivateKey = `-----BEGIN PRIVATE KEY-----\n${base64PrivateKey}\n-----END PRIVATE KEY-----`;
// Create a Sign object using SHA256
const sign = crypto.createSign('SHA256');
sign.update(Buffer.from(data));
// Sign the data with ECDSA as specified in the key specs
return sign.sign(pemPrivateKey);
}
Python
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import ec
def sign_contextual_ads(data, private_key_der):
private_key = serialization.load_der_private_key(
private_key_der,
password=None,
backend=default_backend()
)
signature = private_key.sign(
data,
ec.ECDSA(hashes.SHA256())
)
return signature
def generate_key_pair():
private_key = ec.generate_private_key(ec.SECP256R1())
# Serialize the keys into DER format
public_key_der = private_key.public_key().public_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
private_key_der = private_key.private_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
)
return public_key_der, private_key_der
Serialización
Dado que las firmas se crearán en los servidores del comprador, se requiere un conjunto de reglas canónicas para mantener la serialización de un SignedContextualAds
determinado coherente en todos los sistemas.
Reglas canónicas
Un conjunto de reglas puede garantizar que la serialización sea coherente entre la tecnología publicitaria y Protected Audience. Estas reglas se encontrarán en la guía para desarrolladores junto con fragmentos de código en diferentes lenguajes para facilitar la adopción.
- Los objetos concatenan los valores serializados de sus campos con una "|". (barra vertical) después de cada campo. El último campo también tendrá una "|" para hacerlo más simple: "nombre_del_campo_1=valor1|nombre_del_campo_2=valor2|".
- Los campos de objetos se serializan con la concatenación del nombre del campo en minúsculas con guiones bajos, el signo igual y el valor del campo serializado "mi_campo=
|" . - Todos los campos se ordenan alfabéticamente por nombre de campo dentro del objeto.
- Los campos anulables (opcionales) se omiten (quedan vacíos) si son nulos o no están establecidos.
- Los dobles se convierten en cadenas que preservan la precisión de 2 dígitos después del punto decimal.
- Los números enteros se convierten en valores de cadena.
- Los conjuntos se ordenan alfabéticamente.
- Las listas mantienen el mismo orden, separadas por comas.
La cadena se codifica en byte[] con UTF-8.
Java
public class ContextualAdsSerializationUtil {
private static final String FIELD_SEPARATOR = "|";
private static final String ENUMERATOR_SEPARATOR = ",";
private final ByteArrayOutputStream mByteArrayStream;
public ContextualAdsSerializationUtil() {
this.mByteArrayStream = new ByteArrayOutputStream();
}
byte[] getBytes() {
return this.mByteArrayStream.toByteArray();
}
public byte[] serialize(ContextualAds ads) {
writeContextualAds(ads);
return getBytes();
}
private void writeContextualAds(ContextualAds ads) {
writeString("buyer=");
writeField(ads.getBuyer().getIdentifier(), this::writeString);
writeString("decision_logic_uri=");
writeField(ads.getDecisionLogicUri().toString(), this::writeString);
writeString("ads_with_bid=");
writeList(ads.getAdsWithBid(), this::writeAdWithBid);
}
private void writeAdWithBid(AdWithBid adWithBid) {
writeString("ad_data=");
writeField(adWithBid.getAdData(), this::writeAdData);
writeString("bid=");
writeField(adWithBid.getBid(), this::writeDouble);
}
private void writeAdData(AdData adData) {
writeString("ad_counter_keys=");
writeSet(adData.getAdCounterKeys(), this::writeInt);
if (!Objects.isNull(adData.getAdFilters())) {
writeString("ad_filters=");
writeField(adData.getAdFilters(), this::writeAdFilters);
}
if (!Objects.isNull(adData.getAdRenderId())) {
writeString("ad_render_id=");
writeField(adData.getAdRenderId(), this::writeString);
}
writeString("metadata=");
writeField(adData.getMetadata(), this::writeString);
writeString("render_uri=");
writeField(adData.getRenderUri().toString(), this::writeString);
}
private void writeAdFilters(AdFilters adFilters) {
if (!Objects.isNull(adFilters.getAppInstallFilters())) {
writeString("app_install_filters=");
writeField(adFilters.getAppInstallFilters(), this::writeAppInstallFilter);
}
if (!Objects.isNull(adFilters.getFrequencyCapFilters())) {
writeString("frequency_cap_filters=");
writeField(adFilters.getFrequencyCapFilters(), this::writeFrequencyCapFilters);
}
}
private void writeAppInstallFilter(AppInstallFilters appInstallFilters) {
writeString("package_names=");
writeSet(appInstallFilters.getPackageNames(), this::writeString);
}
private void writeFrequencyCapFilters(FrequencyCapFilters frequencyCapFilters) {
writeString("keyed_frequency_caps_for_click_events=");
writeList(
frequencyCapFilters.getKeyedFrequencyCapsForClickEvents(),
this::writeKeyedFrequencyCap);
writeString("keyed_frequency_caps_for_impression_events=");
writeList(
frequencyCapFilters.getKeyedFrequencyCapsForImpressionEvents(),
this::writeKeyedFrequencyCap);
writeString("keyed_frequency_caps_for_view_events=");
writeList(
frequencyCapFilters.getKeyedFrequencyCapsForViewEvents(),
this::writeKeyedFrequencyCap);
writeString("keyed_frequency_caps_for_win_events=");
writeList(
frequencyCapFilters.getKeyedFrequencyCapsForWinEvents(),
this::writeKeyedFrequencyCap);
}
private void writeKeyedFrequencyCap(KeyedFrequencyCap keyedFrequencyCap) {
writeString("ad_counter_key=");
writeField(keyedFrequencyCap.getAdCounterKey(), this::writeInt);
writeString("interval=");
writeField(keyedFrequencyCap.getInterval().toMillis(), this::writeLong);
writeString("max_count=");
writeField(keyedFrequencyCap.getMaxCount(), this::writeInt);
}
private <T> void writeField(T field, Consumer<T> writerConsumer) {
Objects.requireNonNull(field);
writerConsumer.accept(field);
writeString(FIELD_SEPARATOR);
}
private <T> void writeList(List<T> list, Consumer<T> writerConsumer) {
FirstElementStateHolder state = new FirstElementStateHolder();
for (T t : list) {
if (!state.isFirstThenSetFalse()) {
writeString(ENUMERATOR_SEPARATOR);
}
writerConsumer.accept(t);
}
writeString(FIELD_SEPARATOR);
}
private <T> void writeSet(Set<T> set, Consumer<T> writerConsumer) {
FirstElementStateHolder state = new FirstElementStateHolder();
set.stream()
.sorted()
.forEach(
(value) -> {
if (!state.isFirstThenSetFalse()) {
writeString(ENUMERATOR_SEPARATOR);
}
writerConsumer.accept(value);
});
writeString(FIELD_SEPARATOR);
}
void writeString(String value) {
mByteArrayStream.writeBytes(value.getBytes(StandardCharsets.UTF_8));
}
void writeLong(long value) {
writeString(Long.toString(value));
}
void writeDouble(double value) {
writeString(String.format("%.2f", value));
}
void writeInt(int value) {
writeString(Integer.toString(value));
}
private static class FirstElementStateHolder {
private boolean mIsFirst = true;
public boolean isFirstThenSetFalse() {
boolean initialValue = mIsFirst;
mIsFirst = false;
return initialValue;
}
}
}
JavaScript
class SignedContextualAdsHashUtil {
constructor() {
this.serializedString = '';
}
serialize(ads) {
this.writeContextualAds(ads);
return new TextEncoder().encode(this.serializedString);
}
writeContextualAds(ads) {
this.writeString('buyer=');
this.writeField(ads.buyer.identifier, value => this.writeString(value));
this.writeString('decision_logic_uri=');
this.writeField(ads.decisionLogicUri, value => this.writeString(value));
this.writeString('ads_with_bid=');
this.writeList(ads.adsWithBid, adWithBid => this.writeAdWithBid(adWithBid));
}
writeAdWithBid(adWithBid) {
this.writeString('ad_data=');
this.writeField(adWithBid.adData, adData => this.writeAdData(adData));
this.writeString('bid=');
this.writeField(adWithBid.bid, value => this.writeDouble(value));
}
writeAdData(adData) {
this.writeString('ad_counter_keys=');
this.writeSet([...adData.adCounterKeys], value => this.writeInt(value));
if (adData.adFilters) {
this.writeString('ad_filters=');
this.writeField(adData.adFilters, adFilters => this.writeAdFilters(adFilters));
}
if (adData.adRenderId) {
this.writeString('ad_render_id=');
this.writeField(adData.adRenderId, value => this.writeString(value));
}
this.writeString('metadata=');
this.writeField(adData.metadata, value => this.writeString(value));
this.writeString('render_uri=');
this.writeField(adData.renderUri, value => this.writeString(value));
}
writeAdFilters(adFilters) {
if (adFilters.appInstallFilters) {
this.writeString('app_install_filters=');
this.writeField(adFilters.appInstallFilters, appInstallFilters => this.writeAppInstallFilter(appInstallFilters));
}
if (adFilters.frequencyCapFilters) {
this.writeString('frequency_cap_filters=');
this.writeField(adFilters.frequencyCapFilters, frequencyCapFilters => this.writeFrequencyCapFilters(frequencyCapFilters));
}
}
writeAppInstallFilter(appInstallFilters) {
this.writeString('package_names=');
this.writeSet([...appInstallFilters.packageNames], value => this.writeString(value));
}
writeFrequencyCapFilters(frequencyCapFilters) {
this.writeString('keyed_frequency_caps_for_click_events=');
this.writeList(frequencyCapFilters.keyedFrequencyCapsForClickEvents, cap => this.writeKeyedFrequencyCap(cap));
this.writeString('keyed_frequency_caps_for_impression_events=');
this.writeList(frequencyCapFilters.keyedFrequencyCapsForImpressionEvents, cap => this.writeKeyedFrequencyCap(cap));
this.writeString('keyed_frequency_caps_for_view_events=');
this.writeList(frequencyCapFilters.keyedFrequencyCapsForViewEvents, cap => this.writeKeyedFrequencyCap(cap));
this.writeString('keyed_frequency_caps_for_win_events=');
this.writeList(frequencyCapFilters.keyedFrequencyCapsForWinEvents, cap => this.writeKeyedFrequencyCap(cap));
}
writeKeyedFrequencyCap(cap) {
this.writeString('ad_counter_key=');
this.writeField(cap.adCounterKey, value => this.writeInt(value));
this.writeString('interval=');
this.writeField(cap.interval, value => this.writeLong(value));
this.writeString('max_count=');
this.writeField(cap.maxCount, value => this.writeInt(value));
}
writeField(field, writer) {
writer(field);
this.writeString('|');
}
writeList(list, writer) {
list.forEach((item, index) => {
if (index > 0) this.writeString(',');
writer(item);
});
this.writeString('|');
}
writeSet(set, writer) {
[...set].sort().forEach((item, index) => {
if (index > 0) this.writeString(',');
writer(item);
});
this.writeString('|');
}
writeString(value) {
this.serializedString += value;
}
writeLong(value) {
this.writeString(value.toString());
}
writeDouble(value) {
this.writeString(value.toFixed(2));
}
writeInt(value) {
this.writeString(value.toString());
}
}
module.exports = {
SignedContextualAdsHashUtil,
};
Python
class SignedContextualAdsHashUtil:
def __init__(self):
self.serialized_string = ''
def serialize(self, ads):
self.write_contextual_ads(ads)
return self.serialized_string.encode('utf-8')
def write_contextual_ads(self, ads):
self.write_string('buyer=')
self.write_field(ads.buyer.identifier, lambda v: self.write_string(v))
self.write_string('decision_logic_uri=')
self.write_field(ads.decision_logic_uri, lambda v: self.write_string(v))
self.write_string('ads_with_bid=')
self.write_list(ads.ads_with_bid, self.write_ad_with_bid)
def write_ad_with_bid(self, ad_with_bid):
self.write_string('ad_data=')
self.write_field(ad_with_bid.ad_data, self.write_ad_data)
self.write_string('bid=')
self.write_field(ad_with_bid.bid, lambda v: self.write_double(v))
def write_ad_data(self, ad_data):
self.write_string('ad_counter_keys=')
self.write_set(ad_data.ad_counter_keys, lambda v: self.write_int(v))
if ad_data.ad_filters:
self.write_string('ad_filters=')
self.write_field(ad_data.ad_filters, self.write_ad_filters)
if ad_data.ad_render_id:
self.write_string('ad_render_id=')
self.write_field(ad_data.ad_render_id, lambda v: self.write_string(v))
self.write_string('metadata=')
self.write_field(ad_data.metadata, lambda v: self.write_string(v))
self.write_string('render_uri=')
self.write_field(ad_data.render_uri, lambda v: self.write_string(v))
def write_ad_filters(self, ad_filters):
if ad_filters.app_install_filters:
self.write_string('app_install_filters=')
self.write_field(ad_filters.app_install_filters,
self.write_app_install_filter)
if ad_filters.frequency_cap_filters:
self.write_string('frequency_cap_filters=')
self.write_field(ad_filters.frequency_cap_filters,
self.write_frequency_cap_filters)
def write_app_install_filter(self, app_install_filters):
self.write_string('package_names=')
self.write_set(app_install_filters.package_names,
lambda v: self.write_string(v))
def write_frequency_cap_filters(self, frequency_cap_filters):
for attr in ['keyed_frequency_caps_for_click_events',
'keyed_frequency_caps_for_impression_events',
'keyed_frequency_caps_for_view_events',
'keyed_frequency_caps_for_win_events']:
self.write_string(f'{attr}=')
self.write_list(getattr(frequency_cap_filters, attr),
self.write_keyed_frequency_cap)
def write_keyed_frequency_cap(self, cap):
self.write_string('ad_counter_key=')
self.write_field(cap.ad_counter_key, lambda v: self.write_int(v))
self.write_string('interval=')
self.write_field(cap.interval, lambda v: self.write_long(v))
self.write_string('max_count=')
self.write_field(cap.max_count, lambda v: self.write_int(v))
def write_field(self, field, writer):
writer(field)
self.write_string('|')
def write_list(self, list_items, writer):
for index, item in enumerate(list_items):
if index > 0:
self.write_string(',')
writer(item)
self.write_string('|')
def write_set(self, set_items, writer):
for index, item in enumerate(sorted(set_items)):
if index > 0:
self.write_string(',')
writer(item)
self.write_string('|')
def write_string(self, value):
self.serialized_string += value
def write_long(self, value):
self.write_string(str(value))
def write_double(self, value):
self.write_string(f'{value:.2f}')
def write_int(self, value):
self.write_string(str(value))
Ejemplos
Ejemplo 1: Objeto de anuncios contextuales con todos los campos. Dado el siguiente objeto de anuncios contextuales:
ContextualAds contextualAds = new ContextualAds.Builder()
.setBuyer(new AdTechIdentifier.Builder().setIdentifier("https://example.com").build()) // Replaced 'buyer' variable
.setDecisionLogicUri(URI.create("example.com/decisionLogic")) // Replaced 'decisionLogicUri'
.setAdsWithBid(
List.of(
new AdWithBid.Builder()
.setAdData(new AdData.Builder()
.setMetadata("metadata") // Replaced 'metadata'
.setAdFilters(buildAdFilters()) // Created a helper for filters
.setAdRenderId("987") // Replaced 'adRenderId'
.setAdCounterKeys(buildAdCounterKeys()) // Created a helper
.setRenderUri(URI.create("example.com/render")) // Replaced 'adRenderUri'
.build())
.setBid(5.10) // Replaced 'bid' (as double)
.build()))
.build();
// Helper function to build FrequencyCapFilters
private static FrequencyCapFilters buildAdFilters() {
KeyedFrequencyCap keyedFrequencyCap = new KeyedFrequencyCap.Builder()
.setAdCounterKey(42) // Replaced 'adCounterKey'
.setMaxCount(43) // Replaced 'maxCount'
.setInterval(Duration.ofDays(1)) // Replaced 'oneDay'
.build();
return new FrequencyCapFilters.Builder()
// ... set all KeyedFrequencyCaps using keyedFrequencyCap ...
.build();
}
// Helper function to convert adCounterKeys string
private static Set<Integer> buildAdCounterKeys() {
return Arrays.stream("1,2,3".split(",")) // Replaced 'adCounterKeys'
.map(Integer::valueOf)
.collect(Collectors.toSet());
}
La representación de cadena del byte[] serializado debería ser la siguiente:
"buyer=https://example.com|decision_logic_uri=example.com/decisionLogic|ads_with_bid=ad_data=ad_counter_keys=1,2,3|ad_filters=app_install_filters=package_names=com.awesome.app1,com.awesome.app2||frequency_cap_filters=keyed_frequency_caps_for_click_events=ad_counter_key=42|interval=86400000|max_count=43||keyed_frequency_caps_for_impression_events=ad_counter_key=42|interval=86400000|max_count=43||keyed_frequency_caps_for_view_events=ad_counter_key=42|interval=86400000|max_count=43||keyed_frequency_caps_for_win_events=ad_counter_key=42|interval=86400000|max_count=43||||ad_render_id=987|metadata=metadata|render_uri=example.com/render||bid=5.10||"
Ejemplo 2: Objeto de anuncios contextuales con campos vacíos. En el siguiente objeto, "adFilters" y "adCounterKeys" están vacíos, y cada uno es "anulable" y "no nulo", respectivamente.
ContextualAds contextualAds = new ContextualAds.Builder()
.setBuyer(new AdTechIdentifier.Builder().setIdentifier("https://example.com").build())
.setDecisionLogicUri(URI.create("example.com/decisionLogic"))
.setAdsWithBid(
List.of(
new AdWithBid.Builder()
.setAdData(new AdData.Builder()
.setMetadata("metadata")
.setAdRenderId("987")
.setRenderUri(URI.create("example.com/render"))
.build())
.setBid(5.10)
.build()))
.build();
Como se ve en la siguiente cadena serializada, si un campo anulable se configura como nulo (o si no se lo establece), se omite de la serialización. Pero si no se configura un campo como no nulo, este se incluye en la serialización con una cadena vacía como valor.
"buyer=https://example.com|decision_logic_uri=example.com/decisionLogic|ads_with_bid=ad_data=ad_counter_keys=|ad_render_id=987|metadata=metadata|render_uri=example.com/render||bid=5.10||"
Filtrado de anuncios contextuales sin llamadas de red
Si no hay demanda de remarketing en el dispositivo, puedes ejecutar la selección de anuncios para anuncios contextuales sin llamadas de red. Con los URI precompilados y una lista de anuncios contextuales con ofertas, la plataforma puede omitir la recuperación de la lógica de ofertas, los indicadores de ofertas y los indicadores de puntuación. La plataforma usa un URI precompilado para seleccionar el anuncio contextual con la oferta más alta.
Para mejorar la latencia, las tecnologías publicitarias pueden ejecutar un flujo de selección de anuncios que solo incluya anuncios contextuales con funcionalidad de filtrado de anuncios sin llamadas de red. Esto se logra usando URIs precompilados para los indicadores de puntuación. Consulta la sección de casos de uso y nombres de URI precompilados compatibles para obtener una lista de implementaciones de scoreAds
.
Para ejecutar la selección de anuncios sin llamadas de red, haz lo siguiente:
- Configura el filtrado de anuncios.
- Crea anuncios contextuales.
Crea un objeto
AdSelectionConfig
con lo siguiente:- Una lista vacía de compradores
- Un URI precompilado para seleccionar la oferta más alta
- Anuncios contextuales
- Un URI vacío para los indicadores de puntuación. Este tiene permitido indicar que no deseas usar la recuperación de indicadores de confianza para la puntuación:
Uri prebuiltURIScoringUri = Uri.parse("ad-selection-prebuilt://ad-selection/highest-bid-wins/?reportingUrl=your.registered.uri/reporting"); // Initialize AdSelectionConfig AdSelectionConfig adSelectionConfig = new AdSelectionConfig.Builder() .setSeller(seller) .setDecisionLogicUri(prebuiltURIScoringUri) .setCustomAudienceBuyers(Collections.emptyList()) .setAdSelectionSignals(adSelectionSignals) .setSellerSignals(sellerSignals) .setPerBuyerSignals(perBuyerSignals) .setBuyerContextualAds(buyerContextualAds) .setTrustedScoringSignalsUri(Uri.EMPTY) .build();
Ejecuta la selección de anuncios:
adSelectionManager.selectAds( adSelectionConfig, executor, outcomeReceiver);
Ejecuta tus propios informes de JavaScript mientras usas URIs precompilados
Actualmente, la plataforma de Privacy Sandbox solo tiene una implementación básica de informes de JavaScript disponible para los URIs precompilados. Si deseas ejecutar tu propio código de informes de JavaScript y, al mismo tiempo, usar los URI precompilados para obtener una selección de anuncios de baja latencia, puedes anular el DecisionLogicUri
entre la selección de anuncios y las ejecuciones de informes.
- Ejecuta los pasos para ejecutar la selección de anuncios contextuales con URIs precompilados.
Crea una copia de
AdSelectionConfig
antes de ejecutar el informeadSelectionConfigWithYourReportingJS = adSelectionConfig.cloneToBuilder() // Replace <urlToFetchYourReportingJS> with your own URL: .setDecisionLogicUri(Uri.parse(<urlToFetchYourReportingJS>)) .build();
Ejecuta informes de impresiones
// adSelectionId is from the result of the previous selectAds run ReportImpressionRequest request = new ReportImpressionRequest( adSelectionId, adSelectionConfigWithYourReportingJS); adSelectionManager.reportImpression( request, executor, outcomeReceiver);
Cómo ejecutar la mediación en cascada
La mediación en cascada requiere que varios SDKs de terceros (redes de terceros) estén organizados por una red de mediación de SDK propia. La mediación en cascada se realiza de la misma manera, independientemente de si la subasta se realizó en el dispositivo o en los servicios de ofertas y subastas (B&A).
Redes de terceros
Las redes de terceros deben proporcionar un adaptador que permita a la red de mediación invocar los métodos necesarios para ejecutar una subasta:
- Ejecuta la selección de anuncios
- Informar impresiones
El siguiente es un ejemplo de un adaptador de red de mediación:
Kotlin
class NetworkAdaptor {
private val adSelectionManager : AdSelectionManager
init {
adSelectionManager = context.getSystemService(AdSelectionManager::class.java)
}
fun selectAds() {...}
fun reportImpressions() {...}
}
Java
class NetworkAdaptor {
AdSelectionManager adSelectionManager;
public NetworkAdaptor() {
AdSelectionManager adSelectionManager =
context.getSystemService(AdSelectionManager.class);
}
public void selectAds() {...}
public void reportImpressions() {...}
}
Cada SDK tiene sus propios administradores de servicios de selección de anuncios y clientes, así como su propia implementación de selectAds
y reportImpressions
. Los proveedores del SDK pueden consultar las secciones para ejecutar la selección de anuncios para subastas integradas en el dispositivo o la explicación de B&A para subastas de B&A. Sigue los pasos para informar impresiones de anuncios (siguiendo los informes de impresiones de SSP única para generar informes).
Red de mediación
Al igual que las redes de terceros, las redes de mediación necesitan implementaciones de selectAds
y reportImpression
. Consulta las secciones sobre cómo ejecutar la selección de anuncios y cómo informar impresiones de anuncios para obtener más información.
Las redes de mediación son responsables de ejecutar la cadena de mediación y ubicarse en ella. En la siguiente sección, se explica cómo configurar y ejecutar este proceso.
Recupera la cadena de mediación y las ofertas mínimas
La red de mediación es responsable de recuperar los anuncios contextuales propios, la cadena de mediación y las ofertas mínimas de las redes de terceros. Esto puede suceder en una solicitud para recuperar anuncios contextuales que ejecuta la red de mediación. La cadena de mediación determina cómo se realiza la iteración a través de las redes de terceros, y las ofertas mínimas se pueden pasar al proceso de subasta como adSelectionSignals
.
Ubicación de la red en la cadena de mediación
Un SDK de mediación puede ubicarse en la cadena de mediación según su eCPM en vivo de ofertas de anuncios propias. En la API de Protected Audience, las ofertas de anuncios son opacas. Un SDK de mediación debe usar AdSelectionFromOutcomesConfig
para poder comparar la oferta de un anuncio propia con la oferta mínima de la siguiente red de terceros en la cadena. Si la oferta propia es mayor que la oferta mínima, eso significa que el SDK de mediación se coloca frente a esa red de terceros.
Ejecuta la selección de anuncios
Para recuperar un candidato de anuncio propio, la red de mediación puede ejecutar una subasta integrada en el dispositivo a través de los pasos que se indican en la sección Cómo ejecutar la selección de anuncios. Esto genera un candidato de anuncio propio, una oferta y un AdSelectionId
que se usa en el proceso de mediación.
Cómo crear un elemento AdSelectionFromResultssConfig
Un AdSelectionFromOutcomesConfig
permite que la red de mediación pase una lista de AdSelectionIds
(resultados de subastas anteriores), indicadores de selección de anuncios y un URI para recuperar JavaScript que selecciona un anuncio de varios candidatos. La lista de AdSelectionIds junto con sus ofertas y los indicadores se pasan al código JavaScript, que puede mostrar uno de los AdSelectionIds
si supera la oferta mínima o ninguno si la cadena de mediación debe continuar.
Las redes de mediación crean una AdSelectionFromOutcomesConfig
con el AdSelectionId
propio de la sección anterior, y se tiene en cuenta la oferta mínima de la red de terceros. Se debe crear una AdSelectionFromOutcomesConfig
nueva para cada paso en la cadena de mediación.
Kotlin
fun runSelectOutcome(
adSelectionClient : AdSelectionClient,
outcome1p : AdSelectionOutcome,
network3p : NetworkAdapter) : ListenableFuture<AdSelectionOutcome?> {
val config = AdSelectionFromOutcomesConfig.Builder()
.setSeller(seller)
.setAdSelectionIds(listOf(outcome1p))
.setSelectionSignals({"bid_floor": bid_floor})
.setSelectionLogicUri(selectionLogicUri)
.build()
return adSelectionClient.selectAds(config)
}
Java
public ListenableFuture<AdSelectionOutcome> runSelectOutcome(AdSelectionOutcome outcome1p,
NetworkAdapter network3p) {
AdSelectionFromOutcomesConfig config = new AdSelectionFromOutcomesConfig.Builder()
.setSeller(seller)
.setAdSelectionIds(Collection.singletonList(outcome1p))
.setSelectionSignals({"bid_floor": bid_floor})
.setSelectionLogicUri(selectionLogicUri)
.build();
return adSelectionClient.selectAds(config){}
}
La anulación del método selectAds()
para la mediación en cascada requiere una entrada AdSelectionFromOutcomesConfig
, en la que debes especificar los siguientes parámetros obligatorios:
- Vendedor: Es el identificador de la red de publicidad del vendedor que inicia la selección de anuncios.
- AdSelectionIds: Es una lista singleton de una ejecución
selectAds()
anterior para un anuncio propio. - Indicadores de selección de anuncios: Es un objeto JSON, serializado como una cadena, que contiene indicadores que debe usar la lógica de ofertas del comprador. En este caso, incluye la oferta mínima recuperada para la red de terceros específica.
- URI de lógica de selección: Es una URL HTTPS que se consulta durante la selección de anuncios para recuperar el código JavaScript de la red de mediación para seleccionar un anuncio ganador. Consulta las firmas de las funciones necesarias en JavaScript. JavaScript debe mostrar el anuncio de terceros si la oferta es superior a la oferta mínima, o bien mostrar
null
. Esto le permite al SDK de mediación truncar la cadena de mediación cuando se encuentra un ganador.
Con AdSelectionOutcomesConfig
creada, llama al método selectAds()
de la red de terceros que se encuentra primero en la cadena.
Kotlin
val adSelectionManager = context.getSystemService(AdSelectionManager::class.java)
// Initialize AdSelectionFromOutcomesConfig
AdSelectionFromOutcomesConfig adSelectionFromOutcomesConfig =
AdSelectionFromOutcomesConfig.Builder()
.setSeller(seller)
.setAdSelectionIds(listof(outcome1p))
.setSelectionSignals({"bid_floor": bid_floor})
.setSelectionLogicUri(selectionLogicUri)
.setAdSelectionIds(outcomeIds)
.build()
// Run ad selection with AdSelectionConfig
adSelectionManager.selectAds(
adSelectionFromOutcomesConfig,
executor,
outcomeReceiver)
Java
AdSelectionManager adSelectionManager =
context.getSystemService(AdSelectionManager.class);
// Initialize AdSelectionFromOutcomesConfig
AdSelectionFromOutcomesConfig adSelectionFromOutcomesConfig =
new AdSelectionFromOutcomesConfig.Builder()
.setSeller(seller)
.setAdSelectionIds(Collection.singletonList(outcome1p))
.setSelectionSignals({"bid_floor": bid_floor})
.setSelectionLogicUri(selectionLogicUri)
.setAdSelectionIds(outcomeIds)
.build();
// Run ad selection with AdSelectionConfig
adSelectionManager.selectAds(
adSelectionFromOutcomesConfig,
executor,
outcomeReceiver);
Cómo organizar la mediación en cascada
A continuación, se muestra el orden de las operaciones para ejecutar durante el proceso de mediación.
- Ejecuta la selección de anuncios propios.
- Realiza la iteración en la cadena de mediación. Para cada red de terceros, haz lo siguiente:
- Compila
AdSelectionFromOutcomeConfig
, incluidos eloutcomeId
propio y la oferta mínima del SDK de terceros. - Llama a
selectAds()
con la configuración del paso anterior. - Si el resultado no está vacío, muestra el anuncio.
- Llama al método
selectAds()
del adaptador de red del SDK actual. Si el resultado no está vacío, muestra el anuncio.
- Compila
- Si no se encuentra un ganador en la cadena, muestra el anuncio propio.
Kotlin
fun runWaterfallMediation(mediationChain : List<NetworkAdapter>)
: Pair<AdSelectionOutcome, NetworkAdapter> {
val outcome1p = runAdSelection()
var outcome : AdSelectionOutcome
for(network3p in mediationChain) {
outcome = runSelectOutcome(outcome1p, network3p)
if (outcome1p.hasOutcome() && outcome.hasOutcome()) {
return Pair(outcome, this)
}
outcome = network3p.runAdSelection()
if(outcome.hasOutcome()) {
return Pair(outcome, network3p)
}
}
return Pair(outcome1p, this)
}
Java
class MediationNetwork {
AdSelectionManager adSelectionManager;
public MediationNetwork() {
AdSelectionManager adSelectionManager =
context.getSystemService(AdSelectionManager.class);
}
public void runAdSelection() {...}
public void reportImpressions() {...}
public Pair<AdSelectionOutcome, NetworkAdapter> runWaterfallMediation(
List<NetworkAdapter> mediationChain) {
AdSelectionOutcome outcome1p = runAdSelection();
AdSelectionOutcome outcome;
for(NetworkAdapter network3p: mediationChain) {
if (outcome1p.hasOutcome() &&
(outcome = runSelectOutcome(outcome1p, network3p)).hasOutcome()) {
return new Pair<>(outcome, this);
}
if((outcome = network3p.runAdSelection()).hasOutcome()) {
return new Pair<>(outcome, network3p);
}
}
return new Pair<>(outcome1p, this);
}
/* Runs comparison by creating an AdSelectionFromOutcomesConfig */
public AdSelectionOutcome runSelectOutcome(AdSelectionOutcome outcome1p,
NetworkAdapter network3p) { ... }
}
Cómo informar impresiones de anuncios
Existen dos flujos para informar una impresión de anuncios según cómo se ejecuta la subasta. Si tienes una sola SSP que ejecuta una subasta, sigue esta sección. Si quieres implementar la mediación en cascada, sigue los pasos que se encuentran en la sección de informes de impresiones de mediación en cascada.
Informe de impresiones de SSP única
Después de elegir un anuncio ganador del flujo de trabajo de selección de anuncios, puedes informar la impresión a las plataformas participantes orientadas a la compra y a la venta con el método AdSelectionManager.reportImpression()
. Para informar una impresión de anuncios, haz lo siguiente:
- Inicializa un objeto
AdSelectionManager
. - Compila un objeto
ReportImpressionRequest
con el ID de selección de anuncios. - Llama al método asíncrono
reportImpression()
con el objetoReportImpressionRequest
y los objetosExecutor
yOutcomeReceiver
relevantes.
Java
AdSelectionManager adSelectionManager =
context.getSystemService(AdSelectionManager.class);
// Initialize a ReportImpressionRequest
ReportImpressionRequest reportImpressionRequest =
new ReportImpressionRequest.Builder()
.setAdSelectionId(adSelectionId)
.setAdSelectionConfig(adSelectionConfig)
.build();
// Request to report the impression with the ReportImpressionRequest
adSelectionManager.reportImpression(
reportImpressionRequest,
executor,
outcomeReceiver);
Kotlin
val adSelectionManager = context.getSystemService(AdSelectionManager::class.java)
// Initialize a ReportImpressionRequest
val adSelectionConfig: ReportImpressionRequest =
ReportImpressionRequest.Builder()
.setAdSelectionId(adSelectionId)
.setAdSelectionConfig(adSelectionConfig)
.build()
// Request to report the impression with the ReportImpressionRequest
adSelectionManager.reportImpression(
reportImpressionRequest,
executor,
outcomeReceiver)
Inicializa ReportImpressionRequest
con los siguientes parámetros obligatorios:
- ID de selección de anuncios: Es un ID único solo para el usuario de un dispositivo que identifica a una selección de anuncios correcta.
- Configuración de selección de anuncios: Es la misma configuración que se usa en la llamada
selectAds()
identificada con el ID de selección de anuncios proporcionado.
El método reportImpression()
asíncrono usa el objeto OutcomeReceiver
para indicar el resultado de la llamada a la API.
- La devolución de llamada
onResult()
indica si se crearon las URLs de informes de impresiones y si se programó la solicitud. - La devolución de llamada
onError()
indica las siguientes condiciones posibles:- Si se inicializa la llamada con un argumento de entrada no válido,
AdServicesException
indicaIllegalArgumentException
como la causa. - Todos los demás errores recibirán
AdServicesException
conIllegalStateException
como la causa.
- Si se inicializa la llamada con un argumento de entrada no válido,
Informes de impresiones de la mediación en cascada
Un SDK de mediación debe realizar un seguimiento del SDK ganador para activar sus flujos de informes. Los SDKs que participan en una cadena de mediación deben proporcionar un método que invoque el mediador para activar su propio flujo de informes. Un SDK que participa en una subasta mediada puede seguir los pasos anteriores para implementar sus propios informes.
Las SSPs pueden usar este ejemplo de código del SDK de terceros como prototipo para aprender a unirse a los flujos de mediación:
Pair<AdSelectionOutcome, NetworkAdapter> winnerOutcomeAndNetwork =
mediationSdk.orchestrateMediation(mediationChain);
if (winner.first.hasOutcome()) {
winner.second.reportImpressions(winner.first.getAdSelectionId());
Extremos de informes de impresiones
La API de Report Impression emitirá solicitudes GET HTTPS a los extremos que proporciona la plataforma orientada a la venta y la plataforma ganadora orientada a la compra:
Extremo de la plataforma orientada a la compra:
- La API usa la URL de lógica de ofertas especificada en el público personalizado para recuperar el JavaScript que brinda el comprador y que incluye lógica para mostrar una URL de informe de impresiones.
- Invoca la función de JavaScript
reportWin()
, que se espera que muestre la URL del informe de impresiones del comprador.
Extremo de la plataforma orientada a la venta:
- Usa la URL de lógica de decisión que se especifica en el objeto
AdSelectionConfig
para recuperar la lógica de decisión de JavaScript del vendedor. - Invoca la función de JavaScript
reportResult()
, que se espera que muestre la URL del informe de impresiones del comprador.
Informes de servicios de ofertas y subastas
Una subasta ejecutada en servicios de ofertas y subastas tendrá toda la información de informes necesaria, incluidas las URLs generadas para los informes de interacción con anuncios, que se incluyen en la respuesta encriptada de la subasta del servidor. Cuando se desencripta la respuesta, se registran las URLs adecuadas en la plataforma, por lo que los informes de impresiones y anuncios siguen los mismos pasos mencionados previamente.
La mejor manera de completar informes de impresiones
El método reportImpression()
está diseñado para ofrecer la mejor manera de completar los informes.
Cómo informar interacciones con los anuncios
Protected Audience ofrece compatibilidad con el informe sobre interacciones más detalladas para un anuncio renderizado. Esto puede incluir interacciones como el tiempo de vista, los clics, los desplazamientos del cursor sobre algún elemento o cualquier otra métrica útil que se pueda recopilar. El proceso para recibir estos informes requiere dos pasos. En primer lugar, los compradores y vendedores deben registrarse para recibir estos informes en su JavaScript de informes. Luego, el cliente debe informar estos eventos.
Cómo registrarse para recibir eventos de interacción
El registro para eventos de interacción ocurre en las funciones de JavaScript reportWin()
del comprador y reportResult()
del vendedor a través de una función de JavaScript proporcionada por la plataforma: registerAdBeacon
. Si quieres registrarte para recibir un informe de eventos, solo debes llamar a la función de JavaScript de la plataforma desde tu JavaScript de informes. El siguiente fragmento usa la función reportWin()
del comprador, pero el mismo enfoque se aplica a reportResult()
.
reportWin(
adSelectionSignals,
perBuyerSignals,
signalsForBuyer,
contextualSignals,
customAudienceSignals) {
...
// Calculate reportingUri, clickUri, viewUri, and hoverUri
registerAdBeacon("click", clickUri)
registerAdBeacon("view", viewUri)
registerAdBeacon("hover", hoverUri)
return reportingUrl;
}
Cómo informar eventos de interacción
Después de informar una impresión, los clientes pueden informar las interacciones a las plataformas ganadoras orientadas a la compra y a la venta previamente registradas con el método AdSelectionManager.reportInteraction()
. Para informar un evento de anuncio, haz lo siguiente:
- Inicializa un objeto
AdSelectionManager
. - Compila un objeto
ReportInteractionRequest
con el ID de selección de anuncios, la clave de interacción, los datos de interacción y el destino de los informes. - Llama al método asíncrono
reportInteraction()
con el objetorequest
y los objetosExecutor
yOutcomeReceiver
relevantes.
AdSelectionManager adSelectionManager =
context.getSystemService(AdSelectionManager.class);
// Initialize a ReportInteractionRequest
ReportInteractionRequest request =
new ReportInteractionRequest.Builder()
.setAdSelectionId(adSelectionId)
.setInteractionKey("view")
.setInteractionData("{ viewTimeInSeconds : 1 }") // Can be any string
.setReportingDestinations(
FLAG_REPORTING_DESTINATION_BUYER | FLAG_REPORTING_DESTINATION_SELLER
)
.build();
// Request to report the impression with the ReportImpressionRequest
adSelectionManager.reportInteraction(
reportImpressionRequest,
executor,
outcomeReceiver);
Inicializa ReportInteractionRequest
con los siguientes parámetros obligatorios:
- ID de selección de anuncios: Es un ID de selección de anuncios recuperado de un
AdSelectionOutcome
que se mostró antes. - Clave de interacción: Es una clave de cadena que define el cliente y que describe la acción que se informa. Debe coincidir con la clave que registró el vendedor o el comprador en las funciones de JavaScript de informes.
- Datos de interacción: Es una cadena que contiene datos que se incluirán en el informe del evento para enviar en solicitudes POST a los servidores de informes.
- Destinos de informes: Es una máscara binaria que especifica si se deben informar los eventos al comprador, al vendedor o a ambos. La plataforma proporciona estas marcas, y la máscara de destino final se puede crear con operaciones a nivel de bits. Para informar a un destino, puedes usar la marca que proporciona la plataforma directamente. Para informar a varios destinos, puedes usar el OR a nivel de bits (
|
) para combinar los valores de las marcas.
El método reportInteraction()
asíncrono usa el objeto OutcomeReceiver
para indicar el resultado de la llamada a la API.
- La devolución de llamada
onResult()
indica que la llamada de interacción de informes es válida. - La devolución de llamada
onError()
indica las siguientes condiciones posibles:- Si se realiza la llamada cuando la app se ejecuta en segundo plano, se muestra una
IllegalStateException
con una descripción de la falla. - Si el cliente no puede llamar a
reportInteraction()
, se muestra unaLimitExceededException
. - Si el paquete no está inscrito para llamar a las APIs de preservación de la privacidad, se muestra una
SecurityException()
. - Si las interacciones de los informes de la app son diferentes de las de la app que llamó a
selectAds()
, se muestra unaIllegalStateException
.
- Si se realiza la llamada cuando la app se ejecuta en segundo plano, se muestra una
- Si el usuario no dio su consentimiento para habilitar las APIs de Privacy Sandbox, la llamada fallará de manera silenciosa.
Extremos de informes de interacciones
La API de interacción de informes emite solicitudes HTTPS POST a los extremos que proporciona la plataforma orientada a la venta y la plataforma ganadora orientada a la compra. Protected Audience hará coincidir las claves de interacción con los URI declarados en el JavaScript de informes y emitirá una solicitud POST a cada extremo para cada interacción que se informe. El tipo de contenido de la solicitud es texto sin formato, y el cuerpo contiene los datos de interacción.
La mejor manera de completar informes de interacción
El objetivo de reportInteraction()
es ofrecer la mejor manera de completar los informes a través de HTTP POST.
Actualización diaria en segundo plano
Cuando creas un público personalizado, tu app o SDK pueden inicializar metadatos personalizados. Además, la plataforma puede actualizar los siguientes metadatos personalizados del público con un proceso diario de actualización en segundo plano.
- Indicadores de ofertas del usuario
- Datos de ofertas de confianza
- Lista
AdData
Este proceso consulta la URL de actualización diaria definida en el público personalizado y es posible que la URL muestre una respuesta JSON.
- La respuesta JSON puede contener cualquiera de los campos de metadatos admitidos que deben actualizarse.
- Cada campo JSON se valida de forma independiente. El cliente ignora los campos con formato incorrecto que no generen actualizaciones para ese campo en particular en la respuesta.
- Una respuesta HTTP vacía o un objeto JSON vacío "
{}
" no generan actualizaciones de metadatos. - El tamaño del mensaje de respuesta debe limitarse a 10 KB.
- Todos los URIs son obligatorios para usar HTTPS.
trusted_bidding_uri
debe compartir el mismo ETLD+1 que el comprador.
Ejemplo: Respuesta JSON para una actualización diaria en segundo plano
{
"user_bidding_signals" : { ... }, // Valid JSON object
"trusted_bidding_data" : {
"trusted_bidding_uri" : 'example-dsp1-key-value-service.com',
"trusted_bidding_keys" : [ 'campaign123', 'campaign456', ... ]
},
'ads' : [
{
"render_uri" : 'www.example-dsp1.com/.../campaign123.html',
'metadata' : { ... } // Valid JSON object
},
{
"render_uri" : 'www.example-dsp1.com/.../campaign456.html',
'metadata' : { ... } // Valid JSON object
},
...
]
}
JavaScript para la selección de anuncios
El flujo de trabajo de la selección de anuncios organiza la ejecución de JavaScript que brinda el comprador y el vendedor.
El JavaScript que brinda el comprador se recupera de la URL de lógica de ofertas que se especifica en el público personalizado. El JavaScript que se muestra debe incluir las siguientes funciones:
El JavaScript que brinda el vendedor se recupera de la URL de lógica de decisión que se especifica en el parámetro AdSelectionConfig
para la API de Ad Selection. El JavaScript que se muestra debe incluir las siguientes funciones:
generateBid()
function generateBid(
ad,
auction_signals,
per_buyer_signals,
trusted_bidding_signals,
contextual_signals,
user_signals,
custom_audience_bidding_signals) {
return {'status': 0, 'ad': ad, 'bid': ad.metadata.result };
}
Parámetros de entrada:
ad
: Es un objeto JSON con el formatovar ad = { 'render_url': url, 'metadata': json_metadata };
.auction_signals, per_buyer_signals
: Son objetos JSON especificados en el objeto de configuración de la subasta.custom_audience_bidding_signals
: Es un objeto JSON que genera la plataforma. El formato de este objeto JSON es el siguiente:var custom_audience_signals = { "owner":"ca_owner", "buyer":"ca_buyer", "name":"ca_name", "activation_time":"ca_activation_time_epoch_ms", "expiration_time":"ca_expiration_time_epoch_ms", "user_bidding_signals":"ca_user_bidding_signals" }
donde:
owner
,buyer
yname
son cadenas que se toman de las propiedades con el mismo nombre del público personalizado que participa en la selección de anuncios.activation_time
yexpiration_time
son el tiempo de activación y vencimiento del público personalizado, que se expresa como segundos desde el tiempo Unix.ca_user_bidding_signals
es una cadena JSON que se especifica en el campouserBiddingSignals
deCustomAudience
cuando se crea.trusted_bidding_signals, contextual_signals
yuser_signals
son objetos JSON. Se pasan como objetos vacíos y se completarán en versiones futuras. Su formato no se aplica de manera forzosa por la plataforma y es administrado por la tecnología publicitaria.
Resultado:
ad
: el anuncio al que hace referencia la oferta. La secuencia de comandos puede mostrar una copia del anuncio que recibió con diferentes metadatos. Se espera que no cambie la propiedadrender_url
del anunciobid
: un valor flotante que representa el valor de la oferta para este anunciostatus
: Un valor entero que puede ser uno de los siguientes:0
: Para una ejecución correcta1
(o cualquier valor distinto de cero): En caso de que alguno de los indicadores de entrada no sea válido (si generate-bid muestra un valor distinto de cero, el proceso de oferta se invalida para todos los anuncios de PP).
scoreAd()
function scoreAd(
ad,
bid,
ad_selection_config,
seller_signals,
trusted_scoring_signals,
contextual_signal,
user_signal,
custom_audience_signal) {
return {'status': 0, 'score': score };
}
Parámetros de entrada:
ad
: consulta la documentación degenerateBid
.bid
: el valor de la oferta para el anuncio.ad_selection_config
: un objeto JSON que representa el parámetroAdSelectionConfig
de la API deselectAds
. El formato es el siguiente:var ad_selection_config = { 'seller': 'seller', 'decision_logic_url': 'url_of_decision_logic', 'custom_audience_buyers': ['buyer1', 'buyer2'], 'auction_signals': auction_signals, 'per_buyer_signals': per_buyer_signals, 'contextual_ads': [ad1, ad2] }
seller_signals
: Son objetos JSON que se leen del parámetro de la API desellerSignals
AdSelectionConfig
.trusted_scoring_signal
: Lee del campoadSelectionSignals
en el parámetro de la API deAdSelectionConfig
.contextual_signals, user_signals
: objetos JSON. En la actualidad, se pasan como objetos vacíos y se completarán en versiones futuras. Su formato no se aplica de manera forzosa por la plataforma y es administrado por la tecnología publicitaria.per_buyer_signals
: Es un objeto JSON que se lee del mapaperBuyerSignal
en el parámetro de la API deAdSelectionConfig
usando como clave el comprador actual del público personalizado. Estará vacío si el mapa no contiene ninguna entrada para el comprador determinado.
Resultado:
score
: un valor flotante que representa el valor de puntuación para este anunciostatus
: un valor entero que puede ser uno de los siguientes:- 0: para una ejecución correcta
- 1: en caso de que
customAudienceSignals
no sea válido - 2: en caso de que
AdSelectionConfig
no sea válido - 3: en caso de que alguno de los otros indicadores no sea válido
- Cualquier valor distinto de cero causa la falla del proceso; el valor determina el tipo de excepción que se arroja.
selectOutcome()
function selectOutcome(
outcomes,
selection_signals) {
return {'status': 0, 'result': null};
}
Parámetros de entrada:
outcomes
: Un objeto JSON{"id": id_string, "bid": bid_double}
selection_signals
: Objetos JSON especificados en el objeto de configuración de la subasta
Resultado:
status
:0
para la ejecución correcta y un valor distinto de cero para las fallasresult
: Uno de los resultados pasados o nulos
reportResult()
function reportResult(ad_selection_config, render_url, bid, contextual_signals) {
return {
'status': status,
'results': {'signals_for_buyer': signals_for_buyer, 'reporting_url': reporting_url }
};
}
Parámetros de entrada:
ad_selection_config
: consulta la documentación descoreAds
render_url
: la URL de renderización del anuncio ganadorbid
: la oferta que se ofrece para el anuncio ganadorcontextual_signals
: consulta la documentación degenerateBid
Salida:
status: 0
para la ejecución correcta y un valor distinto de cero para las fallasresults
: Un objeto JSON que contiene lo siguiente:signals_for_buyer
: Un objeto JSON que se pasa a la funciónreportWin
reporting_url
: Una URL que usa la plataforma para notificar la impresión al comprador
reportWin()
function reportWin(
ad_selection_signals,
per_buyer_signals,
signals_for_buyer,
contextual_signals,
custom_audience_signals) {
return {'status': 0, 'results': {'reporting_url': reporting_url } };
}
Parámetros de entrada:
ad_selection_signals, per_buyer_signals
: Consulta la documentación sobrescoreAd
signals_for_buyer
: un objeto JSON que muestrareportResult
contextual_signals, custom_audience_signals
: consulta la documentación degenerateBid
Salida:
status: 0
para la ejecución correcta y un valor distinto de cero para las fallasresults
: Un objeto JSON que contiene lo siguiente:reporting_url
: Una URL que usa la plataforma para notificar la impresión al vendedor
registerAdBeacon()
function registerAdBeacon(
interaction_key,
reporting_uri
)
Parámetros de entrada:
interaction_key
: Es una cadena que representa el evento. La plataforma la usará más adelante cuando informe las interacciones de eventos para buscar elreporting_uri
que debe notificarse. Esta clave debe coincidir con lo que informa el vendedor y lo que registra el comprador o vendedor.reporting_uri
: Es un URI para recibir informes de eventos. Debe ser específico para el tipo de evento que se informa. Debe aceptar una solicitud POST para controlar cualquier dato informado junto con el evento.
URIs precompilados de selección de anuncios
Los URI precompilados permiten que las tecnologías publicitarias asignen funciones de JavaScript para la lógica de decisión de selección de anuncios en las clases AdSelectionConfig
y AdSelectionFromOutcomesConfig
. Los URIs precompilados no requieren llamadas de red para descargar el JavaScript correspondiente. Las tecnologías publicitarias pueden usar URIs precompilados sin tener que configurar un dominio inscrito para alojar JavaScript.
Un URI precompilado se construye con el siguiente formato:
ad-selection-prebuilt:<use-case>/<name>?<required-script-generation-parameters>
La plataforma de Privacy Sandbox proporciona JavaScript con la información de este URI en el entorno de ejecución.
Se arroja IllegalArgumentException
en los siguientes casos:
- Alguno de los parámetros obligatorios no está presente en el URI
- Hay parámetros no reconocidos en el URI
Casos de uso y nombres de URIs precompilados admitidos
Caso de uso 1: Selección de anuncios
Los URIs precompilados en el caso de uso de ad-selection
son compatibles con el flujo selectAds(AdSelectionConfig)
.
Nombre del URI precompilado: highest-bid-wins
Este URI precompilado proporciona un JavaScript que selecciona el anuncio con la oferta más alta después de la oferta. También proporciona una función de informes básica para informar el render_uri
y la bid
del ganador.
Parámetros obligatorios
reportingUrl
: Es la URL del informe base que se parametriza con el render_uri
y la bid
del anuncio ganador:
<reportingUrl>?render_uri=<renderUriOfWinnigAd>&bid=<bidOfWinningAd>
Uso
Si la URL de los informes base es https://www.ssp.com/reporting
, el URI precompilado sería el siguiente:
`ad-selection-prebuilt://ad-selection/highest-bid-wins/?reportingUrl=https://www.ssp.com/reporting`
Caso de uso 2: Selección de anuncios a partir de resultados
Los URI precompilados en el caso de uso de ad-selection-from-outcomes
admiten el flujo de trabajo selectAds(AdSelectionFromOutcomesConfig)
.
Nombre del URI precompilado: waterfall-mediation-truncation
El URI precompilado waterfall-mediation-truncation
proporciona JavaScript que implementa la lógica de truncamiento de la mediación en cascada en la que JavaScript muestra un anuncio propio si la bid
es mayor o igual que el bid floor
, y muestra null
de no ser así.
Parámetros obligatorios
bidFloor
: Es la clave del valor mínimo de la oferta que se pasa en la getSelectionSignals()
que se compara con el anuncio del SDK de mediación.
Uso
Si los indicadores de selección de anuncios se ven como {"bid_floor": 10}
, el URI precompilado sería el siguiente:
`ad-selection-prebuilt://ad-selection-from-outcomes/waterfall-mediation-truncation/?bidFloor=bid_floor`
Pruebas
Para ayudarte a comenzar con la API de Protected Audience, creamos apps de ejemplo en Kotlin y Java, que se encuentran en GitHub.
Requisitos previos
La API de Protected Audience requiere JavaScript durante la selección de anuncios y los informes de impresiones. Hay dos métodos para proporcionar este JavaScript en un entorno de pruebas:
- Ejecuta un servidor con los extremos HTTPS requeridos que muestra el código JavaScript.
- Para anular la recuperación remota, proporciona el código necesario de una fuente local.
Cualquiera de los dos métodos requiere la configuración de un extremo HTTPS para administrar los informes de impresiones.
Extremos HTTPS
Para probar la selección de anuncios y los informes de impresiones, deberás configurar 7 extremos HTTPS a los que puede acceder tu dispositivo de prueba o emulador:
- Extremo del comprador que publica la lógica de ofertas de JavaScript
- Un extremo que publica los indicadores de ofertas
- Extremo del vendedor que publica la lógica de decisión de JavaScript
- Un extremo que muestra indicadores de puntuación
- Extremo de los informes de impresiones del comprador que ganó
- Extremo de los informes de impresiones del vendedor
- Un extremo que publica las actualizaciones diarias de un público personalizado
Para mayor comodidad, el repositorio de GitHub brinda código básico de JavaScript con fines de prueba. También incluye definiciones del servicio de OpenAPI, que se pueden implementar en una plataforma simulada o de microservicios compatible. Para obtener más detalles, consulta el archivo readme del proyecto.
Cómo anular la recuperación remota de JavaScript
Esta función está diseñada para usarse en pruebas de extremo a extremo. Para anular la recuperación remota, tu app debe ejecutarse en modo de depuración con las opciones para desarrolladores habilitadas.
Para habilitar el modo de depuración en tu aplicación, agrega la siguiente línea al atributo de la aplicación en tu AndroidManifest.xml:
<application
android:debuggable="true">
Para ver un ejemplo de cómo usar estas anulaciones, consulta la app de ejemplo de la API de Protected Audience en GitHub.
Debes agregar tu propio JavaScript personalizado para controlar las rutinas de selección de anuncios, como las ofertas, las decisiones de puntuación y los informes. Puedes encontrar ejemplos básicos de código JavaScript que manejan todas las solicitudes necesarias en el repositorio de GitHub. La aplicación de ejemplo de la API de Protected Audience demuestra cómo leer el código de ese archivo y prepararlo para usarlo como anulación.
Es posible anular de forma independiente la recuperación de JavaScript orientada a la compra y la venta, aunque necesitarás un extremo HTTPS para publicar cualquier JavaScript para el que no brindes anulaciones. Consulta el archivo README para obtener información sobre cómo configurar un servidor que controle estos casos.
Solo tu paquete puede anular la recuperación de JavaScript para públicos personalizados de tu propiedad.
Cómo anular JavaScript orientado a la venta
Para configurar una anulación de JavaScript orientado a la venta, haz lo siguiente como se muestra en el siguiente ejemplo de código:
- Inicializa un objeto
AdSelectionManager
. - Obtén una referencia a
TestAdSelectionManager
desde el objetoAdSelectionManager
. - Compila un objeto
AdSelectionConfig
. - Compila una
AddAdSelectionOverrideRequest
con el objetoAdSelectionConfig
y unaString
que represente el JavaScript que quieres usar como anulación. - Llama al método asíncrono
overrideAdSelectionConfigRemoteInfo()
con el objetoAddAdSelectionOverrideRequest
y los objetosExecutor
yOutcomeReceiver
relevantes.
Kotlin
val testAdSelectionManager: TestAdSelectionManager =
context.getSystemService(AdSelectionManager::class.java).getTestAdSelectionManager()
// Initialize AdSelectionConfig =
val adSelectionConfig = new AdSelectionConfig.Builder()
.setSeller(seller)
.setDecisionLogicUrl(decisionLogicUrl)
.setCustomAudienceBuyers(customAudienceBuyers)
.setAdSelectionSignals(adSelectionSignals)
.setSellerSignals(sellerSignals)
.setPerBuyerSignals(perBuyerSignals)
.build()
// Initialize AddAddSelectionOverrideRequest
val request = AddAdSelectionOverrideRequest.Builder()
.setAdSelectionConfig(adSelectionConfig)
.setDecisionLogicJs(decisionLogicJS)
.build()
// Run the call to override the JavaScript for the given AdSelectionConfig
// Note that this only takes effect in apps marked as debuggable
testAdSelectionManager.overrideAdSelectionConfigRemoteInfo(
request,
executor,
outComeReceiver)
Java
TestAdSelectionManager testAdSelectionManager =
context.getSystemService(AdSelectionManager.class).getTestAdSelectionManager();
// Initialize AdSelectionConfig =
AdSelectionConfig adSelectionConfig = new AdSelectionConfig.Builder()
.setSeller(seller)
.setDecisionLogicUrl(decisionLogicUrl)
.setCustomAudienceBuyers(customAudienceBuyers)
.setAdSelectionSignals(adSelectionSignals)
.setSellerSignals(sellerSignals)
.setPerBuyerSignals(perBuyerSignals)
.build();
// Initialize AddAddSelectionOverrideRequest
AddAdSelectionOverrideRequest request = AddAdSelectionOverrideRequest.Builder()
.setAdSelectionConfig(adSelectionConfig)
.setDecisionLogicJs(decisionLogicJS)
.build();
// Run the call to override the JavaScript for the given AdSelectionConfig
// Note that this only takes effect in apps marked as debuggable
testAdSelectionManager.overrideAdSelectionConfigRemoteInfo(
request,
executor,
outComeReceiver);
Consulta la sección Ejecuta la selección de anuncios para obtener más información sobre lo que representa cada uno de los campos en AdSelectionConfig
. La diferencia clave es que decisionLogicUrl se puede establecer como un valor de marcador de posición, ya que se ignorará.
Para anular el código JavaScript que se usa durante la selección de anuncios, decisionLogicJs
debe contener las firmas de funciones adecuadas del lado del vendedor.
Para ver un ejemplo de cómo leer un archivo JavaScript como una cadena, consulta la app de ejemplo de la API de Protected Audience en GitHub.
El método overrideAdSelectionConfigRemoteInfo()
asíncrono usa el objeto OutcomeReceiver
para indicar el resultado de la llamada a la API.
La devolución de llamada onResult()
significa que la anulación se aplicó correctamente.
Las llamadas futuras a selectAds()
usarán la lógica de decisión y de informe que hayas pasado como anulación.
La devolución de llamada onError()
indica dos condiciones posibles:
- Si se intenta realizar la anulación con argumentos no válidos,
AdServiceException
indicaráIllegalArgumentException
como la causa. - Si la anulación se intenta con una app que no se ejecuta en el modo de depuración con las opciones para desarrolladores habilitadas,
AdServiceException
indicaráIllegalStateException
como la causa.
Cómo restablecer anulaciones orientadas a la venta
En esta sección, se da por sentado que anulaste el código JavaScript orientado a la venta y que tienes una referencia a los elementos TestAdSelectionManager
y AdSelectionConfig
que se usaron en la sección anterior.
Para restablecer las anulaciones para todos los elementos AdSelectionConfigs
, sigue estos pasos:
- Llama al método
resetAllAdSelectionConfigRemoteOverrides()
asíncrono con el objetoOutcomeReceiver
relevante.
Kotlin
// Resets overrides for all AdSelectionConfigs
testAadSelectionManager.resetAllAdSelectionConfigRemoteOverrides(
outComeReceiver)
Java
// Resets overrides for all AdSelectionConfigs
testAdSelectionManager.resetAllAdSelectionConfigRemoteOverrides(
outComeReceiver);
Después de restablecer las anulaciones orientadas a la venta, las llamadas a selectAds()
usan cualquier decisionLogicUrl almacenada en AdSelectionConfig
para intentar recuperar el JavaScript necesario.
Si la llamada a resetAllAdSelectionConfigRemoteOverrides()
falla, la devolución de llamada OutComeReceiver.onError()
proporciona una AdServiceException
.
Si se intentan quitar las anulaciones con una app que no se ejecuta en el modo de depuración con las opciones para desarrolladores habilitadas, AdServiceException
indicará IllegalStateException
como la causa.
Cómo anular JavaScript orientado a la compra
- Sigue los pasos para unirte a un público personalizado.
- Compila una
AddCustomAudienceOverrideRequest
con el comprador y nombre del público personalizado que deseas anular, además de la lógica de ofertas y los datos que deseas usar como anulación. - Llama al método asíncrono
overrideCustomAudienceRemoteInfo()
con el objetoAddCustomAudienceOverrideRequest
y los objetosExecutor
yOutcomeReceiver
relevantes.
Kotlin
val testCustomAudienceManager: TestCustomAudienceManager =
context.getSystemService(CustomAudienceManager::class.java).getTestCustomAudienceManager()
// Join custom audience
// Build the AddCustomAudienceOverrideRequest
val request = AddCustomAudienceOverrideRequest.Builder()
.setBuyer(buyer)
.setName(name)
.setBiddingLogicJs(biddingLogicJS)
.setTrustedBiddingSignals(trustedBiddingSignals)
.build()
// Run the call to override JavaScript for the given custom audience
testCustomAudienceManager.overrideCustomAudienceRemoteInfo(
request,
executor,
outComeReceiver)
Java
TestCustomAudienceManager testCustomAudienceManager =
context.getSystemService(CustomAudienceManager.class).getTestCustomAudienceManager();
// Join custom audience
// Build the AddCustomAudienceOverrideRequest
AddCustomAudienceOverrideRequest request =
AddCustomAudienceOverrideRequest.Builder()
.setBuyer(buyer)
.setName(name)
.setBiddingLogicJs(biddingLogicJS)
.setTrustedBiddingSignals(trustedBiddingSignals)
.build();
// Run the call to override JavaScript for the given custom audience
testCustomAudienceManager.overrideCustomAudienceRemoteInfo(
request,
executor,
outComeReceiver);
Los valores para comprador y nombre son los mismos que se usan para crear el público personalizado. Más información sobre estos campos.
También puedes especificar dos parámetros adicionales:
biddingLogicJs
: JavaScript que contiene la lógica del comprador que se usa durante la selección de anuncios. Consulta las firmas de las funciones necesarias en JavaScript.trustedBiddingSignals
: Indicadores de ofertas que se usarán durante la selección de anuncios. Para fines de prueba, puede ser una cadena vacía.
El método overrideCustomAudienceRemoteInfo()
asíncrono usa el objeto OutcomeReceiver
para indicar el resultado de la llamada a la API.
La devolución de llamada onResult()
significa que la anulación se aplicó correctamente.
Las llamadas posteriores a selectAds()
usan la lógica de informes y ofertas que hayas pasado como anulación.
La devolución de llamada onError()
indica dos condiciones posibles.
- Si se intenta realizar la anulación con argumentos no válidos,
AdServiceException
indicaráIllegalArgumentException
como la causa. - Si la anulación se intenta con una app que no se ejecuta en el modo de depuración con las opciones para desarrolladores habilitadas,
AdServiceException
indicaráIllegalStateException
como la causa.
Cómo restablecer anulaciones orientadas a la compra
En esta sección, se da por sentado que anulaste el código JavaScript orientado a la compra y que tienes una referencia a TestCustomAudienceManager
que se usó en la sección anterior.
Para restablecer las anulaciones para todos los públicos personalizados, sigue estos pasos:
- Llama al método
resetAllCustomAudienceOverrides()
asíncrono con objetosExecutor
yOutcomeReceiver
relevantes.
Kotlin
// Resets overrides for all custom audiences
testCustomAudienceManager.resetCustomAudienceRemoteInfoOverride(
executor,
outComeReceiver)
Java
// Resets overrides for all custom audiences
testCustomAudienceManager.resetCustomAudienceRemoteInfoOverride(
executor,
outComeReceiver)
Después de restablecer las anulaciones orientadas a la compra, las llamadas posteriores a selectAds()
usarán la biddingLogicUrl
y los trustedBiddingData
que estén almacenados en CustomAudience
para intentar recuperar el código JavaScript necesario.
Si la llamada a resetCustomAudienceRemoteInfoOverride()
falla, la devolución de llamada OutComeReceiver.onError()
proporciona una AdServiceException
.
Si se intentan quitar las anulaciones con una app que no se ejecuta en el modo de depuración con las opciones para desarrolladores habilitadas, AdServiceException
indicará IllegalStateException
como la causa.
Cómo configurar un servidor de informes
Cuando uses anulaciones de recuperación remota, deberás configurar un servidor al que pueda acceder tu dispositivo o emulador para responder a los eventos de informes. Un extremo simple que muestra 200 es suficiente para realizar pruebas. El repositorio de GitHub incluye definiciones del servicio de OpenAPI, que se pueden implementar en una plataforma simulada o de microservicios compatible. Para obtener más detalles, consulta el archivo readme del proyecto.
Cuando busques las definiciones de OpenAPI, busca el reporting-server.json.
Este archivo contiene un extremo simple que muestra 200, que representa un código de respuesta HTTP. Este extremo se usa durante selectAds()
y le indica a la API de Protected Audience que los informes de impresiones se completaron correctamente.
Funcionalidad para realizar pruebas
- Prueba unirte a un público personalizado, abandonarlo y configurarlo, según las acciones del usuario anterior.
- Prueba iniciar la selección de anuncios en el dispositivo a través de JavaScript alojados de manera remota.
- Observa cómo la asociación de una app con la configuración de un público personalizado puede afectar los resultados de la selección de anuncios.
- Prueba los informes de impresiones después de la selección de anuncios.
Limitaciones
En la siguiente tabla, se enumeran las limitaciones para el procesamiento de la API de Protected Audience. Los límites que se detallan pueden estar sujetos a cambios en función de los comentarios. Para conocer las funciones en progreso, lee las notas de la versión.
Componente | Descripción del límite | Valor del límite |
---|---|---|
Público personalizado (PP) | Cantidad máxima de anuncios por PP | 100 |
Cantidad máxima de PP por aplicación | 1000 | |
Cantidad máxima de apps que pueden crear un PP | 1000 | |
Retraso máximo en el tiempo de activación de un PP desde el momento de su creación | 60 días | |
Tiempo de caducidad máximo de un PP a partir de su hora de activación | 60 días | |
Cantidad máxima de PP en el dispositivo | 4,000 | |
Tamaño máximo del nombre de PP | 200 bytes | |
Tamaño máximo del URI de recuperación diario | 400 bytes | |
Tamaño máximo del URI de lógica de ofertas | 400 bytes | |
Tamaño máximo de los datos de ofertas confiables | 10 KB | |
Tamaño máximo de los indicadores de ofertas del usuario | 10 KB | |
Tasa máxima de llamadas para leaveCustomAudience por comprador |
1 por segundo | |
Tasa máxima de llamadas para joinCustomAudience por comprador |
1 por segundo | |
Recuperación en segundo plano de AC | Tiempo de espera de la conexión | 5 segundos |
Tiempo de espera de lectura de HTTP | 30 segundos | |
Tamaño máximo total de descarga | 10 KB | |
Duración máxima de una iteración de recuperación | 5 minutos | |
Cantidad máxima de PP actualizados por trabajo | 1000 | |
Selección de anuncios | Cantidad máxima de compradores | Por definir |
Cantidad máxima de PP por comprador | Por definir | |
Cantidad máxima de anuncios en una subasta | Por definir | |
Tiempo de espera de conexión inicial | 5 segundos | |
Tiempo de espera de lectura de la conexión | 5 segundos | |
Tiempo máximo de ejecución de AdSelection |
10 segundos | |
Tiempo máximo de ejecución de ofertas por PP en AdSelection |
5 segundos | |
Tiempo máximo de ejecución para la puntuación en AdSelection |
5 segundos | |
Tiempo máximo de ejecución por comprador en AdSelection |
Por definir | |
Tamaño máximo de la selección de anuncios/vendedor/indicadores por comprador | Por definir | |
Tamaño máximo de las secuencias de comandos del vendedor o comprador | Por definir | |
Tarifa de llamada máxima para selectAds |
1 QPS | |
Informes de impresiones | Tiempo mínimo antes de quitar la selección de anuncios de la persistencia | 24 h |
Cantidad máxima de selecciones de anuncios de almacenamiento | Por definir | |
Tamaño máximo de la URL de salida de los informes | Por definir | |
Tiempo máximo para los informes de impresiones | Por definir | |
Cantidad máxima de reintentos para llamadas de notificación | Por definir | |
Tiempo de espera de la conexión | 5 segundos | |
Tiempo máximo de ejecución general de reportImpression |
2 segundos | |
Tarifa de llamada máxima para reportImpressions |
1 QPS | |
Informes de eventos | Cantidad máxima de píxeles contadores por comprador por subasta | 10 |
Cantidad máxima de píxeles contadores por vendedor por subasta |
10 |
|
Tamaño máximo de la clave del evento |
40 bytes |
|
Tamaño máximo de los datos de eventos |
64 KB |
|
Anuncios | Tamaño máximo de la lista de anuncios | 10 KB compartidos por todos los AdData en un solo AC para los anuncios contextuales |
URLs | Longitud máxima de cualquier cadena de URL tomada como entrada | Por definir |
JavaScript | Tiempo máximo de ejecución | 1 segundo para las ofertas y la puntuación para los informes de impresiones |
Cantidad máxima de memoria usada | 10 MB |
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.
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- Admite la segmentación por público personalizada con la API de Protected Audience
- Notas de la versión
- Protected Audience: guía de integración