New Adapter: Epom Ad Server - #4916
Open
ruin wants to merge 5 commits into
Open
Conversation
Server-side counterpart of the epom_as Prebid.js adapter. Same bidder code, same params and the same wire format, so a publisher can move between client-side and S2S without reconfiguring. Distinct from the existing epom adapter, which is the Epom DSP: the DSP buys impressions, this one sells a publisher's own inventory. The platform is white-label, so the host arrives per impression in imp.ext.bidder.host and resolves into the endpoint template. Impressions sharing a host stay in one request because the ad server resolves a page as a unit. The host is validated with urlutil.IsSafeHost so a publisher config cannot rewrite the outbound URL. Banner only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mirrors the Prebid.js adapter so both transports put the same data in the same place: channel under imp.ext.epom_as, custom parameters merged into imp.ext.data alongside first-party data, and the same ingest limits. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The schema declared four parameters where the Prebid.js adapter accepts six, so a publisher moving a working client-side configuration to Prebid Server would have bidFloor and bidFloorCur silently rejected — and an earlier commit claimed the two were in step.
bidFloor and bidFloorCur were declared in static/bidder-params and documented, but ExtImpEpomAs
carried neither and the adapter read neither, so a publisher's floor was validated and then thrown
away — while the same configuration worked on Prebid.js. They are now on the ext struct and applied
with the same precedence the JS adapter uses: only when the request carries no floor of its own, so
a Price Floors result always wins. Currency defaults to USD when a floor comes from the params.
The custom-parameter caps are gone from both the schema prose and the merge. They were enforced by
dropping entries mid-range over a Go map, whose iteration order is randomised, so which 32 keys
survived changed from request to request and the emitted imp.ext was not reproducible. Type
validation stays in the schema, which is where every other adapter with an object parameter leaves
it. The ad server applies its own ingest limits and ignores the rest.
channel loses its 128-character cap: it existed on this side only, and a value Prebid.js accepts
should not vanish server-side. bidFloorCur loses its ^[A-Z]{3}$ pattern for the same reason — it was
the only occurrence of that clause across every bidder-params file.
Tests go from three supplemental fixtures to seventeen plus two exemplary, covering the paths that
previously had none: 400 and 500 responses, an unparseable body, an unresolvable media type, a
malformed imp.ext, a partial failure across several impressions, an empty seatbid, and a bid whose
impid matches nothing. params_test now exercises both sides of every declared constraint.
3 tasks
The ad server decides geo targeting, IP targeting, IP blacklists and its consent country fallback from the address it sees on the call. On a server-to-server request that address is this host, never the reader, so every one of those decisions was being made about the wrong machine — a visitor in Warsaw priced and targeted as whatever country the Prebid Server instance sits in. The request already carries the right address on device.ip; it simply never reached a header. Forwards it as X-Forwarded-For, IPv6 first, matching the 48 adapters in this repository that already do the same and the 31 of those that carry both families. The exemplary case that covers it also states the headers, which is what makes the harness compare them at all.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
New server-side adapter for Epom Ad Server (
epom_as), banner only, GVL vendor id 849.Maintainer: support@epom.com
Epom Ad Server is white-label: each network runs its own deployment on its own domain, so the
endpoint is templated on a per-impression
hostparameter and the adapter posts tohttps://{{.Host}}/hb/bid. The host pattern in the params schema is the same expressionutil/urlutil.IsSafeHostapplies, so a bid the Prebid.js adapter accepts is one this adapteraccepts too.
placementKeyis sent asimp.tagid;channelandcustomParamsride inimp.ext.epom_asandimp.ext.data, where a key already on the impression wins.bidFloorisapplied only when the request carries no floor of its own, so a Price Floors result always wins.
Tests: 6 exemplary and 17 supplemental fixtures, 89.3% statement coverage. The supplemental set
covers the failure paths — 400 and 500 responses, an unparseable body, an unresolvable media type, a
malformed
imp.ext, a partial failure across several impressions, an empty seatbid, and a bid whoseimpidmatches no impression.params_test.goexercises both sides of every declared constraint.Why a second Epom bidder rather than a change to
epomepomis already registered here, currently disabled. It is the other side of the trade: ademand-side connector pointing at
an.epom.com/ortb, where Epom acts as the buyer.epom_asis thesell-side of an Epom Ad Server deployment, where Epom is the seller: a different endpoint, on the
publisher network's own domain, with a different parameter contract keyed per impression on a
placement identifier. Neither is an alias or a fix of the other, and a publisher integrating one has
no use for the other. Renaming or repurposing
epomwould break the existing configuration ofanyone who re-enables it.
Related