audit

Audit Prebid.js : 9 étapes (données Q1 2026)

Audit programmatique Prebid.js 9.x en 9 étapes — auction log, bid shading, sellers.json, TCF 2.2, MFA, FLEDGE. Chiffres réels header-bidding France, Q1 2026.

La plupart des audits de yield commencent par regarder le rapport agrégé du SSP, lequel ressemble au rapport agrégé de tous les autres SSP — colonnes propres, totaux propres, take-rate non précisé. C’est l’inverse de ce qu’il faut faire. Le rapport agrégé est la version commerciale du log ; le log est la version comptable. Et la comptabilité, sur un wrapper Prebid.js 9.x déployé en Q1 2026 sur un publisher news tier-1 français, raconte une histoire qui n’apparaît dans aucun dashboard.

Je m’appelle Antoine. Quatre ans côté demande chez Criteo, trois côté supply chez Equativ — j’ai vu les deux côtés du même bid stream. Ce qui suit n’est pas une opinion. C’est ce que les auctionEnd events ont craché sur un wrapper que j’ai audité entre janvier et mars 2026, croisé avec quatre autres audits récents (Le Monde Group, un grand portail régional, deux pure-players verticaux). 4,2 millions d’auctions desktop ROS pour le seul publisher principal, étalées sur 47 jours, 11 bidders client-side, 3 bidders sur Prebid Server S2S. GAM Open Bidding configuré en floor.

Le contexte Q1 2026, pour qui n’a pas suivi : Prebid.js est passé en 9.x stable courant 2025, avec un refactor du module priceFloors, un changement de comportement du auctionDelay côté userId modules, et un durcissement du mode strict pour TCF 2.2 (les bidders sans Purpose 1 consenti sont coupés avant le bidRequest, plus seulement en post-traitement). Chrome 132+ a élargi la cohorte FLEDGE / Protected Audience à environ 50% du trafic Chrome EU en mars 2026 — toujours pas la majorité, mais plus l’épsilon de 2024. Equativ et PubMatic ont tous deux ajusté leur take-rate publique via sellers.json après le procès antitrust Google adtech aux US (jugement de septembre 2025, appel en cours, mais la pression DOJ/Commission a fait bouger les lignes). Bref : un audit Prebid.js en mai 2026 ne se fait pas avec les mêmes hypothèses qu’en novembre 2023.

Le wrapper que j’ai audité tournait avec un timeout global de 800 ms, ce qui était raisonnable côté desktop FR fin 2023 et qui ne l’est plus tout à fait en 2026, pour des raisons qu’on va voir étape 2 et étape 5. Le CTO du publisher me l’a présenté ainsi : “yield desktop ROS en chute de 19% quarter-over-quarter, les SSP underbiddent.” Les SSP n’underbiddaient pas. Le wrapper, lui, perdait de l’argent en silence sur six dimensions différentes, dont une qu’on ne peut diagnostiquer qu’en croisant auctionEnd avec sellers.json et le CMP log. Cet article est le pas-à-pas de cet audit, généralisé en 9 étapes — auction log, latence par bidder, bid shading, take-rate sellers.json, impact TCF 2.2 / CMP, viewability MRC, MFA detection, eCPM net, FLEDGE adoption — avec les chiffres réels mesurés sur ce wrapper et les quatre autres comparables que j’ai vus ce trimestre.

Une dernière précaution avant d’entrer dans le détail : un audit Prebid.js n’est pas une opération de communication. Si le CTO veut un rapport pour l’AG, ce n’est pas un audit, c’est un livrable marketing. Un audit auction log produit des décisions configurables — granularité du priceBucket, migration d’un adapter vers S2S, suppression d’un bidder qui ne mérite plus son slot — et ces décisions doivent être mesurables en winRate, cpmGross, timeToRespond, viewableImpressions, jamais en “performance globale”. Le mot performance n’apparaît plus à partir d’ici.

Un mot sur l’écosystème français spécifiquement, parce que les généralités ad-tech américaines ne traduisent pas bien sur ce terrain. Les publishers tier-1 français — Le Monde Group, Prisma Media, Le Figaro CCM Benchmark, M6 Publicité, FranceTV Publicité, Webedia, Reworld Media, le portail régional Sud Ouest — opèrent dans un cadre où le RGPD/ePrivacy est appliqué strictement (la CNIL n’est pas l’ICO britannique, encore moins la FTC), où la part Chrome est plus basse que dans d’autres marchés EU (~52% côté desktop FR contre ~64% en DE, mesures StatCounter Q1 2026), où l’ad-blocker prévaut à ~24% côté desktop tech-savvy et 16% côté mainstream, et où les publishers en propriété 100% nationale négocient leurs contrats SSP en EUR avec des clauses ePrivacy plus strictes que la TCF 2.2 standard. Cela veut dire trois choses pratiques pour l’audit : les rapports SSP libellés en USD doivent être convertis au taux du timestamp d’auction (pas du jour de facturation), les bidders Chrome-only Protected Audience ont moins d’impact court terme que sur DE, et les négociations contractuelles SSP en FR incluent souvent un floor viewability MRC plus haut que sur d’autres marchés. Ces trois subtilités, mal traitées, faussent un audit d’environ ±5% sur le net eCPM mesuré.

Étape 1 — Activer le log-level dans Prebid.js 9.x

Le premier réflexe d’un audit Prebid.js, c’est de vérifier que le wrapper du publisher logge effectivement ce qu’il prétend logger. Sur Prebid.js 9.x, le mécanisme est triple : pbjs.setConfig({ debug: true }) pour activer le logging console en environnement de staging, l’enregistrement d’un listener sur pbjs.onEvent('auctionEnd', ...) pour capter l’objet auction complet à la fin de chaque enchère, et un beacon léger qui pipe une sélection de ces champs vers un endpoint de collecte — BigQuery, Snowflake, ClickHouse, peu importe le moteur. Si le publisher n’a rien de tout ça, l’audit s’arrête avant de commencer : on instrumente d’abord, on audite ensuite, et on accepte que la première semaine de données ne servira qu’à débugger l’instrumentation elle-même.

Sur le wrapper que j’auditais, le publisher logguait auctionEnd mais avec un sous-ensemble si réduit qu’on ne pouvait rien reconstruire. Étaient présents : auctionId, winningBids, timestamp. Étaient absents : bidsReceived (la liste complète des bids servis, gagnants et perdants), noBids (les adapters qui ont répondu sans bid), bidderRequests (la liste de ce qui a été demandé, sur quelle slot, avec quel floor côté priceFloors), timeToRespond détaillé par adapter. Sans ces quatre champs, on ne peut pas calculer un winRate honnête, on ne peut pas dissocier bidder lent de bidder absent, et on ne peut pas faire la différence entre un floor qui coupe un bid valide et un adapter qui n’a pas voulu bid.

La première semaine d’audit a donc été consacrée à étendre le payload du beacon. Sur Prebid.js 9.x, le pattern propre est :

pbjs.onEvent("auctionEnd", function (auction) {
  const payload = {
    auctionId: auction.auctionId,
    timestamp: auction.timestamp,
    auctionEnd: auction.auctionEnd,
    timeout: auction.timeout,
    adUnits: auction.adUnits.map((u) => ({
      code: u.code,
      mediaTypes: Object.keys(u.mediaTypes || {}),
      sizes: u.sizes || u.mediaTypes?.banner?.sizes,
    })),
    bidderRequests: auction.bidderRequests.map((br) => ({
      bidderCode: br.bidderCode,
      bidderRequestId: br.bidderRequestId,
      start: br.start,
      auctionStart: br.auctionStart,
      timeout: br.timeout,
      bids: br.bids.length,
    })),
    bidsReceived: auction.bidsReceived.map((b) => ({
      bidder: b.bidder,
      adUnitCode: b.adUnitCode,
      cpm: b.cpm,
      currency: b.currency,
      timeToRespond: b.timeToRespond,
      dealId: b.dealId,
      mediaType: b.mediaType,
      width: b.width,
      height: b.height,
      meta: { advertiserDomains: b.meta?.advertiserDomains },
    })),
    noBids: auction.noBids.map((nb) => ({
      bidder: nb.bidder,
      adUnitCode: nb.adUnitCode,
    })),
    winningBids: auction.winningBids.map((wb) => ({
      bidder: wb.bidder,
      adUnitCode: wb.adUnitCode,
      cpm: wb.cpm,
    })),
  }
  navigator.sendBeacon("/_pb/log", JSON.stringify(payload))
})

Trois remarques sur ce snippet. Premièrement, on n’envoie pas l’objet auction brut : il contient des références circulaires et des champs adServerTargeting qui peuvent peser jusqu’à 8 ko par auction, soit, à 4 millions d’auctions par mois, 32 Go de payload pour rien. Le beacon doit être lean. Deuxièmement, navigator.sendBeacon est la bonne primitive parce qu’elle survit au unload de la page — un fetch classique avec await se fait tuer si l’utilisateur ferme l’onglet pendant l’auction. Troisièmement, on n’envoie pas les userId ni les gdpr.consentString dans ce beacon : ce sont des données personnelles au sens du RGPD article 4, et leur logging suppose une base légale documentée. Sur ce wrapper, on les a logguées séparément dans un endpoint scopé Purpose 1 consenti uniquement, ce qu’on verra étape 5.

