Guia do desenvolvedor sobre indicadores de apps protegidos

Para ajudar os desenvolvedores a começar a testar a API Protected App Signals, este documento descreve todas as APIs na plataforma da API, detalha como configurar um ambiente de teste e traz exemplos de scripts e configuração.

Histórico de versões

Janeiro de 2024

Primeira versão do guia do desenvolvedor que oferece suporte à versão do PAS MVP

March 2024

Mudanças na API para oferecer suporte à versão M-2024-05 da API Android e à versão de abril de 2024 dos componentes do lado do servidor. Mudanças mais importantes:

  • Foram adicionados detalhes sobre as permissões necessárias para a API no dispositivo.
  • Foram adicionados detalhes sobre o gerenciamento de cotas de sinais no dispositivo.
  • A assinatura generateBid foi atualizada com mudanças relacionadas à recuperação de anúncios contextuais e ao suporte à saída.
  • Atualizamos a documentação de reportWin, incluindo suporte de saída.
  • Atualização da documentação da API Ad Retrieval removendo o suporte para recuperação de anúncios BYOS e documentando a UDF de recuperação de anúncios

Visão geral da API

A plataforma da API Protected Signals inclui diferentes subconjuntos de APIs em diferentes sistemas:

  • APIs do Android:
    • API Signal Curation, composta de:
    • API Update Signals
    • API Signals Encoding
    • API Protected Auction Support: para ser usada por SDKs para executar o leilão protegido nos servidores de lances e leilões (B&A) usando indicadores de apps protegidos.
  • APIs do servidor:
    • API Protected Auction: uma série de scripts JS em execução nos servidores de lances e leilões. Essa API permite que vendedores e compradores criem a lógica para implementar o leilão protegido.
    • API Ad Retrieval: responsável por fornecer uma lista de anúncios candidatos, de acordo com as informações contextuais e do usuário disponibilizadas para o servidor de lances do comprador.

Cliente Android

No lado do cliente, a plataforma da API Protected App Signals consiste em três APIs diferentes:

  • Update Signals: uma API do sistema Android para ativar a seleção de indicadores no dispositivo.
  • Signals Encoding: uma API do JavaScript para preparar os indicadores que serão enviados ao servidor durante o leilão.
  • Protected Auction Support: uma API que oferece suporte à execução de um leilão protegido nos servidores de lances e leilões. Essa API não é específica para a Protected App Signals, sendo também usada para oferecer suporte a leilões da API Protected Audience.

API Update Signals

A API Update Signals permite às adtechs registrar indicadores relacionados ao usuário e ao app em nome de um comprador. Ela funciona em um modelo de delegação. O autor da chamada fornece um URI que o framework usa para buscar os indicadores correspondentes e a lógica para codificar esses indicadores para serem usados no leilão.

A API requer a permissão android.permission.ACCESS_ADSERVICES_PROTECTED_SIGNALS.

A API updateSignals() vai recuperar um objeto JSON do URI que descreve quais indicadores adicionar ou remover e como preparar esses indicadores para o leilão.

Executor executor = Executors.newCachedThreadPool();
ProtectedSignalsManager protectedSignalsManager
     =  ProtectedSignalsManager.get(context);

// Initialize a UpdateSignalsRequest
UpdateSignalsRequest updateSignalsRequest = new
  UpdateSignalsRequest.Builder(Uri.parse("https://example-adtech1.com/signals"))
      .build();

