Intégrer des enchères en ligne en tant que vendeur

Les services d'enchères et de mise aux enchères (B&A) sont un ensemble de services destinés aux acheteurs et aux vendeurs d'annonces. Ils s'exécutent dans un environnement d'exécution sécurisé (TEE) pour faciliter les enchères Protected Audience (PA). Ce guide du développeur explique comment un marchand peut s'intégrer à une enchère Chrome PA pour B&A.

Tutoriel

Flux d'intégration du marchand où le code JavaScript obtient la charge utile des enchères B&A envoyée à SAS, et où SAS transfère la requête au Seller Front-End (SFE). SFE renvoie le résultat que SAS doit transférer au navigateur, et le code JavaScript du vendeur appelle runAdAuction.

Voici les étapes à suivre :

  1. Appelez getInterestGroupAdAuctionData() pour obtenir la charge utile chiffrée du navigateur.
  2. Appelez fetch('https://your-ad-server.example') et envoyez la demande d'enchères unifiées avec la charge utile chiffrée à votre SAS.
  3. Appelez l'opération SelectAd() de votre SFE depuis votre SAS pour exécuter l'enchère B&A.
  4. Renvoie le résultat des enchères B&A à la page, ainsi que le hachage de la réponse.
  5. Appelez runAdAuction() dans le navigateur pour exécuter une enchère PA à un seul vendeur, en mode mixte ou multivendeur, et transmettez le résultat de l'enchère B&A côté serveur à l'appel.

Obtenir des données chiffrées sur les enchères publicitaires

Diagramme de procédure pas à pas identique, avec la première étape mise en évidence (code JavaScript du marchand appelant getInterestGroupAdAuctionData)

Pour obtenir les données nécessaires à l'exécution des enchères et des mises aux enchères côté serveur, le code JavaScript du vendeur sur la page de l'éditeur appelle 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;
Champ Description
seller Obligatoire. Origine du vendeur qui organise l'enchère. Cette valeur doit correspondre à la valeur seller dans l'appel runAdAuction() ultérieur.
requestSize Facultatif. Définit la taille maximale de la charge utile pour toutes les données des acheteurs. Pour en savoir plus, consultez la section Taille de la requête de l'explication.
perBuyerConfig Facultatif. Définit les configurations pour chaque acheteur et contrôle également les acheteurs qui participent aux enchères B&A.

Si les origines des acheteurs sont listées dans perBuyerConfig, seules les données de ces groupes d'intérêt des acheteurs sont incluses dans la charge utile. Si aucun acheteur n'est listé dans perBuyerConfig, tous les groupes d'intérêt de l'utilisateur sont inclus dans la charge utile.

targetSize Facultatif si requestSize est défini. Obligatoire si une origine d'acheteur est définie dans perBuyerConfig, mais que requestSize ne l'est pas.

Définit la taille maximale de la charge utile des données de cet acheteur. Pour en savoir plus, consultez la section Taille de la requête de l'explication.

coordinatorOrigin Facultatif, mais deviendra obligatoire à terme. Si elle n'est pas définie, la valeur par défaut est https://publickeyservice.pa.gcp.privacysandboxservices.com.

Définit le coordinateur à utiliser pour récupérer la clé permettant de chiffrer la charge utile. Pour en savoir plus, consultez la section Coordinateur de l'explication.

Lorsque l'appel est effectué, le navigateur lit les groupes d'intérêt des acheteurs listés dans perBuyerConfig et chiffre les données des acheteurs. Ces données sur les acheteurs contiennent des informations multisites à utiliser pour les enchères. Elles ne peuvent pas être déchiffrées en dehors d'un TEE. Pour l'optimisation de la charge utile, seuls le nom du groupe d'intérêt, les clés de signaux d'enchères fiables et les signaux du navigateur sont inclus dans la charge utile.

Dans l'objet de données d'enchères publicitaires renvoyé par l'appel getInterestGroupAdAuctionData(), la chaîne requestId et le tableau d'octets request chiffré sont disponibles.

Capture d'écran des outils pour les développeurs Chrome montrant que la demande et l'ID de demande sont disponibles dans les données des enchères publicitaires.

La chaîne requestId est utilisée ultérieurement lorsque runAdAuction() est appelé pour terminer l'enchère dans le navigateur. La charge utile request chiffrée est envoyée au service publicitaire du vendeur dans le cadre de la demande d'enchères unifiée.

Pour voir un exemple de cet appel, consultez le code JavaScript du marchand de l'application de test en local.

Envoyer la demande d'enchères unifiées à SAS

Diagramme du même parcours avec la deuxième étape mise en évidence, qui correspond au moment où le code JavaScript du vendeur envoie une demande d'enchères unifiée à SAS