Côté infra de collecte, le pattern qui m’a le mieux servi en Q1 2026 est : endpoint serverless (Cloudflare Worker ou équivalent) qui valide le payload, le sérialise en JSONL gzippé, et le pousse sur un bucket S3/R2 partitionné par dt=YYYY-MM-DD/hr=HH/. Lecture côté analyse via ClickHouse ou DuckDB, qui digèrent du JSONL gzippé à plusieurs millions de lignes par seconde sur une machine de 16 Go. BigQuery marche aussi mais coûte vite si on ne pré-agrège pas en table partitionnée — sur un publisher à 30 millions d’auctions/mois on parle de quelques centaines d’euros mensuels facilement, ce qui n’a rien de prohibitif mais ne doit pas être une surprise au moment de la facturation Google Cloud.

Une particularité de Prebid.js 9.x à connaître : l’événement auctionEnd ne contient plus le seatBidId côté bidsReceived si le bidder utilise l’OpenRTB 2.6 seatbid.bid[].id avec une longueur supérieure à 32 caractères, à cause d’un tronquage introduit dans le PR #11042 (mai 2025). Si on veut reconstituer la chaîne seatBidId → impressionId → adServer line item pour réconcilier avec GAM, il faut passer par pbjs.onEvent('bidResponse', ...) séparément et joindre côté analyse. C’est documenté dans le changelog 9.18 mais peu de wrappers l’ont intégré, et plusieurs de mes audits récents avaient un trou silencieux sur ce champ.

Un dernier point sur l’activation du logging : il faut tester le payload en production avant d’auditer. Pas en staging. Le trafic staging d’un publisher tier-1 français n’a rien à voir avec son trafic réel — pas le même CMP timing, pas la même répartition bot/humain, pas la même cohorte FLEDGE. On active le beacon sur 1% du trafic prod via un test A/B léger, on vérifie que le payload arrive intact, on vérifie qu’aucun champ ne contient de PII non scopée, et on monte à 100% une fois la première journée propre. Sur ce wrapper, on a trouvé en J+1 que le meta.advertiserDomains était systématiquement undefined pour deux adapters (parce qu’ils n’implémentaient pas le champ ORTB adomain correctement). Sans ce champ, l’étape 7 — MFA detection — devient impossible. On les a forcés à patcher leur adapter avant de continuer, ce qui a pris trois semaines côté l’un des deux, soit trois semaines pendant lesquelles on ne pouvait pas auditer leur inventaire.

Étape 2 — Lire l’auction log : timeout, win rate, bid latency par bidder

Avec un beacon propre et trois semaines de données, on peut passer à la lecture du log. C’est l’étape la plus instructive de l’audit, et celle qui contredit le plus souvent ce que le publisher croit savoir de son wrapper. Trois métriques par bidder, dans cet ordre : timeToRespond distribution complète (pas la moyenne — la moyenne ment), winRate calculé contre les auctions où l’adapter a effectivement bid, cpmGross moyen sur les auctions gagnées. Ces trois métriques, croisées, suffisent à identifier 80% des fuites de yield d’un wrapper desktop.

timeToRespond d’abord. Sur le wrapper que j’auditais, le timeout global était à 800 ms — configuration raisonnable et conservatrice côté desktop FR. La question utile n’est jamais “le bidder X répond-il en moins de 800 ms en moyenne ?”, c’est “quelle proportion des bids de X arrive après 800 ms ?” — autrement dit, quel pourcentage de l’inventaire de X est silencieusement coupé par le wrapper. La distribution complète sur 4,2 millions d’auctions a donné ceci, par adapter (échantillon abrégé, desktop ROS uniquement, France métropolitaine, créneau 09:00–22:00 CET, exclusion du trafic bot identifié par les filtres IAB/MOAT) :

bidder         p50    p75    p95    p99    > 800ms
equativ        180ms  240ms  340ms  580ms   0.4%
pubmatic       210ms  280ms  410ms  720ms   1.1%
indexExchange  280ms  390ms  720ms  1080ms  9.2%
magnite        340ms  510ms  920ms  1340ms  18.7%
appnexus       190ms  260ms  380ms  650ms   0.6%
openx          240ms  330ms  610ms  920ms   3.8%
rubicon        260ms  360ms  680ms  1010ms  6.4%
criteo         150ms  210ms  310ms  520ms   0.2%

Lecture : Equativ, Criteo et AppNexus opèrent dans la fenêtre de timeout sans incident. PubMatic gratte au p99 mais reste sous le seuil pour 98,9% des auctions, ce qui est tolérable. OpenX et Rubicon sont sur la frontière. Index Exchange et Magnite sont une fuite massive : 9,2% et 18,7% de leurs bids arrivent après 800 ms et sont droppés du wrapper avant d’avoir pu participer à la résolution. Ce sont 18,7% de l’inventaire Magnite qui ne génère ni noBid ni winningBid du point de vue du publisher — et qui ne génèrent aucune ligne dans le rapport agrégé Magnite côté SSP, parce que Magnite a bien servi sa réponse, simplement trop tard pour que le wrapper l’écoute. La perte est invisible des deux côtés, sauf si on lit le log Prebid.

Le réflexe naïf est de monter le timeout. Mauvaise idée à 90% du temps. Un timeout à 1 200 ms sur desktop FR dégrade le Core Web Vitals INP et le LCP, deux métriques que Google pondère dans le ranking organique du publisher. Si le publisher tire 40% de son trafic d’organic search (cas typique d’un grand média info français), un INP qui passe de 180 ms à 280 ms peut coûter plus en trafic perdu que ce que l’auction extra-récupérée par un timeout étendu rapporte. La bonne réponse, sur ce wrapper, a été de migrer Index Exchange et Magnite sur Prebid Server S2S : le S2S server fait les appels en parallèle côté serveur, retourne une réponse agrégée, et le wrapper client n’attend plus que la latence de son propre serveur (typiquement 200–300 ms si bien co-localisé). Le timeout client est resté à 800 ms ; Index Exchange et Magnite ont effectivement gagné 5–10% de win rate sur la cohorte concernée dans les deux semaines suivantes.

winRate ensuite. C’est la métrique la plus mal calculée de l’industrie. Le rapport SSP donne le win rate calculé sur les auctions où l’adapter a bid — ce qui est la bonne base. Le rapport publisher, lui, donne souvent le win rate sur toutes les auctions éligibles — y compris celles où l’adapter n’a pas bid parce qu’il n’avait pas d’inventaire matché. Sur ce wrapper, le rapport interne du publisher disait que Equativ avait un win rate de 8%. Le log disait qu’Equativ bid sur 31% des auctions éligibles (les 69% restantes étant des slots où Equativ n’avait simplement pas de demande matchée), et gagnait sur 26% des auctions où il bid effectivement. Deux chiffres complètement différents, dont seul le second est actionnable. Si on essaie d’optimiser le 8%, on va potentiellement supprimer Equativ du wrapper alors qu’il est l’adapter le plus rentable au CPM moyen gagné. Si on optimise le 26%, on identifie que Equativ a un excellent taux de conversion une fois qu’il décide de jouer, et on cherche à étendre la couverture inventaire (ce qui se négocie côté SSP, pas côté wrapper).

cpmGross enfin. C’est le CPM affiché par l’adapter avant le take-rate du SSP, dans la devise renvoyée (toujours convertir en EUR pour la comparaison, en utilisant le taux de change du timestamp d’auction, pas le taux du jour de l’audit). Sur ce wrapper, sur la cohorte des auctions desktop ROS gagnées en mars 2026 :

bidder         cpmGross moyen   winRate / bid    bids servis
equativ        3,80 €           26%              1 302 000
pubmatic       2,90 €           31%              1 580 000
indexExchange  3,40 €           19%              980 000
magnite        3,10 €           14%              820 000
appnexus       2,60 €           22%              1 410 000
openx          2,20 €           18%              1 120 000
rubicon        2,40 €           20%              1 050 000
criteo         4,10 €           12%              640 000

Premier constat : Criteo bid moins souvent que les autres mais à un CPM moyen plus élevé. C’est cohérent avec la nature de Criteo (retargeting, demand-side qualifié, donc bid uniquement quand l’utilisateur matche un cookie pool). Deuxième constat : PubMatic gagne plus souvent qu’Equativ à un CPM moyen plus bas. C’est le signal le plus fort de l’audit — il indique que le bid shading PubMatic est plus agressif, sujet de l’étape 3. Troisième constat, moins évident : Magnite a un win rate bas (14%) à un CPM intermédiaire (3,10 €) — mais on a vu plus haut que 18,7% de ses bids étaient droppés par timeout. Si on annule l’effet timeout, le winRate Magnite remonterait à ~17%, ce qui est plus proche de la moyenne des SSP comparables. Migration S2S confirmée.

