Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PAAPI: add top level auction example #11259

Merged
merged 10 commits into from
Apr 17, 2024
Merged

Conversation

dgirardi
Copy link
Collaborator

@dgirardi dgirardi commented Mar 26, 2024

Type of change

  • Feature

Description of change

  • Add requestedSize to the configs returned by pbjs.getPAAPIConfig. For now, this is the first banner size defined by the ad unit.
  • Add an example showing how to use getPAAPIConfig to run a top level auction using your own decision logic, using a test IG set up by openx and the debugging module.

});
});

function raa() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it make sense to have some of this code in a submodule, which might end up being extremely compact on initial commit, but would provide the convenient logical abstraction that a user would pick the PAAPI submodule associated with their choice of TLS?

Copy link
Member

@jdwieland8282 jdwieland8282 Mar 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so yes. A pub makes 2 decisions.

  1. I want to run PAAPI with prebid
  2. I want to do it myself (pub sub module) or I want GPT to do it for me

if (pbjs.adserverRequestSent) return;
pbjs.adserverRequestSent = true;
raa().then((allPaapi) => {
if (!allPaapi) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this calls gam if paapi doesn't fill, correct? But PAAPI will always fill if we give it the best contextual bid from prebid as its best alternative? Is the below code basically saying 'Let's compete Prebid vs PAAPI, and if neither provide any ad call gam?'

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we can give it the best contextual bid. Some bidders may decide to provide "extra" bids for it, but those don't necessarily contain all, or even the same, contextual bids, and Prebid can't control them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's auctionSignals.prebid.bidfloor no ? I don't know if all buyers take it into account, so it may still not fill even if everyone bid all the time and above the floor.

Anyway, I assume that deleting the <div> is what makes GAM skip that slot if it was filled by PAAPI. Is there a better way to disable the slot more explicitly and perhaps less permanent ? It's fine either way as a test page but I imagine it won't work if I wanted to periodically refresh the ads.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is not a great way to render. I am not sure yet what the render API will look like:

  • when using GAM, the use case I'm hearing is to run fledge only after GAM picks the Prebid contextual winner (to keep adx demand in GAM). In practice this would mean returning the URN back to the rendering logic running in the GAM creative (PUC or equivalent). The publisher would not call any rendering API but somehow enable this behavior.
  • when not using GAM, the publisher calls renderAd(document, adId). We could do something similar and only "pretend" to render adId, rendering the fledge ad instead in a nested frame, if the publisher enabled the same behavior as above. Or we could provide separate runPaapi/renderPaapi APIs.
  • I'm not sure there will be a use case for what's demoed here, only run gam if fledge has no winner. Pubs would probably prefer to let GAM run fledge and get better demand.

browserSignals,
directFromSellerSignals,
) {
var score = bid+20;
Copy link
Collaborator

@patmmccann patmmccann Mar 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reference comparison to floor (or top prebid bid)

  var sellerSignals = auctionConfig.sellerSignals;
  var floor = sellerSignals.floor || 0;
  var modifiedBid = bid * 0.95;

  // temporary reporting: https://github.com/WICG/turtledove/blob/main/Proposed_First_FLEDGE_OT_Details.md#reporting
  const reportingBrowserSignals = {...browserSignals, bid, modifiedBid}
  const macros = '&winningBid=${winningBid}&winningBidCurrency=${winningBidCurrency}&topLevelWinningBid=${topLevelWinningBid}&topLevelWinningBidCurrency=${topLevelWinningBidCurrency}';
  globalThis.forDebuggingOnly?.reportAdAuctionLoss(
    buildReportURL('bid-loss', auctionConfig, reportingBrowserSignals) + macros);
  globalThis.forDebuggingOnly?.reportAdAuctionWin(
    buildReportURL('bid-win',  auctionConfig, reportingBrowserSignals) + macros);

  return {
    ad: null,
    desirability: (modifiedBid > floor && (browserSignals.bidCurrency == '???' || auctionConfig.sellerCurrency == browserSignals.bidCurrency)) ? modifiedBid : 0,
    allowComponentAuction: true,
    bid: modifiedBid
  };
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

console.groupEnd();
console.groupEnd();

log('reportResult', { auctionConfig, browserSignals, directFromSellerSignals });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we demonstrate calling a url in sellerSingals

eg

const reportingURL =
(sellerSignals.reportingURL || 'https://privacysandbox-reporting.openx.net/fledgeReporting')
+ '?'
+ Object.entries(params)
.filter(([k,v]) => v)
.map(([k,v]) => ${k}=${encodeURIComponent(v)})
.join('&');

return reportingURL;
}

@dgirardi
Copy link
Collaborator Author

My plan for this is to update decisionLogic so that it demonstrates floor enforcement, and remove the reportResult portion.

Pending are:

  1. moving the runAdAuction logic into a module. This should also define new events to fire for PAAPI won / loss.
  2. moving the rendering logic into paapi.js. This should define a new rendering API. It's unclear yet how to deal with size (see PAAPI module: fill out auctionSignals.prebid.ortb2Imp.banner better #11189)
  3. a reference implementation for the decision logic that includes reporting.

Let me know if you'd prefer some of the above to be included in this.

@jdwieland8282
Copy link
Member

I'm working on finding a pub willing to run a demo for us. If we don't find one by May 1 what are our options? My preference would be to use Chrome flags to run the demo from prebid.org.

trustedScoringSignals,
browserSignals,
directFromSellerSignals
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Objects logged from worklets cannot be expanded after the worklet finished.
I usually do JSON.stringify() while skipping perBuyerSignals from the logged auctionConfig (too large). Is there a better way ?

'bid': 1.5
}
},
'resolveToConfig': true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should leave this out for component, I do not think it has any effect