Une demande d'enchères unifiée est une demande qui contient la charge utile d'enchères contextuelles en texte brut et la charge utile d'enchères B&A PA. La charge utile d'enchères B&A PA correspond aux données request chiffrées que le navigateur a générées lors de l'appel getInterestGroupAdAuctionData(). Cette demande est envoyée à SAS, où l'orchestration des enchères contextuelles et des enchères B&A de l'éditeur partenaire a lieu.

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

Pour envoyer la demande à SAS, un appel fetch() est effectué à partir de la page :

  • L'appel doit inclure l'option adAuctionHeaders: true, qui indique au navigateur de vérifier la réponse de cet appel ultérieurement, lorsque runAdAuction() est appelé pour terminer l'enchère dans le navigateur.
  • L'origine de la requête d'extraction doit correspondre à l'origine seller fournie aux appels getInterestGroupAdAuctionData() et runAdAuction().

Le corps de l'appel contient les éléments suivants :

  1. Charge utile de l'enchère contextuelle en texte brut à utiliser par le SAS pour exécuter l'enchère contextuelle.
  2. Charge utile chiffrée des enchères Protected Audience à envoyer à SFE par SAS pour exécuter les enchères et mises aux enchères côté serveur.

Pour voir un exemple de cet appel, consultez le code JavaScript du marchand de l'application de test en local.

Encodage et décodage en base64

La charge utile request chiffrée renvoyée par l'appel getInterestGroupAdAuctionData() est une instance de Uint8Array, qui est un type de données que JSON ne peut pas gérer. Pour envoyer le tableau d'octets au format JSON, vous pouvez appliquer un encodage base64 aux données binaires pour les convertir en chaîne.

L'API JavaScript pour navigateur fournit les fonctions atob() et btoa() sur window, qui permettent de convertir les données binaires en chaîne ASCII encodée en base64 et inversement. (atob signifie ASCII vers binaire et btoa signifie binaire vers ASCII).

L'appel de btoa() pour encoder des données binaires dans une chaîne encodée en base64 se présente comme suit :

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

Le résultat chiffré de l'enchère B&A renvoyé par cet appel fetch est également encodé en base64. Vous devez donc le décoder pour le reconvertir en données binaires. Appelez atob() pour décoder la chaîne ASCII encodée en base64 en données binaires :

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

Toutefois, une chaîne encodée en base64 est généralement environ 33 % plus grande que les données d'origine. Si vous souhaitez améliorer davantage la latence, utilisez un format autre que JSON pour envoyer les données binaires.

Appelez SelectAd de SFE pour exécuter l'enchère B&A.

Diagramme du même parcours avec la troisième étape mise en évidence, qui correspond au moment où le SAS envoie une demande SelectAd au SFE et où le SFE exécute une enchère B&A

Une fois que le service d'annonces du vendeur reçoit la demande d'enchères unifiées de la page, la mise aux enchères contextuelle est exécutée en premier pour déterminer le gagnant et collecter les signaux de l'acheteur à transmettre aux enchères et mises aux enchères PA. L'enchère B&A est ensuite lancée en appelant l'opération SelectAd du SFE à partir de SAS avec la charge utile de la requête. Notez que certaines métadonnées de la requête de la page envoyée à SAS à l'étape 2 sont transmises à SFE.

Construire la charge utile SelectAdRequest

La charge utile de la requête d'appel SelectAd peut être construite comme suit :

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

Notez que si les données chiffrées des enchères publicitaires provenant du navigateur ont été encodées en base64, elles doivent être décodées pour revenir à des données binaires si la requête est envoyée à SFE à l'aide de gRPC. Si la requête est envoyée via HTTP, les données chiffrées des enchères publicitaires peuvent rester sous leur forme encodée en base64.

Pour afficher les autres champs définis dans la requête SelectAd, consultez la définition proto de SelectAdRequest.

Définir le champ du vendeur de premier niveau pour les enchères en mode mixte et par composants

Si le vendeur organise une enchère en mode mixte ou participe en tant que vendeur de composants à une enchère multivendeur, le champ top_level_seller doit être défini dans la demande.

Si vous êtes un marchand en mode mixte, la valeur top_level_seller correspond à votre origine :

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

Si vous vendez des composants, la valeur top_level_seller correspond au vendeur de premier niveau de l'enchère multiseller :

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

Appeler le SelectAd de SFE

L'appel à SFE depuis SAS peut être effectué avec gRPC ou HTTP.

Appel gRPC

La requête gRPC envoyée à SFE ressemble à ce qui suit en utilisant Express dans Node avec un client 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
});

La définition proto du client SFE est disponible dans le dépôt de l'application de test local.

Appel HTTP au proxy Envoy

La requête HTTP POST envoyée à SFE est envoyée au chemin d'accès /v1/selectAd et ressemble à ce qui suit :

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

Transférer les métadonnées

Les métadonnées suivantes de l'appel de la page à SAS doivent être ajoutées à l'appel SelectAd de SAS à SFE :