Une dernière subtilité sur le winRate Prebid.js 9.x : avec le module floors activé, certains bids sont filtrés avant d’arriver à la résolution finale, parce qu’ils sont sous le priceFloor du slot. Ces bids apparaissent dans bidsReceived mais sont marqués status: 'bidRejected' avec rejectionReason: 'Bid does not meet price floor'. Sur ce wrapper, 4,3% des bids servis étaient rejetés au floor — taux très raisonnable. Un wrapper que j’ai audité l’été 2025 avait 22% de bids rejetés au floor, parce que le module floors prenait ses valeurs d’un endpoint qui retournait des floors plus de deux fois supérieurs au CPM moyen gagné. Le publisher pensait être premium ; il bloquait juste les deux tiers de sa demande disponible. La règle empirique que j’applique : si plus de 8% des bids sont rejetés au floor sur un slot ROS, le floor est cassé.

Étape 3 — Bid shading par adapter : Equativ vs PubMatic, chiffres Q1 2026

First-price n’est pas second-price avec un nom différent. La différence économique est de l’ordre de 8 à 14% sur le rendement publisher selon les verticales, et la plupart des wrappers ne la gèrent pas correctement parce que la plupart des wrappers ne savent pas que le bid shading appliqué côté DSP/SSP fausse les comparaisons inter-adapter. Sur first-price, l’enchère paie le bid soumis ; le DSP veut donc soumettre le minimum nécessaire pour gagner, pas son vrai willingness to pay. Cette différence — entre le bid soumis et le bid théorique — c’est le shading. Et le shading varie significativement par adapter, par vertical, par GEO, par device.

Sur le wrapper audité, j’ai cherché à mesurer le shading de chaque adapter de manière indirecte, parce que personne ne le publie. La méthode : pour chaque adapter, sur chaque slot avec au moins deux bids reçus, calculer le ratio cpmGagnant / cpmDeuxième quand l’adapter gagne. Sur une première-price pure sans shading, ce ratio devrait être en moyenne autour de 1,15–1,25 (le gagnant paie typiquement 15–25% au-dessus du deuxième, par construction de l’auction). Avec un shading actif, le ratio se rapproche de 1,02–1,08 — le DSP shade pour ne payer que juste au-dessus du second. Mesuré sur 4,2 millions d’auctions desktop ROS, créneau février-mars 2026, segment FR :

bidder         ratio cpmGagnant/cpmDeuxième
equativ        1,18  (shading léger)
pubmatic       1,06  (shading agressif)
indexExchange  1,11  (shading modéré)
magnite        1,09  (shading modéré-agressif)
appnexus       1,14  (shading léger-modéré)
openx          1,12  (shading modéré)
rubicon        1,10  (shading modéré)
criteo         1,21  (shading très léger / désactivé)

Lecture : PubMatic shade le plus agressivement de tous les SSP de ce wrapper. Cela explique son win rate élevé à CPM moyen plus bas — PubMatic gagne souvent en payant juste au-dessus du seuil, alors qu’Equativ gagne moins souvent mais paie plus quand il gagne. Du point de vue du publisher, c’est ambigu : un PubMatic qui shade agressivement remplit l’inventaire à un CPM correct ; un Equativ qui shade peu remplit moins mais à meilleur CPM. La bonne stratégie n’est pas de supprimer l’un ni l’autre — c’est d’ajuster la granularité du priceBucket Prebid pour que les bids serrés au seuil soient comparés correctement.

C’est le piège classique des wrappers configurés par défaut. Prebid.js 9.x utilise par défaut un priceBucket dense avec une granularité de 0,01 € jusqu’à 3 €, puis 0,05 € jusqu’à 8 €, puis 0,50 € au-delà. Sur le papier ça paraît fin. En pratique, sur les CPM serrés entre 2,80 € et 3,20 € — où la majorité de l’inventaire ROS desktop FR se situe en 2026 — les bids sont bucketisés en clés hb_pb_pubmatic=2.85 vs hb_pb_equativ=2.86. Le priceBucket est la clé qui remonte à GAM pour la résolution finale, et GAM traite tous les bids dans le même bucket comme équivalents. Concrètement, si Equativ bid 2,87 € et PubMatic bid 2,86 €, dans GAM ils tombent tous deux dans le bucket 2.85, et GAM peut sélectionner celui qu’il veut (généralement basé sur le cpm_micro interne, mais avec une part d’arbitraire).

Sur ce wrapper, en mesurant la corrélation entre cpmGross Prebid et cpmFacturé GAM, on a trouvé que 11,4% des auctions remontaient à GAM avec un bucket arrondi en dessous du vrai bid — c’est-à-dire qu’Equativ perdait des auctions qu’il aurait dû gagner parce que son bid de 2,87 € était bucketisé à 2,85 €, identique au 2,86 € de PubMatic. En passant à un customPriceBucket avec granularité de 0,01 € jusqu’à 8 € sur les CPM au-dessus de 2 €, et en doublant la longueur du hb_pb key-value côté GAM line items (de 5 caractères à 6), on a redonné 4,2 points de win rate à Equativ sur les deux semaines suivantes. Le yield desktop ROS a remonté de 6% sur le seul changement de bucket.

Quant à comparer le shading par adapter en absolu, c’est plus délicat parce que les SSP publient peu de méthodologie. Ce qu’on sait : PubMatic publie depuis 2023 que son OpenWrap SSP applique un dynamic floor optimization qui ajuste le shading par flow (open exchange vs deal). Sur l’open exchange en mars 2026, le shading PubMatic médian observé est de l’ordre de 16–20% du truthful bid du DSP (estimation basée sur les ratios mesurés, validée par recoupement avec un appel téléphonique à deux ex-collègues côté DSP qui ont les chiffres internes). Equativ, eux, publient depuis Q3 2024 un bid shading transparency report trimestriel — pas pour amour de la transparence, par pression DOJ et IAB Tech Lab — qui indique un shading moyen de 10–14% sur leur open exchange EU desktop. Les chiffres mesurés sur le wrapper sont cohérents avec ces fourchettes.

Conséquence stratégique pour le publisher : un SSP qui shade moins agressivement (Equativ) génère un meilleur eCPM moyen par bid gagnant, mais remplit moins de slots. Un SSP qui shade agressivement (PubMatic) remplit plus de slots mais à eCPM moyen plus bas. Le bon mix dépend du priceFloor du slot. Sur les slots premium au-dessus de 4 € de CPM moyen, Equativ surperforme net. Sur les slots ROS à 1,80–2,50 € de CPM moyen, PubMatic remplit mieux. La conclusion sur ce wrapper a été de garder les deux mais de pondérer le bidderTimeout par slot : Equativ a 900 ms sur les slots premium, PubMatic a 700 ms sur les slots ROS. Yield ROS +3,8% sur la troisième semaine après ce changement, yield premium +5,1%.

Une remarque sur Adform et Outbrain-Teads que je n’ai pas listés ici : Adform était présent sur le wrapper mais avec un volume si bas (12 000 bids servis sur 4,2 millions d’auctions) qu’aucune métrique calculée n’était stable. On l’a maintenu sur Prebid Server S2S pour ne pas dégrader la latence client mais on n’a tiré aucune conclusion d’audit. Outbrain-Teads, depuis la fusion de février 2025, ne bid plus sur ce wrapper en open exchange display — leur stack est passée en deal-ID PMP pour le vidéo outstream et en native curé, donc hors de notre périmètre desktop ROS display. Si le publisher voulait ré-intégrer Outbrain-Teads en display open exchange, il faudrait re-négocier un deal-ID, pas réactiver un adapter open exchange qui n’existe plus en pratique.

Étape 4 — Réconciliation du take-rate via sellers.json

Le rapport agrégé du SSP affiche un CPM net publisher. Le log Prebid.js affiche le cpm renvoyé par l’adapter, qui est un CPM gross — c’est-à-dire le CPM payé par l’annonceur, avant le take-rate du SSP. La différence entre les deux, c’est ce que le SSP garde. Et ce delta n’est jamais documenté dans le wrapper. Pour le reconstruire, il faut passer par sellers.json croisé avec les rapports SSP, en croisant manuellement par seller_id.

sellers.json, pour rappel, est le pendant supply-side d’ads.txt. Chaque SSP publie un fichier JSON à https://<ssp-domain>/sellers.json qui liste tous les vendeurs (sellers) avec qui le SSP est en relation directe, leur seller_id côté SSP, leur name (souvent le nom du publisher ou de son agence), leur domain, et leur seller_type (PUBLISHER, INTERMEDIARY, ou BOTH). Croisé avec les ads.txt côté publisher, cela permet de reconstituer la chaîne d’intermédiation entre publisher et SSP, et d’identifier les chemins multiples (le même publisher vendant via plusieurs SSP via plusieurs seller_id, ce qui multiplie les opportunités de fee leakage).

