Fazer a integração com o B&A como vendedor

Os serviços de lances e leilões (B&A) são um conjunto de serviços para compradores e vendedores de anúncios que são executados em um ambiente de execução confiável (TEE) para facilitar um leilão da Protected Audience (PA). Este guia para desenvolvedores explica como um vendedor pode fazer a integração com um leilão de PA do Chrome para B&A.

Tutorial

Fluxo de integração do vendedor em que o código JavaScript recebe o payload do leilão de B&A enviado ao SAS, e o SAS encaminha a solicitação ao front-end do vendedor (SFE, na sigla em inglês). O SFE retorna o resultado que o SAS precisa encaminhar ao navegador, e o código JavaScript do vendedor chama runAdAuction.

As etapas podem ser resumidas da seguinte forma:

  1. Chame getInterestGroupAdAuctionData() para receber o payload criptografado do navegador.
  2. Chame fetch('https://your-ad-server.example') e envie a solicitação de leilão unificado com o payload criptografado para seu SAS.
  3. Chame a operação SelectAd() do SFE no seu SAS para executar o leilão de B&A.
  4. Retorne o resultado do leilão de B&A para a página junto com o hash da resposta.
  5. Chame runAdAuction() no navegador para executar um leilão de PA de vendedor único, modo misto ou múltiplos vendedores e transmita o resultado do leilão de B&A do lado do servidor para a chamada.

Receber dados criptografados do leilão de anúncios

O mesmo diagrama de instruções com a primeira etapa destacada, que é quando o código JavaScript do vendedor chama getInterestGroupAdAuctionData

Para receber os dados necessários para fazer o leilão de B&A do lado do servidor, o código JavaScript do vendedor na página do editor chama navigator.getInterestGroupAdAuctionData().

const adAuctionData = await navigator.getInterestGroupAdAuctionData({
  seller: 'https://ssp.example', // Required
  requestSize: 51200,
  coordinatorOrigin: 'https://publickeyservice.pa.gcp.privacysandboxservices.com/',
  perBuyerConfig: {
    'https://dsp-x.example': { targetSize: 8192 },
    'https://dsp-y.example': { targetSize: 8192 }
  }
});

const { requestId, request } = adAuctionData;
Campo Descrição
seller Obrigatório. Origem do vendedor que está realizando o leilão. Esse valor precisa corresponder ao valor de seller na chamada runAdAuction() mais tarde.
requestSize Opcional. Define o tamanho máximo do payload de todos os dados do comprador. Consulte a seção Tamanho da solicitação da explicação para saber mais.
perBuyerConfig Opcional. Define configurações para cada comprador e também controla quais compradores participam do leilão de B&A.

Se as origens do comprador estiverem listadas em perBuyerConfig, somente esses dados do grupo de interesse do comprador serão incluídos no payload. Se nenhum comprador estiver listado em perBuyerConfig, todos os grupos de interesse do usuário serão incluídos no payload.

targetSize Opcional se requestSize estiver definido. Obrigatório se uma origem do comprador estiver definida no perBuyerConfig, mas requestSize não estiver definido.

Define o tamanho máximo do payload dos dados desse comprador. Consulte a seção Tamanho da solicitação da explicação para saber mais.

coordinatorOrigin Opcional, mas será obrigatório em algum momento. O padrão é https://publickeyservice.pa.gcp.privacysandboxservices.com quando não definido.

Define o coordenador a ser usado para buscar a chave de criptografia do payload. Consulte a seção coordenador da explicação para saber mais.

Quando a chamada é feita, o navegador lê os grupos de interesse dos compradores listados em perBuyerConfig e criptografa os dados do comprador. Esses dados do comprador contêm informações entre sites que serão usadas para lances e não podem ser descriptografadas fora de um TEE. Para a otimização de payload, apenas o nome do grupo de interesse, as chaves de indicadores de lances confiáveis e os indicadores do navegador são incluídos no payload.

No objeto de dados do leilão de anúncios retornado pela chamada getInterestGroupAdAuctionData(), a string requestId e a matriz de bytes request criptografada estão disponíveis.

