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

Les services d'enchères et de mise aux enchères sont un ensemble de services destinés aux acheteurs et aux vendeurs d'annonces qui 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 vendeur peut intégrer une mise aux enchères avec enchères publicitaires Chrome pour les enchères et les mises aux enchères.

Tutoriel

Flux d'intégration du vendeur dans lequel le code JavaScript récupère la charge utile d'enchères de mise aux enchères et de mise aux enchères qui est envoyée à SAS, et SAS transfère la requête à l'interface du vendeur (SFE). SFE renvoie le résultat que SAS doit transmettre au navigateur, et le code JavaScript du vendeur appelle runAdAuction.

La procédure peut se résumer comme suit:

  1. Appeler getInterestGroupAdAuctionData() pour obtenir la charge utile chiffrée à partir du navigateur
  2. Appelez fetch('https://your-ad-server.example') et envoyez la requête d'enchères unifiées avec la charge utile chiffrée à votre SAS.
  3. Appelez l'opération SelectAd() de votre SFE à partir de votre SAS pour exécuter l'enchère d'enchères et de mise aux enchères.
  4. Renvoyez le résultat de l'enchère aux enchères et aux mises aux enchères sur la page, ainsi que le hachage de la réponse.
  5. Appelez runAdAuction() dans le navigateur pour exécuter une mise aux enchères par enchères publiques avec un seul vendeur, en mode mixte ou avec plusieurs vendeurs, et transmettez le résultat de la mise aux enchères côté serveur à l'appel.

Obtenir des données chiffrées sur les enchères d'annonces

Même schéma de procédure avec la première étape mise en évidence, à savoir lorsque le code JavaScript du vendeur appelle 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 de l'appel runAdAuction() ultérieurement.
requestSize Facultatif. Définit la taille maximale de la charge utile de toutes les données de l'acheteur. Pour en savoir plus, consultez la section Taille de la requête de la vidéo explicative.
perBuyerConfig Facultatif. Définit des configurations pour chaque acheteur et contrôle également les acheteurs qui participent aux enchères d'enchères et de mise aux enchères.

Si les origines des acheteurs sont listées dans perBuyerConfig, seules les données du groupe d'intérêts de l'acheteur sont incluses dans la charge utile. Si aucun acheteur n'est listé dans perBuyerConfig, tous les groupes de centres 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 la vidéo explicative.

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

Définit le coordinateur à utiliser pour extraire la clé de chiffrement de la charge utile. Pour en savoir plus, consultez la section Coordinateur de la vidéo explicative.

Lorsque l'appel est effectué, le navigateur lit les groupes de centres d'intérêt des acheteurs listés dans perBuyerConfig et chiffre les données des acheteurs. Ces données d'acheteur contiennent des informations intersites à utiliser pour les enchères et 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êts, les clés de signal d'enchères approuvées 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 d'annonces

La chaîne requestId est utilisée plus tard 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ées.

Pour voir un exemple de cet appel, consultez le code JavaScript du vendeur de l'application de test locale.

Envoyer la requête d'enchères unifiées à SAS

Même diagramme de procédure avec la deuxième étape mise en évidence, c'est-à-dire lorsque le code JavaScript du vendeur envoie une requête d'enchères unifiées à SAS

Une requête d'enchères unifiées est une requête qui contient la charge utile d'enchères contextuelles en texte brut et la charge utile d'enchères PA. La charge utile d'enchères d'enchères publiques est constituée des données request chiffrées générées par le navigateur dans l'appel getInterestGroupAdAuctionData(). Cette requête est envoyée à SAS, où les enchères contextuelles et les enchères d'enchères et d'enchères publiques sont orchestrées.

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

Pour envoyer la requête à 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 de récupération doit correspondre à l'origine seller fournie aux appels getInterestGroupAdAuctionData() et runAdAuction().

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

  1. Charge utile d'enchères contextuelles en texte brut à utiliser par SAS pour exécuter les enchères contextuelles.
  2. Charge utile d'enchères Protected Audience chiffrée à envoyer au 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 vendeur de l'application de test locale.

Encodage et décodage en base64

La charge utile request chiffrée renvoyée par l'appel getInterestGroupAdAuctionData() est une instance de Uint8Array, 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 du navigateur JavaScript fournit les fonctions atob() et btoa() sur window qui convertissent les données binaires en chaîne ASCII encodée en base64. (atob signifie "ASCII vers binaire" et btoa "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 de l'enchère d'enchères et de mise aux enchères chiffré renvoyé par cet appel fetch est également encodé en base64. Vous devez donc le décoder 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 volumineuse que les données d'origine. Pour améliorer encore la latence, utilisez un format autre que JSON pour envoyer les données binaires.

Appeler SelectAd de SFE pour exécuter les enchères et les mises aux enchères