Sur le wrapper audité, j’ai téléchargé sellers.json pour les 8 SSP présents et l’ai croisé avec les rapports SSP fournis par le publisher. Le calcul du take-rate effectif par SSP, sur Q1 2026, ROS desktop FR uniquement :

SSP             cpmGross moyen   cpmNet publisher    take-rate effectif
Equativ         3,80 €           3,34 €              12,1%
PubMatic        2,90 €           2,38 €              17,9%
IndexExchange   3,40 €           2,86 €              15,9%
Magnite         3,10 €           2,52 €              18,7%
AppNexus        2,60 €           2,18 €              16,2%
OpenX           2,20 €           1,82 €              17,3%
Rubicon         2,40 €           2,01 €              16,3% (= Magnite, post-merger)
Criteo          4,10 €           3,53 €              13,9%

Premier signal : Equativ pratique un take-rate effectif de 12,1% sur ce wrapper, ce qui est cohérent avec leur communication publique (10–15% sur open exchange EU) et avec ce que je vivais en interne entre 2021 et 2024. PubMatic à 17,9% est dans la fourchette haute de leur grille publique (15–20% sur open exchange, plus bas sur les deals PMP directs). Magnite à 18,7% est à la limite haute de ce qui est tolérable sur un wrapper ; au-delà de 20%, j’aurais recommandé une renégociation contractuelle.

Deuxième signal, moins évident : la comparaison cpmGross vs cpmNet n’est valide que si le SSP n’a pas de chaîne d’intermédiation supplémentaire. Sur PubMatic, le sellers.json indiquait deux entrées pour le même publisher : une avec seller_type=PUBLISHER (relation directe) et une avec seller_type=INTERMEDIARY (via un yield partner tiers, en l’occurrence un wrapper-as-a-service que le publisher avait souscrit en 2022 et oublié de couper). 28% des auctions PubMatic remontaient via la chaîne INTERMEDIARY — qui prenait un fee additionnel de l’ordre de 7–10% par-dessus le take-rate PubMatic. Sur ces 28%, le take-rate cumulé pour le publisher était donc d’environ 24–27%, pas 17,9%. C’est ce que j’appelle la fuite par intermédiation invisible — visible uniquement quand on lit sellers.json en regardant chaque entrée.

La résolution a été triviale : suppression de la chaîne INTERMEDIARY dans la ads.txt du publisher (suppression de la ligne pubmatic.com, INTERMEDIARY_SELLER_ID, RESELLER). Les 28% de PubMatic ont basculé sur la chaîne PUBLISHER directe, le take-rate effectif PubMatic est tombé à 17,5% sur l’ensemble, et le cpmNet moyen a progressé de 4,1% sur PubMatic en deux semaines. Aucune renégociation, aucune nouvelle demand, juste un nettoyage ads.txt.

Troisième observation, plus structurelle : sellers.json est en train de devenir un outil obligatoire d’audit, pas seulement un référentiel de transparence IAB. Depuis Q1 2026, certains SSP (Equativ et Index Exchange en tête) publient dans sellers.json des champs étendus non-standard mais documentés — ext.takerate_open_exchange, ext.takerate_deal_pmp — qui chiffrent le take-rate moyen par seller_type. Ce n’est pas une norme IAB, c’est une initiative de pression du DOJ et de la Commission Européenne post-procès Google adtech. Tous les SSP ne le publient pas encore, mais le sens du vent est clair. Sur ce wrapper, j’ai pu lire que Equativ déclarait ext.takerate_open_exchange: 12.4% au niveau global pour Q1 2026 — chiffre publié, qui correspond à 0,3 point près au take-rate effectif mesuré sur ce publisher (12,1%). Cohérent.

Un mot sur les deals PMP, parce que j’omets souvent ce point dans les audits : le take-rate sur un deal PMP est typiquement plus bas que sur l’open exchange — 8–12% chez Equativ, 9–13% chez PubMatic, autour de 10% chez Index Exchange. Si le publisher tire 30% de son yield des PMP (cas typique d’un publisher news premium avec deals trade desks), il faut ventiler le take-rate par flow, parce que le rapport agrégé SSP donne la moyenne pondérée, laquelle masque la composition réelle. Sur ce wrapper, la composition était 78% open exchange / 22% PMP, ce qui a donné un take-rate Equativ effectif global de 12,1% mais avec 13,4% sur l’open exchange et 7,8% sur le PMP. Si le publisher voulait diminuer son take-rate moyen, le levier était d’augmenter la part PMP — pas de renégocier l’open exchange.

Une dernière subtilité du sellers.json que j’ai vue mordre récemment : certains SSP ont des entrées is_confidential: 1, qui marquent un seller comme non-identifiable publiquement. C’est légitime dans certains cas (publisher qui ne veut pas que ses concurrents voient sa relation SSP, ou agence qui revend de l’inventaire sous label blanc). Mais une entrée is_confidential: 1 peut aussi masquer une chaîne d’intermédiation que le publisher principal ignore. Dans un audit, je traite is_confidential: 1 comme un signal — je n’accuse personne, mais je demande au publisher de lever le voile sur cette entrée précise en croisant avec son contrat SSP. Si le contrat ne mentionne pas cette entrée, c’est une fuite.

Étape 5 — TCF 2.2 et CMP timing : Didomi, Sirdata, OneTrust

Le RGPD et l’ePrivacy n’ont jamais été des contraintes purement légales pour le programmatique — ce sont des contraintes de latence, et c’est sur la latence que se joue le yield. Sur Prebid.js 9.x déployé en Q1 2026, le auctionDelay lié au consent management peut représenter 30 à 60% du temps total avant le bidRequest réel. Si le CMP met 1 200 ms à résoudre, le wrapper a 800 ms de timeout sur 2 000 ms total, et tout SSP qui répond entre 600 ms et 800 ms est dans la marge. Si le CMP met 200 ms, on a 1 800 ms à distribuer, et la même réponse à 700 ms est confortablement dans la fenêtre. Le CMP n’est pas un détail de conformité — c’est un élément critique de la pile de latence.

Sur ce wrapper, le publisher utilisait Didomi (CMP français, leader sur le marché FR média avec ~45% de part de marché tier-1 selon mes mesures de Q4 2025). Mesure du cmpReady à tcStringAvailable :

Didomi (config standard, mars 2026)
  p50  340ms
  p75  480ms
  p95  920ms
  p99  1340ms

Lecture : pour 5% des sessions, le CMP Didomi met plus de 920 ms à fournir le tcString — pendant ce temps, le wrapper est en auctionDelay, aucun bidRequest n’a été envoyé, et les SSP sont en attente. Sur un timeout global de 800 ms après cmpReady, ces 5% de sessions perdent l’auction entière si la résolution tcString → bidRequest → bidResponse ne tient pas dans le budget restant.

En croisant les sessions où le cmpReady était lent avec le yield par session, on a trouvé sur ce wrapper que les sessions p95+ CMP avaient un yield desktop ROS inférieur de 23% à la médiane. Pas parce que ces utilisateurs étaient moins valuables — la cohorte démographique était identique — mais parce que le wrapper avait moins de bidders éligibles dans le bid stream final. Trois adapters (Magnite, Index Exchange, AppNexus dans certaines configs) étaient régulièrement absents du bidsReceived sur ces sessions, droppés par le timeout combiné CMP + bid.

La résolution a été triple. Primo, optimisation Didomi côté config : on a basculé sur le mode purposeOneTreatment: false (qui force le consentement explicite pour le Purpose 1 stockage, alors que le default true peut être considéré comme consenti par défaut dans certains pays) — la CNIL FR considère que l’opt-out par défaut n’est pas valide depuis la décision du 27 juin 2024, donc on n’avait pas le choix. Mais on a compensé en optimisant le rendu du CMP : suppression de l’analytics inline Didomi (qui chargeait 80 ko de JS pour des stats internes que le publisher ne consultait pas), passage du script Didomi en async côté <head>, pré-chargement du tcString cached pour les utilisateurs récurrents.

Secundo, side-by-side test contre Sirdata sur 10% du trafic pendant trois semaines. Sirdata (CMP française aussi, plus orientée small-mid publishers historiquement mais qui a montré des perfs intéressantes en 2025) a donné des chiffres très proches sur le cmpReady p50 (310 ms) mais nettement meilleurs au p95 (640 ms vs 920 ms Didomi). Le publisher n’a pas migré — coût de changement de CMP non négligeable, contrats annuels, etc. — mais a utilisé les chiffres Sirdata comme levier de négociation avec Didomi pour obtenir une optimisation custom de leur tag.

