New Module: DAA AdChoices Signal#15138
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 40ba90a5cc
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| import { getHook } from '../src/hook.js'; | ||
| import { enrichFPD } from '../src/fpd/enrichment.js'; | ||
|
|
||
| const MODULE_NAME = 'adChoices'; |
There was a problem hiding this comment.
Align the module name with the build filename
With this file named daaAdChoices.ts, Prebid's build helper derives the selectable module name from the file basename (gulpHelpers.getModules()), so publishers must build with --modules=daaAdChoices; --modules=adChoices is rejected as an invalid module even though this module registers and documents its config under adChoices. Please rename the file/module or align the public name so the documented adChoices module can actually be included in a build.
Useful? React with 👍 / 👎.
Adds the adChoices module (modules/adChoices.ts), which reads the DAA AdChoices Signal in the browser via the Protect My Choices (PMC) extension postMessage protocol (ExtensionLoaded -> GetAdPreferences -> AdPreferences) and conveys it in the OpenRTB bid stream as the community extension regs.ext.adchoices, per Appendix 5 of the DAA AdChoices Signal Specification. - Standalone `adChoices` config namespace; supports a static `signal` override (takes precedence) and an opt-in `timeout`. Non-blocking by default; when a positive timeout is set, the first auction is delayed up to that many ms while waiting for the signal (the window starts when an auction begins waiting and applies once, so later auctions are not re-delayed). - Injects the value via the FPD enrichment hook, matching the consent modules. - TypeScript public types (AdChoicesConfig); 20 unit tests.
40ba90a to
51c3455
Compare
robertrmartinez
left a comment
There was a problem hiding this comment.
I am wondering if this should be a realTimeData submodule instead of a new standalone top-level module?
it is reading data from an outside browser source, optionally delaying the auction, and then adding data into the bidstream at regs.ext.adchoices
that sounds pretty close to the RTD module shape to me:
pbjs.setConfig({
realTimeData: {
auctionDelay: 500,
dataProviders: [{
name: 'adChoices',
waitForIt: true
}]
}
});I think rtdModule already owns a lot of this lifecycle, auctionDelay, waitForIt, and provider docs expectations
could this be adChoicesRtdProvider and just enrich ortb2.regs.ext.adchoices from there?
if there is a reason this needs to be a standalone consent-style module instead, can we add that reasoning somewhere?
just wanted to ask before we add another one-off requestBids hook/config namespace
|
also can we please add the local module markdown file? I see the docs PR is linked here: but we usually still need the repo-side module docs with example config and what changes in the bid request if this becomes RTD, I think that would be if it stays standalone, then prob please add that also! |
Adds modules/adChoices.md with an overview, example `adChoices` config (`signal` and `timeout`), and the resulting `regs.ext.adchoices` bid-request output, per reviewer request.
Thanks, that's a fair question. I was wondering the same thing initially (standalone vs. RTD), and ultimately positioned it as a standalone consent-style module rather than an RTD submodule for a few reasons:
That said, if you still prefer this live under realTimeData as adChoicesRtdProvider, I'm happy to refactor, I just wanted to lay out the rationale. Let me know which you'd prefer and I'll align it. I've also added the repo-side module docs (modules/adChoices.md) in the latest commit, as you requested, with the example config and the resulting regs.ext.adchoices bid request output. |
robertrmartinez
left a comment
There was a problem hiding this comment.
Ok now I get it and I agree standalone is right fit not RTD!
So I think from that standpoint this looks clean to me. couple minor notes.
@patmmccann mentioned activity controls, which we could leverage to enforce some of the user decisions in the PMC extension. Though seems like any enforcement should just be done in a future version once it is a bit more ironed out.
I think we should ship as is!
- Remove the requestBids hook (and clear the installed flag) in resetAdChoicesData so the hook does not leak onto the global requestBids across test runs, and can be reinstalled after a reset. Adds a test that sets a timeout, resets, and asserts the hook is gone. - Reformat modules/adChoices.md to the repo-side `# Overview` convention (Module Name / Module Type / Maintainer); the page_v2 frontmatter remains in the docs PR.
|
Thanks @robertrmartinez - good catches on both. Addressed in 10f6554 As for leveraging activity controls for enforcement, I agree, that's worth exploring for a future version. |
Barecheck - Code coverage reportTotal: 96.58%Your code coverage diff: 0.00% ▴ Uncovered files and lines
|
Type of change
Feature
Does this change affect user-facing APIs or examples documented on http://prebid.org? — yes, docs PR to follow (see below)
Description of change
Adds a new standalone module,
adChoices(modules/adChoices.ts), that reads the DAA AdChoices Signal in the browser and conveys it in the OpenRTB bid stream as the community extensionregs.ext.adchoices, per Appendix 5 of the specification.How it works:
postMessageprotocol (ExtensionLoaded→GetAdPreferences→AdPreferences), and also proactively requests preferences on startup to cover the case whereExtensionLoadedfired before the listener attached. Messages are only trusted whenevent.source === window.enrichFPD.before(...)), the same mechanism used by the USP/GPP consent modules, so it reaches both client adapters and Prebid Server.adChoicesconfig namespace:signal(string, optional): a statically supplied signal (e.g. read server-side from theX-AdChoicesheader); takes precedence over the extension-read value.timeout(integer, optional): max ms to delay the first auction while waiting for the signal. Defaults to0(non-blocking) so users without the extension are not penalized; therequestBidsdelay hook is only installed when a positive timeout is configured. The delay window starts when an auction actually begins waiting (not atsetConfigtime) and applies once — after the signal arrives or the timeout elapses, later auctions proceed without further delay.AdChoicesConfig).Maintainer contact: prebid@aboutads.info
Note: page JavaScript cannot read the
X-AdChoices/Cookie2headers the extension injects into outbound requests (those are for server-side consumption), so the browser path is the postMessage protocol or thesignalconfig option.Testing
gulp lint(eslint on changed files): passes, no output.gulp test --file test/spec/modules/adChoices_spec.js: 20/20 tests passing; strict TypeScript compile (ts-strict) clean.Docs
Issue template
Type of issue
Feature
Description
Enables publishers to read the DAA AdChoices Signal in the browser (via the Protect My Choices extension) and pass it into the bid stream at
regs.ext.adchoices.Steps to reproduce
adChoicesmodule:gulp build --modules=adChoices.regs.ext.adchoiceswith the signal string. Alternatively, setpbjs.setConfig({ adChoices: { signal: '<value>' } })to supply the signal directly.Expected results
regs.ext.adchoicesis present on bid requests when a signal is available.Actual results
As expected with this change.
Platform details
Prebid.js master (11.20.0-pre); module written in TypeScript; Node >= 20.