Captura de tela do Chrome DevTools que mostra a solicitação e o ID da solicitação disponíveis nos dados do leilão de anúncios.

A string requestId é usada mais tarde quando runAdAuction() é chamado para finalizar o leilão no navegador. O payload request criptografado é enviado ao serviço de anúncios do vendedor como parte da solicitação de leilão unificado.

Para ver um exemplo dessa chamada, consulte o código JavaScript do vendedor do app de teste local.

Enviar a solicitação de leilão unificado para o SAS

O mesmo diagrama de tutorial com a segunda etapa destacada, que é quando o código JavaScript do vendedor envia uma solicitação de leilão unificada para o SAS

Uma solicitação de leilão unificado contém o payload de leilão contextual em texto simples e o payload de leilão de B&A da PA. O payload do leilão de B&A da PA são os dados request criptografados que o navegador gerou na chamada getInterestGroupAdAuctionData(). Essa solicitação é enviada ao SAS, onde o leilão contextual e o leilão de B&A de PA são organizados.

fetch('https://ssp.example/ad-auction', {
  method: 'POST',
  adAuctionHeaders: true,
  body: JSON.stringify({
    contextualAuctionPayload: { somePayload },
    protectedAudienceAuctionPayload: encodeBinaryData(request)
  }),
});

Para enviar a solicitação ao SAS, uma chamada fetch() é feita na página:

  • A chamada precisa incluir a opção adAuctionHeaders: true, que indica ao navegador para verificar a resposta dessa chamada posteriormente, quando runAdAuction() for chamado para concluir o leilão no navegador.
  • A origem da solicitação de busca precisa corresponder à origem seller fornecida às chamadas getInterestGroupAdAuctionData() e runAdAuction().

O corpo da chamada contém:

  1. A carga útil do leilão contextual em texto simples a ser usada pelo SAS para executar o leilão contextual.
  2. O payload criptografado do leilão da Protected Audience a ser enviado para o SFE pelo SAS para executar o leilão de B&A do lado do servidor.

Para ver um exemplo dessa chamada, consulte o código JavaScript do vendedor do app de teste local.

Como codificar e decodificar em base64

O payload request criptografado retornado da chamada getInterestGroupAdAuctionData() é uma instância de Uint8Array, um tipo de dados que o JSON não consegue processar. Para enviar a matriz de bytes em um formato JSON, aplique uma codificação base64 aos dados binários para convertê-los em uma string.

A API JavaScript do navegador fornece as funções atob() e btoa() em window, que convertem entre dados binários e string ASCII codificada em base64. atob significa ASCII para binário, e btoa significa binário para ASCII.

Chamar btoa() para codificar dados binários em uma string codificada em base64 é assim:

function encodeBinaryData(data) {
  return btoa(String.fromCharCode.apply(null, data));
}

O resultado criptografado do leilão de B&A retornado dessa chamada fetch também está em uma codificação base64. Portanto, é necessário decodificá-lo de volta para dados binários. Chame atob() para decodificar a string ASCII codificada em base64 para dados binários:

function decodeBase64String(base64string) {
  return new Uint8Array(
    atob(base64string)
      .split('')
      .map((char) => char.charCodeAt(0))
  );
}

No entanto, uma string codificada em base64 geralmente é cerca de 33% maior que os dados originais. Se quiser melhorar ainda mais a latência, use um formato diferente de JSON para enviar os dados binários.

Chame SelectAd da SFE para executar o leilão de B&A

O mesmo diagrama de instruções com a terceira etapa destacada, que é quando o SAS envia uma solicitação SelectAd para o SFE, e o SFE realiza um leilão de B&A

Depois que o serviço de publicidade do vendedor recebe a solicitação de leilão unificado da página, o leilão contextual é executado primeiro para determinar o vencedor e coletar os indicadores do comprador que serão transmitidos ao leilão de B&A de PA. Em seguida, o leilão de B&A é iniciado chamando a operação SelectAd da SFE na SAS com a carga útil da solicitação. Alguns metadados da solicitação da página para o SAS na etapa 2 são encaminhados para o SFE.

Criar o payload de SelectAdRequest