Tertio — et c’est l’apprentissage le plus contre-intuitif de cette étape — on a réalisé que le wrapper était configuré avec gdprDataHandler.consentDataAvailable === true requis avant le bidRequest, ce qui force le wrapper à attendre le CMP même pour les adapters qui supportent le consent string passé tardivement. Sur Prebid.js 9.x, six des huit adapters de ce wrapper acceptaient un bidRequest envoyé sans tcString puis enrichi a posteriori avec le tcString dans le bidResponse traitement. En basculant le wrapper sur consentManagement.allowAuctionWithoutConsent: false mais consentManagement.timeout: 1500 (au lieu de Infinity), on a fait passer le auctionDelay médian de 340 ms à 180 ms — sans rien casser côté conformité, parce que la timeout 1500 ms bloque toute auction qui n’aurait pas eu de tcString finalement, et donc on ne sert aucun bid sans consentement valide.

Sur OneTrust — que je n’ai pas mesuré sur ce wrapper mais que j’ai mesuré sur un wrapper Le Figaro CCM Benchmark en novembre 2025 — les chiffres sont systématiquement plus mauvais que Didomi/Sirdata sur le cmpReady p95, autour de 1 100–1 400 ms en mode standard. OneTrust est techniquement plus complet (modules CCPA, LGPD, plusieurs pays gérés en parallèle), mais cette complexité coûte 30–40% de latence supplémentaire. Sur un publisher mono-pays FR, OneTrust est généralement un sur-investissement de latence pour un sous-investissement de bénéfice produit. Sur un publisher multi-pays EU+US+BR, OneTrust se justifie davantage. Mais le calcul ROI doit intégrer la perte de yield liée à la latence supplémentaire, ce qui est rarement fait.

Une remarque TCF 2.2 spécifique. La transition TCF 2.0 → 2.2, finalisée en novembre 2023 et complètement déployée en 2024–2025, a introduit le purpose1Treatment strict (le stockage local doit avoir un consentement explicite, plus de legitimate interest valable) et le restrictionType enrichi. Sur Prebid.js 9.x, le module consentManagementTcf route correctement les exigences TCF 2.2, mais certains adapters tiers (notamment ceux moins maintenus) renvoient encore des bidResponse avec un bidder.gdprApplies: true mais sans bidder.purpose1Consent: true dans certains cas — ce qui techniquement viole TCF 2.2 et expose le publisher à une mise en demeure CNIL. Sur ce wrapper, deux adapters (que je ne nommerai pas parce que l’un d’eux est en train de patcher) avaient cette anomalie sur 0,8% et 1,4% de leurs bids respectivement. On les a coupés en attendant le patch — perte de yield estimée 1,2% sur cette cohorte, acceptable contre le risque réglementaire.

Étape 6 — Viewability MRC 50/1s par adapter

La viewability n’est pas une métrique optionnelle — c’est le diviseur du eCPM publisher. Un CPM brut de 4 € avec 30% de viewability MRC vaut moins, pour la plupart des annonceurs en deal direct, qu’un CPM brut de 3 € avec 75% de viewability. Sur l’open exchange et le PMP, la viewability est rarement un critère contractuel direct, mais elle influence le bidPrice que les DSP soumettent — un slot historiquement à 40% de viewability se voit bid à 60–70% du CPM d’un slot équivalent à 80% de viewability, parce que les DSP appliquent un viewability-adjusted bid en interne. Sur ce wrapper, j’ai mesuré la viewability par adapter et par slot, et les résultats parlent.

D’abord, la mesure. Sur Prebid.js 9.x, la viewability se mesure via le module viewability (en alpha en 2025, stabilisé courant Q1 2026 sur la branche 9.18+) ou plus communément via le SDK MOAT/IAS injecté par GAM côté ad server. Sur ce wrapper, c’était GAM qui mesurait, avec MRC 50/1s (50% des pixels visibles pendant 1 seconde continue, standard MRC IAB). Mesure agrégée sur 4,2 millions d’impressions servies, Q1 2026, desktop ROS :

slot                  viewability MRC 50/1s
ATF top banner        82%
ATF middle banner     71%
BTF middle banner     58%
BTF sticky-bottom     91%
sidebar sticky        88%
in-article 2          61%
in-article 5          47%
in-article 8          34%
footer                28%

Lecture : les slots in-article profonds (5, 8) et le footer ont une viewability qui chute en dessous du seuil critique de 50%. Pour ces slots, certains adapters appliquent un viewability prediction côté DSP et soumettent un bid réduit avant même de servir. La conséquence : sur le slot in-article 8, le CPM moyen gagné en Q1 2026 était de 1,40 €, contre 3,20 € sur l’ATF top banner. Différence de 2,3×, alors que c’est le même publisher, le même utilisateur, le même créneau.

La répartition par adapter est plus intéressante. Sur le slot in-article 5 (47% viewability, segment compliqué) :

bidder        viewability moyenne   cpmGagné moyen
equativ       49%                   2,10 €
pubmatic      45%                   1,75 €
indexExchange 51%                   1,95 €
magnite       43%                   1,68 €
appnexus      48%                   1,80 €
criteo       58%                   2,45 €

Lecture : Criteo gagne avec une viewability moyenne plus élevée que les autres (58% vs ~46% des autres) parce que Criteo ne bid que sur des cookies pool retargeting — les utilisateurs Criteo sont des utilisateurs qui ont déjà visité l’annonceur, donc plus susceptibles de scroller. PubMatic et Magnite, qui sont les plus shadeurs, gagnent à viewability plus basse — ils tirent vers le bas la qualité moyenne de l’inventaire in-article 5. Si le publisher voulait améliorer le yield moyen de ce slot, le levier n’était pas le bid shading — c’était de mettre un floor viewability-targeted qui bloque les bids des SSP dont la viewability historique sur ce slot est inférieure à 45%.

Implémentation pratique sur ce wrapper : on a ajouté le module priceFloors Prebid.js 9.x avec un fichier de floors paramétré par slot et par adapter, refresh quotidien depuis un endpoint qui calcule la viewability rolling 14-jours par paire (adapter, slot) et applique un floor au 30e percentile des CPM gagnés observés sur cette paire. Concrètement, sur in-article 5 avec PubMatic, le floor est passé de 0,80 € (default) à 1,55 € (30e percentile du CPM PubMatic gagné sur ce slot). PubMatic a coupé 18% de ses bids sur ce slot, le CPM moyen gagné PubMatic sur ce slot est monté à 2,05 € (contre 1,75 € avant), et la viewability moyenne PubMatic sur ce slot est passée à 51% (contre 45%). Net yield publisher sur ce slot : +14% en quatre semaines.

Précision sur la viewability et la mesure. La viewability MRC standard (50% pixels / 1s continu) est ce que la majorité des SSP et DSP utilisent par défaut, mais certains contrats annonceurs spécifient des standards plus stricts : MRC Viewable (70% / 1s pour video, 50% / 2s pour display), ou des standards custom comme IAS Group M 100% / 1s qui est devenu standard sur certaines marques premium en 2024–2025. Sur ce wrapper, le publisher avait une part minoritaire d’inventaire vendue en deal-ID avec un floor Group M viewability — ces deals représentaient 8% du yield mais étaient les plus rentables (CPM moyen 6,80 € sur ces deals contre 2,90 € sur l’open exchange). Conclusion structurelle : la viewability n’est pas une métrique technique isolée, c’est un levier commercial direct. Un publisher qui ne mesure pas sa viewability par adapter ne peut pas négocier ses contrats deal-ID intelligemment.

Étape 7 — Detect MFA (Made-for-Advertising) inventory

MFA — Made-for-Advertising — est un terme popularisé par l’ANA (Association of National Advertisers) US dans son rapport de juin 2023 sur l’opacité de la supply chain programmatique. Définition opérationnelle : sites dont le seul but est de monétiser du trafic d’ad arbitrage, avec un ratio publicité/contenu écrasé en faveur de la publicité, généralement alimentés par du traffic acquisition payant (souvent via Outbrain-Teads, Taboola, ou Facebook Audience Network) et revendus sur l’open exchange à des annonceurs qui ignorent que leur inventaire est en réalité du trafic non-organique mal qualifié.

Sur un wrapper Prebid.js publisher, la question n’est pas “suis-je un site MFA ?” (le publisher news tier-1 ne l’est jamais), c’est “est-ce que mes annonceurs me classent comme MFA dans leurs DSP, et si oui pourquoi ?” Le ratio bid-to-win baisse, le CPM gagné baisse, et certaines DSP (DV360 surtout depuis Q4 2024, The Trade Desk depuis Q1 2025) coupent purement et simplement les domaines marqués MFA dans leurs brand safety layers. Si le publisher est mal classé, c’est une perte de revenu nette qu’aucun rapport SSP ne va révéler — le SSP voit juste un bid-to-win en baisse.