Même schéma de procédure avec la troisième étape mise en surbrillance, qui correspond au moment où SAS envoie une requête SelectAd à SFE et que SFE exécute une mise aux enchères d'enchères et de mise aux enchères

Une fois que le service publicitaire du vendeur a reçu la demande d'enchères unifiées de la page, la mise aux enchères contextuelle s'exécute en premier pour déterminer le gagnant de la mise aux enchères contextuelle et collecter les signaux de l'acheteur à transmettre à la mise aux enchères et aux enchères PA. Ensuite, l'enchère d'enchères et de mise aux enchères est lancée en appelant l'opération SelectAd de la 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.

Créer la charge utile SelectAdRequest

La charge utile de la requête de l'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 d'enchères publicitaires chiffrées du navigateur ont été encodées en base64, elles doivent être décodées en données binaires si la requête envoyée à la SFE utilise gRPC. Si la requête est envoyée via HTTP, les données d'enchères publicitaires chiffrées 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 du protocole SelectAdRequest.

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

Si le vendeur exécute une mise aux enchères en mode mixte ou participe en tant que vendeur de composants à une mise aux enchères multivendeur, le champ top_level_seller doit être défini dans la requête.

Si vous êtes un vendeur 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 êtes un vendeur de composants, la valeur top_level_seller correspond au vendeur de premier niveau de l'enchère multivendeur:

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

Appeler le SelectAd de SFE

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

Appel gRPC

La requête gRPC envoyée à SFE ressemble à celle-ci avec 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 du protocole pour le client SFE se trouve dans le dépôt d'applications 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 se présente comme suit:

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

Transmettre 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

Vous trouverez ci-dessous un exemple de transfert de métadonné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 de 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 niveau supérieur qui exécute une enchère multivendeur orchestrée par le serveur, l'appel GetComponentAuctionCiphertexts est effectué auprès de SFE avant l'appel SelectAd. La réponse contient les charges utiles d'enchères de composants re-chiffrées qui sont envoyées aux services publicitaires des vendeurs de composants. Les résultats des enchères d'annonces d'enchères et de mise aux enchères du composant renvoyés sont fournis à l'appel SelectAd du SFE du vendeur de niveau supérieur.

Pour en savoir plus, consultez la présentation du multivendeur sur GitHub.

Renvoie le résultat de la mise aux enchères sur la page

Même diagramme de procédure avec la quatrième étape mise en évidence, qui correspond au moment où SAS renvoie le résultat de l'enchère de SelectAd au navigateur

Une fois l'enchère de mise aux enchères et de mise aux enchères terminée, le résultat de l'enchère chiffré est renvoyé à SAS, qui répond à la requête d'enchères unifiées à partir de la page de l'étape 2 avec le résultat de l'enchère chiffré. Dans la réponse SAS à la page, le hachage SHA-256 encodé en base64url du résultat de l'enchère chiffrée 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.

La création d'un hachage SHA-256 avec encodage base64 se présente comme suit dans Node:

import { createHash } from 'crypto';

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

L'ajout du hachage dans l'en-tête de réponse et le renvoi du résultat de l'enchère sur la page se présentent comme suit:

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 requête d'enchères unifiées effectuée à partir de la page à l'étape 2, le résultat de la mise aux enchères contextuelle est également inclus dans la réponse.

Vous pouvez inclure plusieurs hachages dans le 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 vendeur de l'application de test locale.

Appeler runAdAuction() pour finaliser l'enchère

Même schéma de procédure 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 aux enchères unifiées renvoyée par SAS inclut le résultat de l'enchère d'enchères et de mise aux enchères chiffré. 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() varie en fonction de la configuration des enchères choisie par le vendeur.

Enchères avec un seul vendeur

Pour exécuter une mise aux enchères d'enchères et de mise aux enchères avec 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 d'enchères et de mise aux enchères exécutée à l'étape 3.

Pour voir un exemple de cet appel, consultez le code JavaScript du vendeur de l'application de test locale.

Enchères en mode mixte

Pour exécuter une mise aux enchères en mode mixte, où les acheteurs sur l'appareil et les acheteurs de mise aux enchères peuvent participer, la configuration des enchères 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 les enchères en mode mixte, le résultat des enchères et la configuration des enchères sur l'appareil sont transmis dans le champ componentAuctions. Dans une mise aux enchères en mode mixte, la valeur seller est identique pour la configuration de premier niveau et les configurations des composants.

Pour voir un exemple de cet appel, consultez le code JavaScript du vendeur de l'application de test locale.

Enchères multivendeurs

Si vous êtes un vendeur de premier niveau qui exécute une mise aux enchères multivendeur orchestrée par l'appareil, chaque vendeur de composants envoie le résultat de la mise aux enchères d'enchères 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 vendeur de l'application de test locale.

Étapes suivantes

Après avoir lu ce guide, vous pouvez procéder comme suit:

En savoir plus

Vous avez des questions ?