O payload de solicitação da chamada SelectAd pode ser construído da seguinte maneira:

const selectAdRequest = {
  auction_config: {
    seller: 'https://ssp.example',
    auction_signals: '{"testKey":"someValue"}',
    seller_signals: '{"testKey":"someValue"}',
    buyer_list: [
      'https://dsp-x.example',
      'https://dsp-y.example',
    ],
    per_buyer_config: {
      'https://dsp-x.example': { buyer_signals: '{"testKey": "someValue"}' },
      'https://dsp-y.example': { buyer_signals: '{"testKey": "someValue"}' },
    },
  },
  client_type: 'CLIENT_TYPE_BROWSER',
  protected_auction_ciphertext: decodeBase64string(request)
};

Se os dados criptografados do leilão de anúncios do navegador foram codificados em base64, eles precisam ser decodificados de volta para dados binários se a solicitação para o SFE for enviada usando gRPC. Se a solicitação for enviada usando HTTP, os dados criptografados do leilão de anúncios poderão permanecer na forma codificada em base64.

Para conferir outros campos definidos na solicitação SelectAd, consulte a definição de proto de SelectAdRequest.

Definir o campo de vendedor de nível superior para leilões de modo misto e de componentes

Se o vendedor estiver realizando um leilão de modo misto ou participando como um vendedor de componentes em um leilão de vários vendedores, o campo top_level_seller precisará ser definido na solicitação.

Se você for um vendedor de modo misto, o valor top_level_seller será sua origem:

const selectAdRequest = {
  auction_config: {
    seller: 'https://ssp-mix.example',
    top_level_seller: 'https://ssp-mix.example',
  }
}

Se você for um vendedor de componentes, o valor de top_level_seller será o vendedor de nível superior do leilão de vários vendedores:

const selectAdRequest = {
  auction_config: {
    seller: 'https://ssp-mix.example',
    top_level_seller: 'https://ssp-top.example',
  }
}

Chamar o SelectAd do SFE

A chamada para SFE do SAS pode ser feita com gRPC ou HTTP.

Chamada gRPC

A solicitação gRPC para o SFE se parece com o seguinte usando Express em Node com um cliente gRPC:

import grpc from '@grpc/grpc-js';

// Load proto definition
const packageDefinition = protoLoader.loadSync(protoPath, { keepCase: true, enums: String });

const {
  privacy_sandbox: {
    bidding_auction_servers: { SellerFrontEnd }
  }
} = grpc.loadPackageDefinition(packageDefinition);

// Instantiate the gRPC client
const sfeGrpcClient = new SellerFrontEnd('192.168.84.104:50067', grpc.credentials.createInsecure());

// Send SelectAd request
sfeGrpcClient.selectAd(selectAdRequest,(error, response) => {
  // Handle SFE response
});

A definição proto do cliente SFE pode ser encontrada no repositório do app de teste local.

Chamada HTTP para o proxy do Envoy

A solicitação HTTP POST para o SFE é enviada ao caminho /v1/selectAd e tem esta aparência:

fetch('https://ssp-ba.example/sfe/v1/selectAd', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(selectAdRequest),
});

Encaminhar metadados

Os seguintes metadados da chamada da página para o SAS precisam ser adicionados à chamada SelectAd do SAS para o SFE:

Quando os metadados são enviados ao SFE, eles precisam usar os seguintes cabeçalhos não padrão porque o gRPC pode alterar o cabeçalho User-Agent:

  • X-Accept-Language
  • X-User-Agent
  • X-BnA-Client-IP

Confira um exemplo de como os metadados podem ser encaminhados usando o Express em Node com um cliente gRPC:

sellerAdService.post('/ad-auction', (req, res) => {
  // …
  const metadata = new grpc.Metadata();
  metadata.add('X-Accept-Language', req.header('Accept-Language'));
  metadata.add('X-User-Agent', req.header('User-Agent'));
  metadata.add('X-BnA-Client-IP', req.ip);

  const sfeGrpcClient = createSfeGrpcClient();
  sfeGrpcClient.selectAd(selectAdRequest, metadata, callbackFn);
})

Confira um exemplo de como os metadados podem ser encaminhados usando uma chamada HTTP:

sellerAdService.post('/ad-auction', (req, res) => {
  // …
  fetch('https://ssp-ba.example/sfe/v1/selectAd', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Accept-Language': req.header('Accept-Language'),
      'X-User-Agent': req.header('User-Agent'),
      'X-BnA-Client-IP': req.ip
    },
    body: JSON.stringify(selectAdRequest)
  });
})

Leilão multimarca orquestrado pelo servidor

Se você for um vendedor de nível superior que executa um leilão de vários vendedores orquestrado pelo servidor, a chamada GetComponentAuctionCiphertexts será feita para o SFE antes da chamada SelectAd. A resposta contém os payloads do leilão de componentes recriptografados que são enviados aos serviços de anúncios do vendedor de componentes. Os resultados do leilão de anúncios de B&A do componente retornado são fornecidos à chamada SelectAd da SFE do vendedor de nível superior.

Consulte a explicação sobre vários vendedores no GitHub para saber mais.

Retornar o resultado do leilão de B&A para a página

O mesmo diagrama de tutorial com a quarta etapa destacada, que é quando o SAS envia o resultado do leilão do SelectAd de volta ao navegador

Depois que o leilão de B&A é concluído, o resultado criptografado é retornado ao SAS, que responde à solicitação de leilão unificado da página na etapa 2 com o resultado criptografado. Na resposta do SAS à página, o hash SHA-256 do resultado do leilão criptografado codificado em base64url é definido no cabeçalho da resposta Ad-Auction-Result. Esse hash é usado pelo navegador para verificar a carga útil ao finalizar o leilão no cliente.

A criação de um hash SHA-256 com codificação base64 é semelhante a isto em Node:

import { createHash } from 'crypto';

createHash('sha256')
  .update(binaryData, 'base64')
  .digest('base64url');

Anexar o hash no cabeçalho da resposta e retornar o resultado do leilão para a página é assim:

sellerAdService.post('/ad-auction', (req, res) => {
  // …
  sfeGrpcClient.selectAd(selectAdRequest, metadata, (error, response) => {
    const { auction_result_ciphertext } = response;

    const ciphertextShaHash = createHash('sha256')
      .update(auction_result_ciphertext, 'base64')
      .digest('base64url');

    res.set('Ad-Auction-Result', ciphertextShaHash);

    res.json({
      protectedAudienceAuctionResult: encodeBinaryData(auction_result_ciphertext),
      contextualAuctionResult: getContextualAuctionResult()
    });
  });
})

Como essa é uma resposta à solicitação de leilão unificado feita na página da etapa 2, o resultado do leilão contextual também está incluído na resposta.

É possível incluir vários hashes no Ad-Auction-Result repetindo o cabeçalho ou separando os hashes. Os dois cabeçalhos de resposta a seguir são equivalentes:

Ad-Auction-Result: ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0=,9UTB-u-WshX66Xqz5DNCpEK9z-x5oCS5SXvgyeoRB1k=
Ad-Auction-Result: ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0=
Ad-Auction-Result: 9UTB-u-WshX66Xqz5DNCpEK9z-x5oCS5SXvgyeoRB1k=

Para ver um exemplo dessa chamada, consulte o código do servidor do vendedor do app de teste local.

Chame runAdAuction() para concluir o leilão

O mesmo diagrama de instruções com a quinta etapa destacada, que é quando o código JavaScript do lado do cliente executa o leilão e fornece a resposta do servidor.

A resposta unificada do leilão retornada pelo SAS inclui o resultado criptografado do leilão de B&A. Esse payload é transmitido para a chamada runAdAuction() para concluir o leilão no navegador. O valor requestId da chamada getInterestGroupAdAuctionData() na etapa 1 também é transmitido para o leilão.

// Get the encrypted ad auction data (Step #1)
const { requestId, request } = navigator.getInterestGroupAdAuctionData(adAuctionDataConfig)

// Send unified auction request (Step #2)
const response = await fetch('https://ssp-ba.example/ad-auction', {
  method: 'POST',
  body: JSON.stringify({
    adAuctionRequest: encodeBinaryData(request),
  }),
});