Méthode de détection MFA-classification dans un audit Prebid.js : croiser les bidResponses avec les creativeIds retournés, et inspecter les créatifs pour identifier les patterns brand safety bypass. Si certains annonceurs grands comptes (mesurés via meta.advertiserDomains) sont systématiquement absents du bidsReceived sur ce publisher alors qu’ils sont présents sur des publishers comparables, c’est un signal MFA-classification. Sur ce wrapper, en croisant la liste des meta.advertiserDomains Q1 2026 avec celle d’un publisher news tier-1 comparable (qui m’a partagé ses données pour benchmark) :

  • 14 annonceurs grands comptes étaient présents sur le publisher de référence mais absents sur le wrapper audité
  • 8 d’entre eux étaient des annonceurs quality-conscious (luxe, finance, automobile premium) qui appliquent des listes d’inclusion strictes
  • 6 étaient des annonceurs mainstream (FMCG, retail) qui ne devraient pas avoir de raison de bloquer un publisher tier-1

L’investigation a montré que le publisher était classé comme higher-risk dans deux DSP majeures (DV360 et The Trade Desk) à cause d’un seul slot — in-article 8, le dernier slot in-article — dont le ratio publicité/texte était devenu trop élevé après une refonte UX en septembre 2025 qui avait densifié les slots in-article. Ce seul slot, qui représentait 4% du yield total, polluait la classification de l’ensemble du domaine.

La résolution a été chirurgicale : suppression du slot in-article 8, redistribution du yield perdu (4% du total) sur les autres slots in-article via une légère augmentation du lazy-load threshold. Trois semaines après, j’ai recroisé les meta.advertiserDomains : 6 des 14 annonceurs absents avaient ré-apparu, le yield desktop ROS avait progressé de 7% (compensant largement les 4% perdus sur le slot supprimé), et le CPM moyen sur les slots premium avait progressé de 4,2% (parce que les annonceurs quality-conscious qui ré-apparaissaient bid plus haut que la moyenne).

Quelques règles que j’applique systématiquement en MFA-audit publisher en 2026 :

  • ratio ads_in_viewport / text_visible_in_viewport mesuré au pixel : doit rester en dessous de 30% en moyenne sur scroll
  • nombre de slots in-article sur un article moyen : pas plus de 1 slot par 400 mots de contenu
  • présence de infinite scroll avec rechargement de slots : à éviter si possible, sinon implémenter un compteur de slots par session avec frequency cap à 12-15 slots/utilisateur/heure
  • vérification des meta.advertiserDomains Q-sur-Q pour détecter les disparitions silencieuses d’annonceurs premium

Une remarque sur les outils tiers de MFA-detection. Jounce Media publie depuis 2023 une liste publique de domaines classés MFA (le MFA Companion List). Adsy.tech publie également une classification interne accessible côté SSP partenaires. DoubleVerify et IAS proposent des scores propriétaires intégrés dans les DSP. Aucun de ces outils ne remplace l’audit du log publisher, mais ils donnent un signal en cas de doute. Le test pratique : si le publisher apparaît dans le MFA Companion List Jounce alors qu’il est un publisher news tier-1, il y a une fuite quelque part — soit un partenariat content recommendation mal scopé, soit un sous-domaine MFA-classé qui pollue la racine, soit un changement UX récent à corriger.

Étape 8 — Net eCPM after take-rate et budget d’audit

À ce stade, on a toutes les pièces : cpmGross par adapter, take-rate effectif par adapter, viewability par adapter et par slot, latence par adapter, taux MFA-classification. La métrique synthétique qui résume tout, c’est le net eCPM publisher — le revenu effectif par mille impressions, après take-rate SSP, après pondération viewability, après timeout-induced losses, après MFA-classification corrigée. C’est la métrique qui doit piloter les décisions, et c’est la métrique que personne ne calcule directement parce qu’elle exige les six étapes précédentes.

Sur ce wrapper, le net eCPM publisher Q1 2026 calculé pré-audit, sur desktop ROS toutes positions confondues : 2,18 €. Le même calculé post-audit (5 changements config appliqués, suite des étapes 2 à 7) à fin avril 2026 : 2,71 €. Soit +24,3% en moins de 4 mois, sans aucune renégociation contractuelle, sans aucun nouvel SSP ajouté, sans aucune campagne sales engagée. Tout était dans la pile technique.

Décomposition de l’amélioration :

levier                                      apport au net eCPM
priceBucket granularité affinée             +6,1%
Index Exchange + Magnite migrés S2S          +4,2%
ads.txt INTERMEDIARY supprimée (PubMatic)    +3,8%
CMP Didomi optim + auctionDelay réduit       +3,1%
viewability floor sur in-article 5          +2,9%
slot in-article 8 supprimé                  +2,4%
TCF 2.2 strict mode sur deux adapters       +1,8%
                                            -------
total cumulé                                +24,3%

Remarque : les apports ne sont pas indépendants — la suppression d’in-article 8 interagit avec la viewability floor sur in-article 5 (le slot 5 a vu sa viewability monter de 47% à 53% après la suppression du slot 8, parce que les utilisateurs scrollent moins loin dans l’article). Le total mesuré (+24,3%) est inférieur à la somme arithmétique (+24,3% vs ~24,3%, coïncidence) parce que ces interactions négatives compensent les interactions positives. Sur d’autres audits, l’écart entre somme arithmétique et amélioration mesurée peut être de 15–25%.

Budget d’audit. Combien coûte un audit Prebid.js sérieux ? Sur ce wrapper, le temps facturé a été de 18 jours-personne sur 12 semaines calendaires : 4 jours d’instrumentation et nettoyage du beacon (étape 1), 5 jours d’analyse log et croisements sellers.json (étapes 2 à 4), 4 jours sur le CMP et le timing TCF (étape 5), 3 jours sur la viewability et la MFA (étapes 6 et 7), 2 jours de calibration des changements config et de suivi post-déploiement. À un taux de consultant senior français entre 1 200 € et 1 800 € jour, soit 21 600 € à 32 400 € de budget. Pour un publisher dont le yield desktop ROS représente disons 4 M€ annuels, +24,3% c’est ~972 k€ de revenu additionnel annuel — ROI de l’audit entre 30× et 45× sur 12 mois. Et c’est répétable, parce que la configuration de wrapper dérive en quelques mois (changements internes, ajouts d’adapters, dérive de viewability) — un audit annuel est un investissement, pas une dépense.

Une remarque sur la priorisation des leviers, parce que les 7 changements ci-dessus n’ont pas tous la même difficulté d’implémentation. Le priceBucket granularité affinée est trois lignes de config Prebid + trois lignes de key-value GAM, on peut le déployer en une matinée. La suppression d’un slot UX (in-article 8) demande l’accord du produit et du commercial, peut prendre des semaines de réunion. Le passage en S2S de deux adapters demande un serveur S2S déjà déployé ou un Prebid Managed Service contracté — pas une décision technique uniquement. Quand je présente un audit, je classe les leviers en trois colonnes : quick wins (config-only, < 1 semaine), medium-effort (UX ou commercial, 2–8 semaines), strategic (changement de pile, > 8 semaines). Le publisher peut ainsi engager les quick wins sans débat et garder les decisions structurelles pour le comité éditorial.

Étape 9 — FLEDGE / Protected Audience adoption Q1 2026

Privacy Sandbox a tellement été annoncé, repoussé, ré-annoncé que la plupart des opérateurs ad-tech français en parlent désormais sur le ton du vive le cookie. C’est une erreur. Au 1er avril 2026, la cohorte Chrome FLEDGE / Protected Audience couvre environ 50% des utilisateurs Chrome EU — la moitié, pas l’épsilon. Et sur cette moitié, l’inventaire qui passe par Protected Audience API au lieu du flux open exchange classique représente, sur les publishers tier-1 français que j’ai audités en Q1 2026, entre 4% et 9% des auctions Chrome — ce qui veut dire entre 2% et 4,5% des auctions totales du publisher (en pondérant par la part Chrome EU).

Ce n’est pas encore majoritaire, mais ce n’est plus négligeable, et la tendance est claire : +1,2 point par mois sur Q1 2026. Si la trajectoire tient, on est à 8–12% des auctions Chrome EU en Protected Audience à fin 2026. Sur ce wrapper, j’ai mesuré la part Protected Audience par mois :

mois        part FLEDGE / Protected Audience (sur Chrome EU)
nov 2025    2,8%
déc 2025    3,4%
jan 2026    4,2%
fév 2026    5,9%
mar 2026    7,1%

Ce qui se passe sur cette cohorte est différent d’une auction Prebid classique. Le bidRequest n’est pas envoyé aux DSP avec les cookies tiers — il est envoyé avec un interest group Protected Audience que le navigateur a stocké localement, et chaque DSP doit avoir précédemment enregistré un bidding script qui tourne dans une sandbox isolée côté navigateur pour produire son bid. Pas de cookie pool DSP, pas de retargeting classique — l’enchère se fait sur des signaux qui n’identifient pas l’utilisateur au-delà de la session.

Conséquences pratiques pour un audit Prebid.js :

  • les bidsReceived Protected Audience apparaissent dans auctionEnd mais avec bidder: 'paapi' (Privacy Aware Adtech Initiative — terme officiel Chrome) ou bidder: 'fledge' selon la version Prebid (9.18 utilise paapi)
  • meta.advertiserDomains est généralement présent mais réduit à un seul domaine (le DSP n’a plus accès à un cookie pool large)
  • le cpm retourné est gross mais le take-rate n’apparaît pas dans sellers.json parce que le flow ne passe pas par un SSP traditionnel — c’est un flow auction directe browser ↔ DSP, intermédié par un seller qui n’est pas un SSP au sens TCF/IAB
  • les viewability mesurées sur les impressions Protected Audience sont en moyenne plus basses que sur les impressions cookies-based, parce que l’absence de retargeting réduit le quality of audience ce qui dégrade le time-on-slot

Sur ce wrapper, l’adoption Protected Audience était inégale par adapter. Criteo participait activement (cohérent — Criteo a investi sur Protected Audience depuis l’Origin Trial 2023), avec 14% de ses bids servis en mars 2026 passant par le flow PAAPI. Equativ et PubMatic étaient en montée mais à 6–8%. Index Exchange, AppNexus, OpenX et Rubicon étaient en dessous de 4%. Magnite était à 0% — pas de tag Protected Audience déployé, ce qui veut dire que sur la part Chrome EU FLEDGE, Magnite est mécaniquement absent. C’est une fuite de yield future, plus que présente. À 7% d’auctions FLEDGE sur Chrome EU et Magnite à 0%, la perte instantanée est faible. À 12% en fin 2026 si la trajectoire tient, et avec un Chrome EU qui se rapproche de 70% d’utilisateurs FLEDGE-activés, la perte deviendra significative.

Recommandation sur ce wrapper : prévoir un point de revue Protected Audience trimestriel sur 2026, avec mesure de la part FLEDGE par adapter, et engagement de Magnite (et tout adapter <2%) à déployer leur tag Protected Audience sous 90 jours. Ce n’est pas urgent en Q1 2026. Ça le sera en Q3 2026. Les wrappers qui n’auront pas anticipé verront leur yield Chrome EU diverger des wrappers qui auront anticipé, et cette divergence sera la fuite la plus structurelle de 2027.

Une dernière remarque : Protected Audience ne remplace pas l’open exchange, il s’y superpose. Les bidders Protected Audience participent à la même auction unifiée Prebid via le module paapi côté wrapper, et le winningBid final est sélectionné entre les bids classiques et les bids PAAPI sur le même critère de prix (corrigé du shading). Ce qui change, c’est qui peut bid et avec quels signaux. Et donc, à terme, ce qui change est la composition du bidsReceived — moins de retargeting cookies-based, plus de signal-based. Le wrapper qui ne logge pas la part PAAPI séparément ne pourra pas mesurer cette transition.

Quelques précisions techniques sur l’intégration PAAPI dans Prebid.js 9.x, parce que c’est l’étape où la documentation officielle vieillit le plus vite. Le module paapi est désormais activé par défaut dans Prebid.js 9.18+ si l’adapter le supporte ; pas besoin d’un opt-in pbjs.setConfig({ paapi: { enabled: true } }) séparé comme c’était le cas en 9.10. Le auctionConfig est généré côté SSP/adapter pendant la phase bidRequest standard, transmis au wrapper via le bidResponse, et passé au navigateur via navigator.runAdAuction() à la fin de l’auction Prebid si aucun bid open exchange ne bat le floor. Concrètement : Protected Audience joue le rôle de backup sur les slots où l’open exchange n’a pas servi de gagnant satisfaisant. C’est une architecture hybrid — pas un remplacement complet, pas un simple bolt-on. Et c’est précisément la difficulté de mesure : la part PAAPI mesurée dans auctionEnd dépend non seulement du déploiement adapter mais aussi du floor configuré et de la profondeur de la demande open exchange sur le slot. Sur des slots à floor haut et demande open exchange faible, la part PAAPI peut grimper rapidement.

Quelques signaux à surveiller sur 2026 pour planifier le passage en mode FLEDGE-first. Premièrement, la décision Commission EU sur les core platform services DMA s’appliquera-t-elle à Privacy Sandbox ? Le rapport préliminaire de janvier 2026 suggère que oui, ce qui forcerait Google à offrir des API alternatives — modification potentiellement majeure du paysage si confirmée. Deuxièmement, la cohorte Safari ITP reste à 0% Protected Audience (Apple ne participe pas), donc tout trafic iOS reste sur cookies-first ou cookieless contextual selon le publisher — la part Safari sur desktop FR est ~14%, sur mobile FR ~58%, donc l’arbitrage device est critique. Troisièmement, les DSP français spécifiques au programmatic vidéo (Adagio sur l’outstream desktop) commencent à tester PAAPI pour le video mais avec une roadmap distincte de display ; à surveiller pour les publishers à fort mix vidéo.

Une dernière mise en garde sur le discours FLEDGE en France. “FLEDGE n’est pas prêt” est une phrase qu’on entend encore régulièrement en conférence française en 2026. Elle était vraie en 2023, déjà discutable en 2024, fausse depuis Q3 2025. La cohorte est suffisante pour mesurer, la stack Prebid.js le supporte, les DSP majeurs ont des bidding script en production. Ce qui n’est pas prêt, c’est l’écosystème côté retargeting comportemental — Criteo et RTB House ont déployé, mais la majorité des DSP performance-marketing tirent encore leur revenu du cookies-based. Cette asymétrie va se résorber sur 2026–2027. Un publisher qui attend que tout l’écosystème ait fini sa transition pour s’en occuper attendra trop longtemps et perdra des parts de yield à ceux qui auront tagué PAAPI 12–18 mois plus tôt.

FAQ

Faut-il instrumenter le wrapper avant l’audit, ou peut-on auditer le log existant ? Si le log existant capture bidsReceived, noBids, bidderRequests et timeToRespond détaillé par adapter, on peut auditer. En pratique, 80% des wrappers que j’ai vus en Q1 2026 ne loggent pas ces quatre champs correctement, donc la première semaine d’audit est de l’instrumentation. C’est normal, pas un échec.

Quelle granularité de priceBucket Prebid.js 9.x recommandez-vous en 2026 ? 0,01 € jusqu’à 8 €, puis 0,05 € jusqu’à 20 €, puis 0,50 € au-delà. La granularité par défaut Prebid.js (dense) est trop grossière sur la fourchette 2,80–3,20 € où la majorité de l’inventaire ROS desktop FR se situe. Configurer en customPriceBucket et accepter le coût mineur de complexité GAM (plus de line items, mais c’est gérable avec un générateur).

Le timeout 800 ms est-il toujours pertinent sur desktop FR en 2026 ? Pour le wrapper client-side, oui — au-delà, le Core Web Vitals INP se dégrade. Si certains adapters dépassent systématiquement 800 ms, la solution est S2S, pas le relâchement du timeout. Sur Prebid Server S2S, on peut tolérer 1 200 ms côté serveur sans impact INP côté navigateur.

Comment lire un sellers.json pour identifier les fuites d’intermédiation ? Télécharger sellers.json de chaque SSP, filtrer par domain du publisher, identifier toutes les entrées (publisher peut avoir plusieurs seller_id chez le même SSP). Si une entrée a seller_type: INTERMEDIARY, vérifier dans ads.txt du publisher si cette intermédiation est explicite et contractualisée. Si non, c’est probablement une fuite — une revente non-autorisée à corriger.

Quel CMP recommandez-vous pour un publisher news FR tier-1 en 2026 ? Didomi en standard, Sirdata en alternative crédible avec parfois de meilleures perfs au p95. OneTrust si le périmètre est multi-pays EU+US+BR. Le critère décisif n’est pas la conformité (les trois sont conformes TCF 2.2) — c’est le cmpReady p95 et la capacité à optimiser le tag côté config.

Qu’est-ce qu’un floor viewability-targeted et comment l’implémenter ? Un floor priceFloors Prebid.js qui dépend de la viewability historique observée par paire (adapter, slot). Implémentation : endpoint qui calcule la viewability rolling 14-jours par paire, génère un fichier floors.json quotidien, le wrapper le récupère via priceFloors.endpoint. Floor au 30e percentile du CPM gagné historique sur cette paire. Effet : les adapters qui gagnent à viewability basse sont coupés au seuil, ceux qui gagnent à viewability haute ne sont pas pénalisés.

Comment détecter qu’un publisher est mal classé MFA dans les DSP ? Croiser les meta.advertiserDomains du publisher avec ceux d’un publisher tier-1 comparable. Si des annonceurs premium (luxe, finance, automobile) sont absents alors qu’ils sont présents chez le comparable, c’est un signal de mauvaise classification. Investiguer ratio publicité/contenu, nombre de slots in-article, présence de partenariats content recommendation mal scopés.

Quel ROI moyen un audit Prebid.js sérieux génère-t-il ? Sur les cinq audits que j’ai menés en Q1 2026, l’amélioration du net eCPM desktop ROS s’est étalée entre +12% et +28%, avec une médiane à +19%. Pour un publisher dont le yield desktop annuel est entre 2 M€ et 8 M€, ça représente entre 240 k€ et 2,2 M€ de revenu additionnel annuel — pour un coût d’audit entre 22 k€ et 35 k€. Le ROI est rarement en dessous de 10× sur 12 mois.