Lorsque les métadonnées sont envoyées à SFE, elles doivent utiliser les en-têtes non standards suivants, car gRPC peut modifier l'en-tête User-Agent :

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

Voici un exemple de la façon dont les métadonnées peuvent être transférées à l'aide d'Express dans Node avec un client 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);
})

Voici un exemple de transfert des métadonnées à l'aide d'un appel 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)
  });
})

Enchères multivendeurs orchestrées par le serveur

Si vous êtes un vendeur de premier niveau qui exécute une enchère multivendeur orchestrée par le serveur, l'appel GetComponentAuctionCiphertexts est effectué vers SFE avant l'appel SelectAd. La réponse contient les charges utiles d'enchères de composants rechiffrées qui sont envoyées aux services publicitaires des vendeurs de composants. Les résultats des enchères d'annonces de composants B&A renvoyés sont fournis à l'appel SelectAd de la SFE du vendeur de premier niveau.

Pour en savoir plus, consultez l'explication sur les vendeurs multiples sur GitHub.

Renvoie le résultat de l'enchère B&A à la page

Diagramme du parcours avec la quatrième étape mise en évidence, qui correspond au moment où le SAS renvoie le résultat de l'enchère SelectAd au navigateur

Une fois l'enchère B&A terminée, le résultat chiffré de l'enchère est renvoyé au SAS. Le SAS répond ensuite à la demande d'enchère unifiée de la page à l'étape 2 avec le résultat chiffré de l'enchère. Dans la réponse SAS à la page, le hachage SHA-256 du résultat d'enchères chiffré, encodé en base64url, est défini dans l'en-tête de réponse Ad-Auction-Result. Ce hachage est utilisé par le navigateur pour valider la charge utile à la fin de l'enchère dans le client.

Voici comment créer un hachage SHA-256 avec un encodage en base64 dans Node :

import { createHash } from 'crypto';

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

Voici à quoi ressemble l'ajout du hachage dans l'en-tête de réponse et le renvoi du résultat de l'enchère à la page :

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

Comme il s'agit d'une réponse à la demande d'enchères unifiées effectuée à partir de la page à l'étape 2, le résultat des enchères contextuelles est également inclus dans la réponse.

Vous pouvez inclure plusieurs hachages dans Ad-Auction-Result en répétant l'en-tête ou en séparant les hachages. Les deux en-têtes de réponse suivants sont équivalents :

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

Pour voir un exemple de cet appel, consultez le code du serveur du marchand de l'application de test local.

Appelez runAdAuction() pour finaliser les enchères.

Le même diagramme de procédure pas à pas avec la cinquième étape mise en évidence, qui correspond au moment où le code JavaScript côté client exécute l'enchère et fournit la réponse du serveur.

La réponse unifiée aux enchères renvoyée par le SAS inclut le résultat chiffré des enchères B&A. Cette charge utile est transmise à l'appel runAdAuction() pour finaliser l'enchère dans le navigateur. La valeur requestId de l'appel getInterestGroupAdAuctionData() à l'étape 1 est également transmise à l'enchère.

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

La structure de la configuration des enchères transmise à l'appel runAdAuction() diffère en fonction de la configuration des enchères choisie par le vendeur.

Enchères d'un seul vendeur

Pour exécuter une enchère B&A à un seul vendeur, la configuration de l'enchère de l'appel runAdAuction() est construite comme suit :

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

Le champ requestId accepte le requestId renvoyé par l'appel getInterestGroupAdAuctionData(). Le champ serverResponse accepte un tableau d'octets de l'enchère B&A exécutée à l'étape 3.

Pour voir un exemple de cet appel, consultez le code JavaScript du marchand de l'application de test en local.

Enchères en mode mixte

Pour exécuter une enchère B&A en mode mixte où les acheteurs sur l'appareil et B&A peuvent participer, la configuration de l'enchère de l'appel runAdAuction() est construite comme suit :

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
      ],
    },
  ]
});

Pour faciliter une enchère en mode mixte, le résultat de l'enchère B&A et la configuration de l'enchère sur l'appareil sont transmis au champ componentAuctions. Dans une enchère en mode mixte, la valeur seller est la même pour la configuration de premier niveau et les configurations de composants.

Pour voir un exemple de cet appel, consultez le code JavaScript du marchand de l'application de test en local.

Enchères multivendeurs

Si vous êtes un vendeur de premier niveau qui organise une enchère multivendeur orchestrée par un appareil, chaque vendeur de composants envoie le résultat de son enchère B&A et les configurations d'enchères sur l'appareil.

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',
    }
  ]
})

Pour voir un exemple de cet appel, consultez le code JavaScript du marchand de l'application de test en local.

Étapes suivantes

Après avoir lu ce guide, vous pouvez suivre les étapes suivantes :

En savoir plus

Vous avez des questions ?