<code>--enable-features=CookieDeprecationFacilitatedTesting:label/treatment_1.2/force_eligible/true
--privacy-sandbox-enrollment-overrides=https://localhost:9999</code>
<p>Join interest group at <a href="https://privacysandbox.openx.net/fledge/advertiser">https://privacysandbox.openx.net/fledge/advertiser</a>
</p>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can make it fully local with

navigator.joinAdInterestGroup({
  name: 'prebid-test',
  owner: window.location.origin,
  biddingLogicURL: (new URL('buyer.js', window.location)).toString(),
  ads: [{
    renderURL: (new URL('ad.html', window.location)).toString(),
  }],
  adComponents: []
}, 600);

and a short buyer js

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intention was to make this as real-world as possible but I couldn't get any adapter that would both work and agree to be in here. Mocking openx' response was a compromise, hopefully temporary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was not sure if the demo needed to be self-contained. If so, the buyer can be local too, at a small cost of being slightly confusing to share a domain with seller. It's fine either way.

Mocking the openx adapter response is also fine - I was not aware this is possible so thanks for showing me how to do it :)

integrationExamples/gpt/top-level-paapi/decisionLogic.js Outdated Show resolved Hide resolved
if (pbjs.adserverRequestSent) return;
pbjs.adserverRequestSent = true;
raa().then((allPaapi) => {
if (!allPaapi) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's auctionSignals.prebid.bidfloor no ? I don't know if all buyers take it into account, so it may still not fill even if everyone bid all the time and above the floor.

Anyway, I assume that deleting the <div> is what makes GAM skip that slot if it was filled by PAAPI. Is there a better way to disable the slot more explicitly and perhaps less permanent ? It's fine either way as a test page but I imagine it won't work if I wanted to periodically refresh the ads.

console.groupEnd();
console.log(...LOG_PREFIX, 'Result:', result);
return result;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reportResult should still be defined even if it does not do anything, to avoid

Worklet error: https://127.0.0.1:9999/integrationExamples/gpt/top-level-paapi/decisionLogic.js reportResult is not a function.

Could be something like this

function reportResult(auctionConfig, browserSignals) {
  log('reportResult', { auctionConfig, browserSignals });
  sendReportTo(`${auctionConfig.seller}/report/win?${Object.entries(browserSignals).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&')}`);
  return {}
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that would replace it with an error about the report call failing :) I am already worried about people copying this demo into production so I'd rather avoid it; the plan is to work with @patmmccann to publish an actual reference implementation separately

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this about the event url showing up as an error in the Network tab ? It's still useful to look at parameters, but if unwanted can comment out sendReportTo or make it conditional on something like sellerSignals.reportURL

@patmmccann patmmccann merged commit 122a72a into prebid:master Apr 17, 2024
4 checks passed
@patmmccann
Copy link
Collaborator

  • moving the runAdAuction logic into a module. This should also define new events to fire for PAAPI won / loss.

tracking as #10690

@piotrj-rtbh
Copy link
Contributor

piotrj-rtbh commented Apr 24, 2024

@patmmccann and @dgirardi, did you have a chance to run the TL auction example on a Dev Chrome?
Mine is Version 126.0.6423.2 (Official Build) dev (64-bit) and once run (with all the appropriate flags) I get an error in the console:

utils.js:211 Prebid ERROR: Error executing bidsBackHandler null TypeError: Cannot read properties of undefined (reading 'apply')
    at navigator.runAdAuction (tl_paapi_example.html:10:45)
    at tl_paapi_example.html:116:42
    at Array.map (<anonymous>)
    at raa (tl_paapi_example.html:115:22)
    at sendAdserverRequest (tl_paapi_example.html:144:13)
    at Object.auctionDone (prebid.js:546:9)
    at auction.js:225:23
    at auction.js:441:5
    at executeCallback (auction.js:219:7)
    at auctionDone (auction.js:251:5)

I cannot figure out why is that happening, all is defined properly and this is not case for my regular Version 124.0.6367.61 (Official Build) (64-bit) - this one works like a charm.

mefjush pushed a commit to adhese/Prebid.js that referenced this pull request Apr 25, 2024
* bidderFactory fledge API: accept single fledge configs

* PAAPI: add top level auction example

* update example formatting

* provide bidfloor in top level auctionSignals

* update example decisionLogic to enforce auction floor, remove reporting

* PR feedback

* add reportResult
DecayConstant pushed a commit to mediavine/Prebid.js that referenced this pull request Jul 18, 2024
* bidderFactory fledge API: accept single fledge configs

* PAAPI: add top level auction example

* update example formatting

* provide bidfloor in top level auctionSignals

* update example decisionLogic to enforce auction floor, remove reporting

* PR feedback

* add reportResult
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants