Repository navigation
Peak226 Bid Adapter: initial release - #15619
Conversation
Adds a new bidder adapter for peak226, built on Prebid's ortbConverter for OpenRTB2-style banner/video/native requests, with region routing across US/EU/JP endpoints and TCF/USP/GPP/COPPA/floors/schain forwarded automatically. Endpoint URLs, response-shape and user-sync details are still placeholders pending confirmation from peak226; see TODOs in modules/peak226BidAdapter.ts and modules/peak226BidAdapter.md. gulp lint: clean (no output) gulp test --file test/spec/modules/peak226BidAdapter_spec.js: 24/24 passing
The adapter already sends every declared format on a single imp and lets response mtype pick the winner, but nothing asserted it. Add a multiFormatBid fixture composed from the existing single-format fixtures, and cover: a multiformat unit validating, a malformed video block dropping the whole bid (validation is additive, not per-format), banner + video + native landing on one imp, and banner and video bids parsed from a single impid. Also set pbs: true in the .md — the Prebid Server adapter exists and is registered — and document the multiformat behavior for publishers.
- Use the production regional endpoints (https://{us,eu,jp}.a.viddea.com/edge_direct)
- Split requests per (region, publisherId) so publisher.id is always correct
- Resolve ${AUCTION_PRICE} in adm, nurl and burl (core only expands it in banner markup)
- Pin currency to USD for floors and responses without cur
- Validate bidder params only; core validates media types
- Drop TODO/pending notes; GVL 1202 (Edge226 Ltd) is registered
- Rewrite module docs in repo convention; instream video test unit, outstream renderer note
…test params
Live testing against the production endpoint (hb-test/hb-test) surfaced two issues:
- Native responses carry markup in a non-standard `adm_native` field (an
already-parsed ORTB native object) instead of `adm` (a JSON string), with
`adm` left empty. Core's native processor only reads `bid.adm` and throws
when it's empty, silently dropping every native bid. The adapter now maps
adm_native onto adm when adm is unset.
- ${AUCTION_PRICE} appears inside native tracker URLs nested under
adm_native (e.g. eventtrackers[].url), which core never resolves. Added a
recursive macro resolver for the whole adm_native object rather than a
fixed list of fields, since which field carries the macro isn't guaranteed.
Also updates the documented test parameters to publisherId/placementId
'hb-test', confirmed via direct requests to return live banner, video and
native bids on the US endpoint.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
The Prebid.js peak226 adapter (prebid/Prebid.js#15619) is now submitted, so this page covers both adapters instead of just Prebid Server: flips pbjs back to true, adds Prebid.js ad unit examples for banner, instream video and native, and splits the Notes section into per-adapter Prebid.js / Prebid Server subsections plus a shared Privacy note.
|
Related: Prebid Server adapter at prebid/prebid-server#4919, docs at prebid/prebid.github.io#6715. |
|
This PR introduces changes that may not work on all browsers. According to Babel, the following polyfills may be needed, and they are not automatically included:
The best way to address this is to provide good test coverage, as normal PR checks run unit tests on older browsers. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d5135a9feb
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const { publisherId, placementId } = bid.params ?? ({} as Partial<Peak226BidderParams>); | ||
| return isNonEmptyId(publisherId) && isNonEmptyId(placementId); |
There was a problem hiding this comment.
Accept identifiers already supplied through ORTB
When a publisher supplies site|app|dooh.publisher.id and imp.tagid through ortb2/ortb2Imp, this validation still rejects the bid unless the same values are duplicated as publisherId and placementId. Both params should be optional overrides of those standard ORTB fields rather than mandatory duplicates.
AGENTS.md reference: AGENTS.md:L67-L67
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 5ef1c81 — agreed, both params are now overrides rather than requirements.
publisherId resolves from params.publisherId first and then, per CLIENT_SECTIONS priority (dooh > app > site), from ortb2.{section}.publisher.id. imp.tagid is only overwritten when params.placementId is given, so an ortb2Imp.tagid supplied by the publisher now stands on its own. isBidRequestValid passes when each of the two values comes from either source, and request grouping keys off the resolved publisher id so the one-publisher-per-request invariant still holds when no params are set. Params are now optional in Peak226BidderParams and the docs (here and in prebid/prebid.github.io#6715) describe them as overrides.
| // every bid in a request shares the same publisherId (see buildRequests) | ||
| const publisherId = context.bidRequests[0]?.params?.publisherId; | ||
| if (isNonEmptyId(publisherId)) { | ||
| deepSetValue(request, `${request.app ? 'app' : 'site'}.publisher.id`, String(publisherId)); |
There was a problem hiding this comment.
Preserve the DOOH client section
For an auction whose global ORTB data contains dooh, the converter's one-client processor retains dooh and removes site, but this wrapper subsequently creates site.publisher.id because only app is checked. The resulting request contains both dooh and site, violating their mutual exclusivity and potentially causing the endpoint to reject DOOH requests; select dooh.publisher.id when request.dooh is present.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Good catch — fixed in 5ef1c81.
The hook now writes to whichever client section actually survived the converter's onlyOneClient processor: CLIENT_SECTIONS.find((s) => hasSection(request, s)) ?? 'site', reusing CLIENT_SECTIONS/hasSection from src/fpd/oneClient.js rather than re-deriving the priority order. A DOOH auction now gets dooh.publisher.id and no site/app keys; covered by a new unit test.
Barecheck - Code coverage reportTotal: 91.35%Your code coverage diff: 0.02% ▴ ✅ All code changes are covered |
Addresses two review findings on prebid#15619. - isBidRequestValid required publisherId and placementId even when the publisher already supplied {dooh|app|site}.publisher.id via ortb2 and imp.tagid via ortb2Imp, forcing them to duplicate standard ORTB fields in bid params. Both are now resolved from params first and ortb2 second, and a bid is valid as long as each value comes from one of the two. imp.tagid is only overwritten when placementId is given, so ortb2Imp.tagid stands on its own otherwise. Request grouping keys off the resolved publisher id so the one-publisher-per-request invariant still holds without params. - The request hook wrote site.publisher.id whenever ortb2 had no app, so a DOOH auction came out with both dooh and site, which are mutually exclusive - the converter's onlyOneClient processor had already dropped site. It now writes to whichever client section survived that processor, reusing CLIENT_SECTIONS/hasSection from src/fpd/oneClient.js. Docs note that the params are optional overrides of the ortb2 fields. Tests: 44 pass (normal build), 37 pass (all features disabled). eslint and both tsc configs clean.
Following review feedback on prebid/Prebid.js#15619, the Prebid.js adapter no longer requires publisherId and placementId when the publisher already supplies {dooh|app|site}.publisher.id and ortb2Imp.tagid as first party data; the params act as per-ad-unit overrides. Prebid Server still requires both.
| | `region` | optional | `string` | Data center to send the request to: `'us'`, `'eu'` or `'jp'`. Default `'us'`. | `'eu'` | | ||
|
|
||
| \* Both IDs may instead be supplied as standard ORTB first party data — | ||
| `ortb2.{site|app|dooh}.publisher.id` and `ortb2Imp.tagid` — in which case the params are not |
There was a problem hiding this comment.
Imp.ext.gpid is typically preferred to imp.tagid
There was a problem hiding this comment.
Fixed in 5cd61aa — isBidRequestValid now also accepts ortb2Imp.ext.gpid as a valid placement identifier (alongside params.placementId/ortb2Imp.tagid), since gpid is already forwarded automatically via the ortb2Imp merge and is more broadly supported than tagid. Docs footnote updated to call it out.
|
|
||
| | Name | Scope | Type | Description | Example | | ||
| |---------------|----------|----------|--------------------------------------------------------------------------|-------------| | ||
| | `publisherId` | required* | `string` | Your Peak226 publisher/account ID. | `'pub-123'` | |
There was a problem hiding this comment.
I would make the entry in the table optional* instead of required*
There was a problem hiding this comment.
Fixed in 5cd61aa — the table now says optional* instead of required* for publisherId/placementId, matching the footnote.
Addresses PR review feedback: imp.ext.gpid is more broadly supported than imp.tagid for placement identification, so isBidRequestValid now accepts it as an additional valid signal alongside placementId/tagid. Also fixes the Bid Params table to say optional* instead of required* for publisherId/placementId, matching the existing footnote.
|
Backport to the 9.53.x-legacy line (needed by AnyClip, which is on Prebid.js 9): #15731 |
Type of change
Bugfix
Feature
New bidder adapter
Updated bidder adapter
Code style update (formatting, local variables)
Refactoring (no functional changes, no api changes)
Build related changes
CI related changes
Does this change affect user-facing APIs or examples documented on http://prebid.org?
Other
Description of change
Adds the Peak226 bid adapter (banner, video and native, incl. multiformat ad units).
ortbConverter(OpenRTB 2.6). Floors, eids, schain, first-party data and consent(TCF EU / USP / GPP / COPPA) are taken from
ortb2/ortb2Imp; no bidder params duplicateortb2 data.
us/eu/jp) and split per(region, publisherId) so
site|app.publisher.idis always correct.${AUCTION_PRICE}is resolved inadm,nurlandburl(the SSP returns the macro in VASTand notice URLs; core only expands it in banner markup).
meta.advertiserDomainsfromadomain.getUserSyncs: GVL 1202 declaresusesCookies: falseand no Purpose 1, so there is nosync to register. No storage is used.
Peak226BidderParamsregistered inBidderParams.adm_nativefield (an already-parsed ORTB nativeobject) rather than
adm(a JSON string); the adapter maps it over so core's nativeprocessor can read it, and resolves
${AUCTION_PRICE}recursively inside it since the macroturned up nested in a tracker URL that core has no path to expand. Found by hitting the live
endpoint directly — see "Checks" below.
Contact email of the adapter's maintainer: support@edge226.com
Test parameters for validating bids:
Confirmed live: direct ORTB requests with this pair returned real
200bid responses forbanner, instream video and native on the US endpoint (a prior placeholder pair,
hb123/hb,204'd — this is a placement the SSP team provisioned to always fill, not an arbitrary string).
Full banner / instream video / native test ad units are in
modules/peak226BidAdapter.md.Instream video needs
pbjs.setConfig({ cache: { url: ... } }); outstream needs a publisherrenderer (Peak226 returns VAST and does not host a renderer).
Relationship to the existing
edge226adapterBoth adapters belong to Edge226 Ltd (GVL 1202, see
https://vendor-list.consensu.org/v3/vendor-list.json, same entity confirmed on
prebid/prebid-server#4919). Peak226 is a separate SSP platform, not a rebrand: it runs on its
own stack (
*.a.viddea.com, regional data centers), speaks OpenRTB 2.6, and uses differentaccount parameters (
publisherId+placementId+region), whereasedge226uses theteqblaze JSON protocol on
ssp.dauup.comwith a singleplacementId. An alias cannot changeendpoint, protocol or params, so a dedicated adapter is required. Prebid Server already has a
separate
peak226adapter for the same reason.GVL name
gvlid: 1202resolves to "Edge226 Ltd", the legal entity; Peak226 is the product/brand name.This was raised and verified on the Prebid Server PR (prebid/prebid-server#4919).
Checks
npx eslint --no-inline-config modules/peak226BidAdapter.ts test/spec/modules/peak226BidAdapter_spec.js— cleannpx tscandnpx tsc -p tsconfig-strict.json— cleannpx gulp test --nolint --file test/spec/modules/peak226BidAdapter_spec.js— 37/37 pass (normal build), 30/30 pass (all-features-disabled build)npx gulp update-metadata --no-fetch— peak226 extracted withgvlid: 1202, no naming violationsus.a.viddea.com/edge_directwith the documented testparams returned real bids for banner, video and native
Other information
Prebid.js:
pbjs: true+ Prebid.js examples)