const { protectedAudienceAuctionResult } = await response.json();

// Finish the auction in the browser
await navigator.runAdAuction({
  // pass in "requestId" and "protectedAudienceAuctionResult"
  // the config structure will differ based on the auction configuration
});

A estrutura da configuração do leilão transmitida para a chamada runAdAuction() varia de acordo com a configuração do leilão escolhida pelo vendedor.

Leilão de vendedor único

Para executar um leilão de B&A de um único vendedor, a configuração do leilão da chamada runAdAuction() é criada da seguinte maneira:

await navigator.runAdAuction({
  seller: 'https://ssp-ba.example',
  requestId,
  serverResponse: protectedAudienceAuctionResult,
});

O campo requestId aceita o requestId retornado pela chamada getInterestGroupAdAuctionData(). O campo serverResponse aceita uma matriz de bytes do leilão de B&A executado na etapa 3.

Para ver um exemplo dessa chamada, consulte o código JavaScript do vendedor do app de teste local.

Leilão de modo misto

Para executar um leilão de B&A no modo misto em que compradores no dispositivo e de B&A podem participar, a configuração do leilão da chamada runAdAuction() é criada da seguinte maneira:

await navigator.runAdAuction({
  seller: 'https://ssp-mix.example',
  decisionLogicURL: 'https://ssp-mix.example/score-ad.js',
  componentAuctions: [
    // B&A auction result
    {
      seller: 'https://ssp-mix.example',
      requestId,
      serverResponse: protectedAudienceAuctionResult,
    },
    // On-device auction config
    {
      seller: 'https://ssp-mix.example',
      decisionLogicURL: 'https://ssp-mix.example/on-device-score-ad.js',
      interestGroupBuyers: [
        'https://dsp-a.example', // On-device buyer
        'https://dsp-a.example', // On-device buyer
      ],
    },
  ]
});

Para facilitar um leilão de modo misto, o resultado do leilão de B&A e a configuração do leilão no dispositivo são transmitidos para o campo componentAuctions. Em um leilão de modo misto, o valor de seller é o mesmo para a configuração de nível superior e as configurações de componentes.

Para ver um exemplo dessa chamada, consulte o código JavaScript do vendedor do app de teste local.

Leilão de vários vendedores

Se você for um vendedor de nível superior que realiza um leilão de vários vendedores orquestrado por dispositivo, cada vendedor componente vai enviar o resultado do leilão de B&A e as configurações do leilão no dispositivo.

await navigator.runAdAuction({
  seller: 'https://ssp-top.example',
  decisionLogicURL: 'https://ssp-top.example/score-ad.js',
  componentAuctions: [
    // SSP-BA's B&A-only auction result
    {
      seller: 'https://ssp-ba.example',
      requestId: 'g8312cb2-da2d-4e9b-80e6-e13dec2a581c',
      serverResponse: Uint8Array(560) [193, 120, 4, ] // Encrypted B&A auction result
    },
    // SSP-MIX's B&A auction result
    {
      seller: 'https://ssp-mix.example',
      requestId: 'f5135cb2-da2d-4e9b-80e6-e13dec2a581c',
      serverResponse: Uint8Array(560) [133, 20, 4, ] // Encrypted B&A auction result
    }.
    // SSP-MIX's on-device auction config
    {
      seller: 'https://ssp-mix.example',
      interestGroupBuyers: ['https://dsp-a.example', 'https://dsp-b.example'],
      decisionLogicURL: 'https://ssp-mix.example/score-ad.js',
    }
    // SSP-OD's on-device auction config
    {
      seller: 'https://ssp-od.example',
      interestGroupBuyers: ['https://dsp-a.example', 'https://dsp-b.example'],
      decisionLogicURL: 'https://ssp-od.example/score-ad.js',
    }
  ]
})

Para ver um exemplo dessa chamada, consulte o código JavaScript do vendedor do app de teste local.

Próximas etapas

Depois de ler este guia, você pode seguir estas etapas:

Saiba mais

Dúvidas?