OutcomeReceiver<Object, Exception> outcomeReceiver = new OutcomeReceiver<Object, Exception>() {
  @Override
  public void onResult(Object o) {
    //Post-success actions
  }

  @Override
  public void onError(Exception error) {
    //Post-failure actions
  };

// Call updateSignals
protectedSignalsManager.updateSignals(updateSignalsRequest,
    executor,
    outcomeReceiver);

A plataforma faz uma solicitação HTTPS ao URI fornecido na solicitação para buscar as atualizações de indicadores. Junto às atualizações de indicadores, a resposta pode incluir um endpoint que hospeda a lógica de codificação para converter os indicadores brutos em payloads codificados. As atualizações dos indicadores precisam estar no formato JSON e podem ter as chaves abaixo:

As chaves de nível superior do objeto JSON precisam corresponder a um destes cinco comandos:

Chave

Descrição

put

Adiciona um novo indicador, substituindo os indicadores existentes com a mesma chave. O valor

para isso é um objeto JSON em que as chaves são strings de base 64 correspondentes à chave que será usada e os valores são uma string de base 64 correspondente ao valor que será usado.

append

Anexa novos indicadores a uma série temporal de indicadores, removendo os mais antigos

para dar espaço aos novos quando o tamanho da série excede o máximo determinado. O valor desse atributo é um objeto JSON em que as chaves são strings de base 64 correspondentes à chave que será anexada e os valores são objetos com dois campos: "values" e "maxSignals".

"values": uma lista de strings de base 64 correspondentes a valores de indicadores que serão anexados à série temporal.

"maxSignals": o número máximo de valores permitidos nessa série temporal. Se

o número atual de indicadores associados à chave exceder "maxSignals", os indicadores mais antigos serão removidos. É possível anexar a uma chave adicionada por put. Adicionar mais do que o número máximo de valores causa um erro.

put_if_not_present

Adiciona um novo indicador somente se não houver indicadores com a mesma chave. O valor para isso é um objeto JSON em que as chaves são strings de base 64 correspondentes à chave que será usada e os valores são uma string de base 64 correspondente ao valor que será usado.

remove

Remove o indicador de uma chave. O valor para isso é uma lista de strings de base 64 correspondentes às chaves dos indicadores que precisam ser excluídos.

update_encoder

Oferece uma ação para atualizar o endpoint e um URI que pode ser usado

para extrair uma lógica de codificação. A subchave para fornecer uma ação de atualização é "ação", e

os valores aceitos atualmente são apenas "REGISTER", que vai registrar o endpoint do codificador se fornecido pela primeira vez ou vai substituir o endpoint atual pelo novo fornecido. É necessário fornecer o endpoint para a ação "REGISTER". A subchave para fornecer um endpoint do codificador é "endpoint", e o valor é a string

do URI para o endpoint.

Confira um exemplo de solicitação JSON:

{
    "put": {
        "AAAAAQ==": "AAAAZQ==",
        "AAAAAg==": "AAAAZg=="
    },
    "append": {
        "AAAAAw==": {
            "values": [
                "AAAAZw=="
            ],
            "max_signals": 3
        }
    },
    "put_if_not_present": {
        "AAAABA==": "AAAAaQ==",
        "AAAABQ==": "AAAAag=="
    },
    "update_encoder": {
        "action": "REGISTER",
        "endpoint": "https://adtech1.com/Protected App Signals_encode_script.js"
    }
}

Os sinais terão uma cota no dispositivo de 10 a 15 KB. Quando a cota for excedida, a PPAPI vai remover os indicadores usando uma estratégia FIFO. O processo de remoção permitirá que a cota seja ligeiramente excedida por um curto intervalo de tempo, a fim de reduzir a frequência das remoções.

API Signals Encoding

Os compradores precisam fornecer uma função de script Java para codificar os indicadores armazenados no dispositivo que serão enviados ao servidor durante o leilão protegido. Eles podem fornecer esse script adicionando o URL em que ele pode ser buscado com a chave "update_encoder" em qualquer uma das respostas a uma solicitação da API UpdateSignal. O script terá a assinatura abaixo:

function encodeSignals(signals, maxSize) {
  let result = new Uint8Array(maxSize);
  // first entry will contain the total size
  let size = 1;
  let keys = 0;
  
  for (const [key, values] of signals.entries()) {
    keys++;
    // In this encoding we only care about the first byte
    console.log("key " + keys + " is " + key)
    result[size++] = key[0];
    result[size++] = values.length;
    for(const value of values) {
      result[size++] = value.signal_value[0];
    }
  }
  result[0] = keys;
  
  return { 'status': 0, 'results': result.subarray(0, size)};
}

O parâmetro signals é um mapa de chaves na forma de UInt8Arrays de tamanho 4 para listas de objetos da API Protected App Signals. Cada objeto da API tem três campos:

  • signal_value: um UInt8Array que representa o valor do indicador.
  • creation_time: um número que representa o horário de criação dos indicadores em segundos de época.
  • package_name: uma string que representa o nome do pacote que criou o indicador.

O parâmetro maxSize é um número que descreve o maior tamanho de matriz permitido para a saída.

A função precisa produzir um objeto com dois campos:

  • status: precisa ser 0 se o script for executado.
  • results: precisa ser um UInt8Array de comprimento menor ou igual a maxSize. Essa matriz será enviada ao servidor durante os leilões e preparada pelo script prepareDataForAdRetrieval.

A codificação oferece às adtechs um estágio inicial de engenharia de atributos, em que elas podem realizar transformações, como a compactação de indicadores brutos em versões concatenadas com base na própria lógica personalizada. Durante um leilão protegido em execução nos ambientes de execução confiáveis (TEE), a lógica personalizada das adtechs vai ter acesso de leitura aos payloads de indicadores gerados pela codificação. A lógica personalizada, conhecida como função definida pelo usuário (UDF) (link em inglês), executada no TEE de B&A do comprador vai ter acesso de leitura aos indicadores codificados e a outros indicadores de contexto fornecidos pelo app do editor para executar a seleção de anúncios (extração de anúncios e lances).

Codificação de indicadores

A cada hora, os indicadores dos compradores que forneceram lógica de codificação com os indicadores registrados serão codificados em um payload de leilão. A matriz de bytes do payload de leilão é mantida no dispositivo e criptografada para ser coletada pelos vendedores como parte dos dados da seleção de anúncios que serão incluídos como parte de um leilão protegido. Para o teste, é possível acionar essa codificação fora do período agendado executando este comando:

adb shell cmd jobscheduler run -f com.google.android.adservices.api 29
Controle de versões da lógica do codificador

Quando é feita uma solicitação de download da lógica do codificador das adtechs, o endpoint pode responder com um número de versão nos cabeçalhos de resposta. Essa versão é mantida com a lógica do codificador no dispositivo. Quando os indicadores brutos são codificados, o payload codificado é mantido com a versão usada para codificação. Essa versão também é enviada ao servidor de B&A durante um leilão protegido para que as adtechs possam usá-la para alinhar a lógica de lances e codificação.

Response header for providing encoder version : X_ENCODER_VERSION

API Protected Auction Support

No lado do dispositivo, realizar um leilão para a API Protected App Signals é o mesmo que realizar um leilão para públicos-alvo protegidos.

Serviços de lances e leilões

Confira as APIs do servidor:

  • API Protected Auction: uma série de funções JS ou UDFs que compradores e vendedores podem implantar nos componentes de B&A deles para determinar a lógica de lances e leilões.
  • API Ad Retrieval: os compradores podem implementar essa API usando um endpoint REST como responsável por fornecer um conjunto de anúncios candidatos para o leilão da API Protected App Signals.

API Protected Auction

A API Protected Auction consiste em uma API de JS ou UDFs que compradores e vendedores podem usar para implementar a lógica de lances e leilões.

UDFs de adtech do comprador
UDF prepareDataForAdRetrieval

Antes que os Indicadores de apps protegidos possam ser usados para buscar candidatos do serviço de recuperação de anúncios TEE, os compradores precisam decodificar e preparar os indicadores de apps protegidos e outros dados fornecidos pelo vendedor. A saída da UDF prepareDataForAdRetrieval dos compradores é transmitida ao serviço de extração de anúncios para extrair os principais anúncios candidatos para lances.

// Inputs
// ------
// encodedOnDeviceSignals: A Uint8Array of bytes from the device.
// encodedOnDeviceSignalsVersion: An integer representing the encoded
//   version of the signals.
// sellerAuctionSignals: Information about auction (ad format, size) derived
//                       contextually.
// contextualSignals: Additional contextual signals that could help in
//                    generating bids.
//
// Outputs
// -------
// Returns a JSON structure to be used for retrieval.
// The structure of this object is left to the adtech.
function prepareDataForAdRetrieval(encodedOnDeviceSignals,encodedOnDeviceSignalsVersion,sellerAuctionSignals,contextualSignals) {
   return {};
}
UDF generateBid

Depois que os principais anúncios candidatos são retornados, eles são transmitidos para a lógica de lances personalizados do comprador, a UDF generateBid (link em inglês):

// Inputs
// ------
// ads: Data string returned by the ads retrieval service. This can include Protected App Signals
//   ads and related ads metadata.
// sellerAuctionSignals: Information about the auction (ad format, size),
//                       derived contextually
// buyerSignals: Any additional contextual information provided by the buyer
// preprocessedDataForRetrieval: This is the output of this UDF.
function generateBid(ads, sellerAuctionSignals, buyerSignals,
                    preprocessedDataForRetrieval,
                    rawSignals, rawSignalsVersion) {
    return { "ad": <ad Value Object>,
             "bid": <float>,
             "render": <render URL string>,
             'adCost': <optional float ad cost>,
             "egressPayload": <limitedEgressPayload>,
             "temporaryUnlimitedEgressPayload": <temporaryUnlimitedEgressPayload>
    };
}

O resultado dessa função é um único lance para um candidato a anúncio, representado como um JSON equivalente a ProtectedAppSignalsAdWithBidMetadata. A função também pode retornar duas matrizes que serão transmitidas para reportWin para ativar o treinamento de modelos. Para mais detalhes sobre saída e treinamento de modelo, consulte a seção de relatórios na explicação do PAS.

UDF reportWin

Quando um leilão é concluído, o serviço gera URLs de relatórios para os compradores e registra beacons usando reportWin UDF. Essa é a mesma função reportWin usada para públicos-alvo protegidos. O dispositivo receberá um ping assim que o anúncio for renderizado pelo cliente. A assinatura desse método é quase a mesma da versão da Protected Audience, exceto por dois parâmetros extras egressPayload e temporaryUnlimitedEgressPayload, que são usados para ativar o treinamento de modelo e preenchidos com os resultados de generateBid.

// Inputs / Outputs
// ----------------
// See detailed documentation here.
function reportWin(auctionSignals, perBuyerSignals, signalsForWinner,
                   buyerReportingSignals,
                   egressPayload, temporaryUnlimitedEgressPayload) {
  // ...
}
UDFs de adtech do vendedor
UDF scoreAd

Essa UDF é usada pelos vendedores para selecionar quais anúncios recebidos dos compradores vão vencer o leilão.

function scoreAd(adMetadata, bid, auctionConfig,
                 trustedScoringSignals, bid_metadata) {
  // ...
  return {desirability: desirabilityScoreForThisAd,
              allowComponentAuction: true_or_false};
}
UDF reportResult

Essa UDF (link em inglês) permite que o vendedor gere (depois de um tempo) relatórios no nível do evento com as informações sobre o anúncio vencedor.

function reportResult(auctionConfig, reporting_metadata) {
  // ...
  registerAdBeacon({"click", clickUrl,"view", viewUrl});
  sendReportTo(reportResultUrl);
  return signalsForWinner;
}

API Ad Retrieval

Na versão do MVP, o serviço de recuperação de anúncios será gerenciado e hospedado pelo comprador, e o serviço de lances recupera os candidatos a anúncios desse serviço. A partir de abril de 2024, o servidor de recuperação de anúncios precisará ser executado em um ambiente de execução confiável (TEE) e expor uma interface GRPC/proto. As empresas de adtech precisam configurar esse servidor e fornecer o URL dele como parte da implantação da pilha de B&A. Uma implementação desse serviço em execução no TEE está disponível no GitHub do Sandbox de privacidade (link em inglês) e no restante da documentação, presumimos que esse seja o código usado na implantação.

A partir de abril de 2024, as versões de B&A são compatíveis com a recuperação de anúncios de caminho contextual. Nesse caso, o servidor de lances vai receber uma lista de identificadores de anúncios enviados pelo servidor de RTB durante a parte contextual do leilão. Os identificadores vão ser enviados a um servidor KV TEE para buscar todas as informações relacionadas ao anúncio que serão usadas durante a fase de lances (por exemplo, ad-render-url, metadados e embeddings de anúncios a serem usados na seleção do top-k). Esse segundo caminho não precisa de nenhuma lógica específica para ser implantada. Portanto, vamos documentar aqui apenas como configurar o caso de uso de recuperação de anúncios baseado em TEE.

UDF HandleRequest
function HandleRequest(requestMetadata, preparedDataForAdRetrieval,
                      deviceMetadata, contextualSignals) {
    return adsMetadataString;
}

Em que:

  • requestMetadata: JSON. Metadados do servidor por solicitação para a UDF. Vazio por enquanto.
  • preparedDataForAdRetrieval: o conteúdo desse campo depende da estratégia de recuperação de anúncios. No caso da recuperação de anúncios contextuais, esse parâmetro vai conter os indicadores brutos do dispositivo e transmitidos pelo serviço de lances. No caso da recuperação de anúncios TEE usando o servidor de recuperação de anúncios, esse parâmetro conterá o resultado da UDF prepareDataForAdRetrieval. Observação: nessa fase, os indicadores de apps protegidos estão decodificados e não criptografados.
  • deviceMetadata: objeto JSON com metadados do dispositivo encaminhados pelo serviço de publicidade do vendedor. Consulte a documentação sobre B&A para mais detalhes.
    • X-Accept-Language: idioma usado no dispositivo.
    • X-User-Agent: user agent usado no dispositivo.
    • X-BnA-Client-IP: endereço IP do dispositivo.
  • contextualSignals: string arbitrária originada do servidor de lances contextuais operado pela mesma DSP. Espera-se que a UDF seja capaz de decodificar a string e usá-la. Eles podem conter informações, como informações da versão do modelo de ML para o embedding protegido transmitido usando os indicadores de app protegidos.

A UDF precisa retornar uma string em caso de êxito. A string é retornada ao servidor de lances, que a transmite para a UDF generateBid. Embora a string possa ser apenas uma string simples, provavelmente ela precisa ser um objeto serializado com esquema definido por cada adtech separadamente. Não há restrição no esquema, desde que a lógica generateBid da adtech possa reconhecer e usar a string.

Configurar o sistema para desenvolvimento

Android

Para configurar seu ambiente de desenvolvimento Android, siga estas etapas:

  1. Crie um emulador (recomendado) ou use um dispositivo físico com a imagem da prévia para desenvolvedores 10.
  2. Execute o comando abaixo:
adb shell am start -n com.google.android.adservices.api/com.android.adservices.ui.settings.activities.AdServicesSettingsMainActivity

Em seguida, selecione a opção mostrada para consentir os anúncios sugeridos por apps.

  1. Execute o comando abaixo para ativar as APIs relevantes. Talvez seja necessário executar esse processo de novo de vez em quando, já que a configuração padrão de "desativado" será sincronizada periodicamente.
adb shell device_config put adservices fledge_custom_audience_service_kill_switch false;  adb shell device_config put adservices fledge_select_ads_kill_switch false; adb shell device_config put adservices fledge_on_device_auction_kill_switch false; adb shell device_config put adservices fledge_auction_server_kill_switch false; adb shell "device_config put adservices disable_fledge_enrollment_check true";  adb shell device_config put adservices ppapi_app_allow_list '\*'; adb shell device_config put adservices fledge_auction_server_overall_timeout_ms 60000;
  1. Reinicie o dispositivo.
  2. Modifique as chaves de leilão do dispositivo para que elas apontem para seu servidor de chaves de leilão. É importante realizar essa etapa antes de tentar realizar um leilão para evitar que chaves incorretas sejam armazenadas em cache.

Serviços de lances e leilões

Para configurar os servidores de B&A, consulte a documentação de configuração de veiculação própria.

Este documento se concentra em como configurar os servidores específicos do comprador, já que não são necessárias mudanças para vendedores.

Pré-requisitos

Antes de implantar um conjunto de serviços de B&A, a adtech do comprador precisa:

  • Verifique se eles implantaram o próprio serviço de recuperação de anúncios TEE. Consulte a seção relevante.
  • Verifique se a adtech tem todas as UDFs necessárias (prepareDataForAdRetrieval, generateBid, reportWin, HandleRequest) definidas e hospedadas.

Também é útil ter uma compreensão de como o leilão protegido com a API Protected Audience funciona com B&A, mas não é necessário.

Configuração do Terraform

Para usar a API Protected App Signals, as adtechs precisam:

  • Ativar o suporte à API Protected App Signals em B&A.
  • Fornecer endpoints de URL em que as novas UDFs de prepareDataForAdRetrieval, generateBid e reportWin possam ser buscadas.

Além disso, este guia presume que as adtechs que querem usar B&A para remarketing vão continuar definindo todas as flags de configuração atuais para o leilão de remarketing, como de costume.

Configuração da adtech do comprador

Usando este arquivo de demonstração como exemplo, os compradores precisam configurar estas flags:

  • Enable Protected App Signals: ativada para coletar dados da API Protected App Signals.
  • Protected App Signals URLs: definida para os URLs dos servidores da API Protected App Signals.

As adtechs precisam substituir os URLs corretos nos marcadores destes campos:

module "buyer" {
  # ... More config here.

  runtime_flags = {
    # ... More config here.

    ENABLE_PROTECTED_APP_SIGNALS                  = "true"
    PROTECTED_APP_SIGNALS_GENERATE_BID_TIMEOUT_MS = "60000"
    TEE_AD_RETRIEVAL_KV_SERVER_ADDR               = "<service mesh address of the instance>"
    AD_RETRIEVAL_TIMEOUT_MS                       = "60000"
    BUYER_CODE_FETCH_CONFIG                       = <<EOF
    {
        "protectedAppSignalsBiddingJsUrl": "<URL to Protected App Signals generateBid UDF>",
        "urlFetchTimeoutMs": 60001, # This has to be > 1 minute.
        "urlFetchPeriodMs": 13000000,
        "prepareDataForAdsRetrievalJsUrl": "<URL to the UDF>"
    }
    EOF

  }  # runtime_flags

}  # Module "buyer"

Configuração da adtech do vendedor

Usando este arquivo de demonstração (link em inglês) como exemplo, os vendedores precisam definir estas flags. Observação: apenas as configurações relacionadas à API Protected App Signals estão destacadas. As adtechs precisam substituir os URLs corretos nos marcadores:

module "seller" {
  # ... More config here.

  runtime_flags = {
    # ... More config here.

    ENABLE_PROTECTED_APP_SIGNALS                  = "true"

    SELLER_CODE_FETCH_CONFIG                           = <<EOF
  {
    "urlFetchTimeoutMs": 60001, # This has to be > 1 minute.
    "urlFetchPeriodMs": 13000000,
    "protectedAppSignalsBuyerReportWinJsUrls": {"<Buyer Domain>": "URL to reportWin UDF"}
  }
  EOF

  }  # runtime_flags

}  # Module "seller"

Serviços de KV e recuperação de anúncios

Dependendo das estratégias escolhidas para oferecer suporte à recuperação de anúncios, o sistema exigirá a implantação de uma ou duas instâncias do serviço KV. Vamos nos referir à instância KV usada para recuperação de anúncios baseados em TEE como Ad Retrieval Server e à instância para oferecer suporte à recuperação baseada em caminho contextual como KV Lookup Server.

Em ambos os casos, a implantação de servidores segue a documentação disponível no GitHub do servidor KV (link em inglês). A diferença entre os dois casos é que o caso de pesquisa funciona imediatamente sem nenhuma configuração extra, enquanto a recuperação requer a implantação da UDF HandleRequest para implementar a lógica de recuperação. Para mais detalhes, consulte o Guia de integração do servidor KV. Observe que o B&A espera que os dois serviços sejam implantados na mesma malha de serviço que o serviço de lances.

Exemplo de configuração

Considere o seguinte cenário: usando a API Protected App Signals, uma adtech armazena indicadores relevantes com base no uso do app do usuário. No nosso exemplo, os indicadores são armazenados representando compras no app de vários apps. Durante um leilão, os indicadores criptografados são coletados e transmitidos para um leilão protegido em execução em B&A. As UDFs do comprador em execução em B&A usam os indicadores para buscar candidatos a anúncio e calcular um lance.

[Comprador] Exemplos de indicadores

Adiciona um indicador com uma chave de 0 e um valor de 1.

{
  "put": {
    "AA==": "AQ=="
  },
  "update_encoder": {
    "action": "REGISTER",
    "endpoint": "https://example.com/example_script"
  }
}

Adiciona um indicador com uma chave de 1 e um valor de 2.

{
  "put": {
    "AQ==": "Ag=="
  },
  "update_encoder": {
    "action": "REGISTER",
    "endpoint": "https://example.com/example_script"
  }
}

[Comprador] Exemplo de encodeSignals

Codifica cada indicador em dois bytes, sendo o primeiro o primeiro byte da chave de indicador e o segundo o primeiro byte do valor do indicador.

function encodeSignals(signals, maxSize) {
  // if there are no signals don't write a payload
  if (signals.size === 0) {
      return {};
  }

  let result = new Uint8Array(signals.size * 2);
  let index = 0;
  
  for (const [key, values] of signals.entries()) {
    result[index++] = key[0];
    result[index++] = values[0].signal_value[0];
  }
  
  return { 'status': 0, 'results': result};
}

[Comprador] Exemplo de prepareDataForAdRetrieval

/**
 * `encodedOnDeviceSignals` is a Uint8Array and would contain
 * the app signals emanating from device. For purpose of the
 * demo, in our sample example, we assume that device is sending
 * the signals with pair of bytes formatted as following:
 * "<id><In app spending>". Where id corresponds to an ad category
 * that user uses on device, and the in app spending is a measure
 * of how much money the user has spent in this app category
 * previously. In our example, id of 0 will correspond to a
 * fitness ad category and a non-zero id will correspond to
 * food app category -- though this info will be useful
 * later in the B&A pipeline.
 *
 * Returns a JSON object indicating what type of ad(s) may be
 * most relevant to the user. In a real setup ad techs might
 * want to decode the signals as part of this script.
 *
 * Note: This example script makes use of only encoded device signals
 * but adtech can take other signals into account as well to prepare
 * the data that will be useful down stream for ad retrieval and
 * bid generation. The max length of the app signals used in this
 * sample example is arbitrarily limited to 4 bytes.
 */
function prepareDataForAdRetrieval(encodedOnDeviceSignals,
                                   encodedOnDeviceSignalsVersion,
                                   sellerAuctionSignals,
                                   contextualSignals) {
  if (encodedOnDeviceSignals.length === 0 || encodedOnDeviceSignals.length > 4 ||
      encodedOnDeviceSignals.length % 2 !== 0) {
     throw "Expected encoded signals length to be an even number in (0, 4]";
  }

  var preparedDataForAdRetrieval = {};
  for (var i = 0; i < encodedOnDeviceSignals.length; i += 2) {
    preparedDataForAdRetrieval[encodedOnDeviceSignals[i]] = encodedOnDeviceSignals[i + 1];
  }
  return preparedDataForAdRetrieval;
}

[Compradores] Exemplo de UDF de recuperação de anúncios

No nosso exemplo, o servidor de extração de anúncios envia metadados (ou seja, o ID para cada anúncio no exemplo, mas pode conter outros dados para cada um que podem ser úteis na geração de lances mais tarde) para cada um dos principais candidatos a anúncio.

function HandleRequest(requestMetadata, protectedSignals, deviceMetadata,
                      contextualSignals) {
 return "[{\"adId\":\"0\"},{\"adId\":\"1\"}]"

[Compradores] Exemplo de generateBid

/**
 * This script receives the data returned by the ad retrieval service
 * in the `ads` argument. This argument is supposed to contain all
 * the Protected App Signals related ads and the metadata obtained from the retrieval
 * service.
 *
 * `preparedDataForAdRetrieval` argument contains the data returned
 * from the `prepareDataForAdRetrieval` UDF.
 *
 * This script is responsible for generating bids for the ads
 * collected from the retrieval service and ad techs can decide to
 * run a small inference model as part of this script in order to
 * decide the best bid given all the signals available to them.
 *
 * For the purpose of the demo, this sample script assumes
 * that ad retrieval service has sent us most relevant ads for the
 * user and this scripts decides on the ad render URL as well as
 * what value to bid for each ad based on the previously decoded
 * device signals. For simplicity sake, this script only considers
 * 2 types of app categories i.e. fitness and food.
 *
 * Note: Only one bid is returned among all the
 * input ad candidates.
 */
function generateBid(ads, sellerAuctionSignals, buyerSignals, preparedDataForAdRetrieval) {
  if (ads === null) {
    console.log("No ads obtained from the ad retrieval service")
    return {};
  }     
        
  const kFitnessAd = "0";
  const kFoodAd = "1";
  const kBuyerDomain = "https://buyer-domain.com";
        
  let resultingBid = 0;
  let resultingRender = kBuyerDomain + "/no-ad";
  for (let i = 0 ; i < ads.length; ++i) {
    let render = "";
    let bid = 0;
    switch (ads[i].adId) {
      case kFitnessAd:
        render = kBuyerDomain + "/get-fitness-app";
        bid = preparedDataForAdRetrieval[kFitnessAd];
        break;
      case kFoodAd:
        render = kBuyerDomain + "/get-fastfood-app";
        bid = preparedDataForAdRetrieval[kFoodAd];
        break;
      default:
        console.log("Unknown ad category");
        render = kBuyerDomain + "/no-ad";
        break;
    }
    console.log("Existing bid: " + resultingBid + ", incoming candidate bid: " + bid);
    if (bid > resultingBid) {
      resultingBid = bid;
      resultingRender = render;
    }
  }
  return {"render": resultingRender, "bid": resultingBid};
}

[Compradores] Exemplo de reportWin

A UDF reportWin informa ao comprador que ele venceu o leilão.

function reportWin(auctionSignals, perBuyerSignals, signalsForWinner,
                                       buyerReportingSignals, directFromSellerSignals,
                                       egressPayload,
                                       temporaryUnlimitedEgressPayload) {
  sendReportTo("https://buyer-controlled-domain.com/");
  registerAdBeacon({"clickEvent":"https://buyer-controlled-domain.com/clickEvent"});
  return;
}

[Vendedor] Configuração do servidor KV

Os vendedores precisam configurar um servidor KV de indicadores de pontuação para que haja um mapeamento disponível dos URLs de renderização do anúncio para os indicadores de pontuação correspondentes. Por exemplo: se https:/buyer-domain.com/get-fitness-app e https:/buyer-domain.com/get-fastfood-app forem retornado pelo comprador, o vendedor poderá receber este exemplo de resposta de indicador de pontuação quando consultado pelo SFE usando um GET em https://key-value-server-endpoint.com?client_type=1&renderUrls=<render-url-returned-by-the-buyer>:

{
   "renderUrls" : {
      "https:/buyer-domain.com/get-fitness-app" : [
         "1",
         "2"
      ],
      "https:/buyer-domain.com/get-fastfood-app" : [
         "3",
         "4"
      ]
   }
}

[Vendedor] Exemplo de scoreAd

/**
 * This module generates a random desirability score for the Protected App
 * Signals ad in this example. In a production deployment,
 * however, the sellers would want to use all the available signals to generate
 * a score for the ad.
 */
function getRandomInt(max) {
  return Math.floor(Math.random() * max);
}

function scoreAd(adMetadata, bid, auctionConfig,
                                   trustedScoringSignals, deviceSignals,
                                   directFromSellerSignals) {
  return {
    "desirability": getRandomInt(10000),
    "allowComponentAuction": false
  };
}

[Vendedor] Exemplo de reportResult

function reportResult(auctionConfig, sellerReportingSignals, directFromSellerSignals){
  let signalsForWinner = {};
    sendReportTo("https://seller-controlled-domain.com");
    registerAdBeacon({"clickEvent":
                    "https://seller-controlled-domain.com/clickEvent"});
    return signalsForWinner;
}

App de exemplo

Como exemplo de como a API pode ser usada para criar um app que usa um fluxo simples, conforme descrito acima, criamos um app de exemplo da API Protected App Signals, que pode ser encontrado neste repositório de exemplo (link em inglês).