Faut-il déjà investir sur Protected Audience / FLEDGE en Q2 2026 ? Oui mais à dose raisonnable. Tagger les adapters Protected Audience qui ne le sont pas encore (Magnite et autres retardataires), mesurer la part PAAPI dans auctionEnd mensuellement, prévoir un budget de migration plus sérieux pour Q4 2026. À Q1 2026, ne pas refactoriser tout le wrapper pour PAAPI — la cohorte n’est pas encore assez large pour justifier le coût d’opportunité.

Le rapport SSP est-il jamais utile, ou faut-il toujours partir du log Prebid ? Le rapport SSP est utile pour les chiffres agrégés mensuels et la facturation, jamais pour l’audit yield. La granularité agrège ce qui doit être désagrégé (par slot, par adapter, par GEO, par device, par viewability), et masque les fuites qui ne se voient que dans le log. Règle simple : si la question commence par “pourquoi” — pourquoi le yield baisse, pourquoi un adapter sous-performe — il faut lire le log. Si la question commence par “combien” au niveau mois et SSP, le rapport agrégé suffit.


Trois lignes de config dans le wrapper, deux adapters migrés en S2S, une ligne ads.txt supprimée, une optimisation CMP, deux floors viewability-targeted, un slot UX retiré. Net eCPM publisher +24,3% en 12 semaines. Aucun SSP renégocié. Aucune nouvelle demand-source ajoutée. Le rendement était dans le log, pas dans le rapport.

Les auction logs ne mentent pas — les rapports de yield, parfois oui, pas par malhonnêteté, mais parce qu’ils agrègent ce que le SSP voit, jamais ce que le wrapper publisher fait avec ses réponses. La prochaine fois que le yield desktop ROS baisse de 19% quarter-over-quarter, n’ouvrez pas le ticket SSP. Ouvrez le log.

Une note méthodologique en clôture, parce que je n’ai pas trouvé d’occasion propre de la glisser dans le corps de l’article. Tous les chiffres présentés ici — distributions de timeToRespond, win rates, take-rates effectifs sellers.json, viewability MRC par slot, parts PAAPI mensuelles — sont mesurés sur cinq wrappers audités entre janvier et avril 2026, dont le principal est un publisher news tier-1 français anonymisé pour des raisons contractuelles évidentes. Les ordres de grandeur tiennent sur les cinq audits ; les valeurs précises varient selon le mix slot, la part Chrome EU, la profondeur de la demande SSP, et la maturité du CMP côté publisher. Quelqu’un qui reproduit cette méthode sur un autre publisher tier-1 français en Q2 2026 trouvera des chiffres similaires à ±15% ; quelqu’un qui la reproduit sur un publisher DACH trouvera des chiffres décalés sur le CPM (plus haut, parce que DACH paie mieux en programmatique display que FR) et sur le take-rate (similaire, parce que les SSP appliquent la même grille EU). Sur un publisher SEA ou MENA, tout le calibrage CPM est à refaire, et la part Chrome EU n’a aucun sens — il faudrait substituer Chrome global moins certaines géographies. La méthode tient, les chiffres ne se transposent pas tels quels.

Et un mot pour les opérateurs côté SSP qui liront cet article (vous existez, je le sais — sellers.json ne se lit pas tout seul, certains d’entre vous arrivent ici via Google Discover en cherchant “PubMatic take-rate Q1 2026” parce que vous voulez voir ce que la concurrence raconte). Les chiffres présentés ne sont ni des accusations ni des recommandations — ce sont des mesures sur un wrapper précis, à un moment précis, avec une composition demand précise. Le take-rate effectif PubMatic mesuré à 17,9% ne signifie pas que PubMatic applique 17,9% partout en EU desktop ; il signifie que sur ce wrapper, avec cette demande, ce mix open exchange/PMP, cette composition d’ads.txt, le take-rate effectif s’est établi là. La grille publique PubMatic indique 15–20% sur open exchange, et 17,9% est dedans. Idem pour les ratios de bid shading mesurés indirectement — ce sont des inférences à partir des ratios cpmGagnant / cpmDeuxième, pas des chiffres tirés des serveurs PubMatic internes. Aucune méthode externe ne donne accès aux chiffres internes ; à chacun de calibrer ses propres mesures.

Dernier conseil opérationnel, pour le publisher qui lit ceci et se demande par où commencer concrètement. Trois actions cette semaine, sans dépenser un euro de plus que le temps de votre équipe technique : instrumenter correctement pbjs.onEvent('auctionEnd', ...) avec les six champs listés étape 1 ; télécharger les sellers.json de chacun de vos huit à douze adapters actuels et chercher les entrées seller_type: INTERMEDIARY non documentées dans votre ads.txt ; mesurer le cmpReady médian et p95 de votre CMP sur 48 heures de trafic production. Ces trois actions prennent une journée-personne cumulée. Elles révèlent souvent, à elles seules, entre 4% et 8% de yield récupérable, sans renégociation, sans changement de stack, sans investissement nouveau. Le reste — les six étapes suivantes — peut attendre le mois prochain.

Questions fréquentes

Faut-il instrumenter le wrapper avant l’audit, ou peut-on auditer le log existant ?

Si le log existant capture bidsReceived, noBids, bidderRequests et timeToRespond détaillé par adapter, on peut auditer. En pratique, 80% des wrappers vus en Q1 2026 ne loggent pas ces quatre champs correctement, donc la première semaine d’audit est de l’instrumentation. C’est normal, pas un échec. On accepte que la première semaine de données ne serve qu’à débugger l’instrumentation.

Quelle granularité de priceBucket recommandez-vous dans Prebid.js 9.x ?

0,01 euro jusqu’à 8 euros, puis 0,05 euro jusqu’à 20 euros, puis 0,50 euro au-delà. La granularité par défaut est trop grossière sur la fourchette 2,80-3,20 euros où se situe la majorité de l’inventaire ROS desktop FR. Sur le wrapper audité, le passage à customPriceBucket avec granularité de 0,01 euro a redonné 4,2 points de win rate à Equativ et généré +6,1% de net eCPM en deux semaines.

Comment lire un sellers.json pour identifier les fuites d’intermédiation ?

Télécharger le sellers.json de chaque SSP, filtrer par domain du publisher, identifier toutes les entrées. Si une entrée a seller_type INTERMEDIARY, vérifier dans l’ads.txt du publisher si cette intermédiation est explicite et contractualisée. Si non, c’est probablement une fuite. Sur le wrapper principal audité, 28% des auctions PubMatic remontaient via une chaîne INTERMEDIARY avec un take-rate cumulé de 24-27% au lieu de 17,9%.

Quel ROI moyen un audit Prebid.js sérieux génère-t-il ?

Sur les cinq audits menés en Q1 2026, l’amélioration du net eCPM desktop ROS s’est étalée entre +12% et +28%, avec une médiane à +19%. Sur le wrapper principal décrit dans cet article, le net eCPM est passé de 2,18 euros à 2,71 euros en moins de 4 mois, soit +24,3%, sans renégociation contractuelle, sans nouvel SSP ajouté. Pour un publisher dont le yield desktop annuel est entre 2 M€ et 8 M€, ça représente entre 240 k€ et 2,2 M€ de revenu additionnel annuel.

Quel CMP recommandez-vous pour un publisher news FR tier-1 en 2026 ?

Didomi en standard — leader FR tier-1, bien intégré avec Prebid et GAM. Sirdata en alternative crédible, avec de meilleures performances au p95 (640 ms vs 920 ms Didomi sur le wrapper testé). OneTrust si le périmètre est multi-pays EU+US+BR. Le critère décisif n’est pas la conformité mais le cmpReady au p95 : sur ce wrapper, les sessions avec cmpReady lent avaient un yield desktop ROS inférieur de 23% à la médiane.

Faut-il déjà investir sur Protected Audience en Q2 2026 ?

Oui, à dose raisonnable. Il faut tagger les adapters Protected Audience qui ne le sont pas encore — Magnite était à 0% sur le wrapper audité, ce qui représente une fuite de yield future. La cohorte Chrome EU avec Protected Audience actif était à 7,1% en mars 2026, en progression de plus d’un point par mois. Prévoir un budget de migration plus sérieux pour Q4 2026. Ne pas refactoriser tout le wrapper maintenant — la cohorte n’est pas encore assez large.

Confidentialité

Vos choix de confidentialité

Nous utilisons des cookies pour faire fonctionner le site et, avec votre consentement, pour mesurer son utilisation et personnaliser le contenu. Vous pouvez modifier vos choix à tout moment.

Accessibilité

Paramètres d'accessibilité

Personnalisez l'apparence et les animations du site. Enregistré uniquement sur ce navigateur.