New Adapter: StackAdapt - #4724
Conversation
Code coverage summaryNote:
stackadaptRefer here for heat map coverage report |
Code coverage summaryNote:
stackadaptRefer here for heat map coverage report |
|
Hi @bsardo , I was wondering if there's a rough idea when this might get reviewed? Thanks! |
|
Hi @bsardo , wondering if you had a chance to look at this PR yet? Any ETA would be much appreciated, thanks! |
Code coverage summaryNote:
stackadaptRefer here for heat map coverage report |
| @@ -0,0 +1,24 @@ | |||
| endpoint: "https://pbs.srv.stackadapt.com/br?publisher_id={{.PublisherID}}&supply_id={{.SupplyId}}" | |||
There was a problem hiding this comment.
Verified endpoint is live
curl -i --location --request POST https://pbs.srv.stackadapt.com/br?publisher_id=123&supply_id=123
[1] 10611
HTTP/2 204
endpoint-load-metrics-bin: Mbr1e7a5ok1ASVoeoaC28A4/
date: Thu, 23 Apr 2026 13:48:34 GMT
x-envoy-upstream-service-time: 0
server: envoy
| endpoint: "https://pbs.srv.stackadapt.com/br?publisher_id={{.PublisherID}}&supply_id={{.SupplyId}}" | ||
| endpointCompression: gzip | ||
| maintainer: | ||
| email: pjs@stackadapt.com |
There was a problem hiding this comment.
Is this a personal email address? We require all email addresses to be a mailbox.
There was a problem hiding this comment.
pjs@stackadapt.com is a shared team mailbox monitored by a group of employees on our Prebid team.
| endpointCompression: gzip | ||
| maintainer: | ||
| email: pjs@stackadapt.com | ||
| gvlVendorID: 238 |
There was a problem hiding this comment.
Verified
curl https://vendor-list.consensu.org/v3/vendor-list.json | jq '.vendors."238"'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 859k 100 859k 0 0 863k 0 --:--:-- --:--:-- --:--:-- 864k
{
"id": 238,
"name": "StackAdapt Inc.",
"purposes": [
1,
3,
4,
5,
6
],
"legIntPurposes": [
2,
7,
8,
9,
10,
11
],
"flexiblePurposes": [
2,
7,
8,
11
],
"specialPurposes": [
1,
2,
3
],
"features": [
1,
2,
3
],
"specialFeatures": [
1,
2
],
"cookieMaxAgeSeconds": 31536000,
"usesCookies": true,
"cookieRefresh": true,
"urls": [
{
"langId": "en",
"privacy": "https://www.stackadapt.com/privacy-policy",
"legIntClaim": "https://www.stackadapt.com/privacy-policy"
}
],
"usesNonCookieAccess": true,
"dataRetention": {
"stdRetention": 365,
"purposes": {
"7": 3650,
"8": 180,
"9": 4320,
"10": 180,
"11": 180
},
"specialPurposes": {
"1": 60,
"2": 1,
"3": 1825
}
},
"dataDeclaration": [
1,
2,
3,
4,
6,
8,
9,
10,
11
],
"deviceStorageDisclosureUrl": "https://s3.amazonaws.com/stackadapt_public/disclosures.json"
}
| redirect: | ||
| url: "https://sync.srv.stackadapt.com/sync?nid=pbs&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redirect={{.RedirectURL}}" |
Code coverage summaryNote:
stackadaptRefer here for heat map coverage report |
Code coverage summaryNote:
stackadaptRefer here for heat map coverage report |
|
Hi @bsardo thanks for the review, I've addressed the comments if you could take another look. Thanks! |
|
Hey @bsardo just wanted to check in if you had a chance to review the updates. Thanks! |
Code coverage summaryNote:
stackadaptRefer here for heat map coverage report |
Code coverage summaryNote:
stackadaptRefer here for heat map coverage report |
|
Hi @bsardo just wanted to follow up on this now that we have one approval. Let me know if there is anything I can do to help, thanks. |
Code coverage summaryNote:
stackadaptRefer here for heat map coverage report |
Code coverage summaryNote:
stackadaptRefer here for heat map coverage report |
Code coverage summaryNote:
stackadaptRefer here for heat map coverage report |
Code coverage summaryNote:
stackadaptRefer here for heat map coverage report |
| return nil, []error{err} | ||
| } | ||
|
|
||
| body, err := json.Marshal(request) |
There was a problem hiding this comment.
Use jsonutil.Marshal instead of encoding/json.
The encoding/json import exists only for this one call (no json.RawMessage in the file), so switch to jsonutil.Marshal(request) and drop the import.
"Adapters must use
jsonutil.Marshalandjsonutil.Unmarshalinstead of the Go standard package functions, as those are not optimized for Prebid Server's high performance needs."
— [Prebid Server · Adding a New Bidder (Go)](https://docs.prebid.org/prebid-server/developers/add-new-bidder-go.html)
There was a problem hiding this comment.
Done. Switched to jsonutil instead of encoding/json.
| publisherID = saExt.PublisherId | ||
| supplyID = saExt.SupplyId |
There was a problem hiding this comment.
Multi-imp: publisherId/supplyId collapse to the last imp (stackadapt.go:91-92). They're reassigned each loop iteration with no accumulation, so the endpoint URL query (publisher_id/supply_id) and the request-level site/app.publisher.id set by setPublisherID both end up with the last imp's values. Since site.publisher.id is the standard OpenRTB publisher identity shared by every imp in the request, a request whose imps carry different publisherId would be attributed entirely to the last one (the per-imp imp.ext.bidder values do still reach you in the body, so this is really a question of intended behavior). Your tests only cover the all-same case. Could you clarify the intended multi-imp contract — validate that all imps share publisherId/supplyId and return BadInput on mismatch, or split into per-publisher requests?
There was a problem hiding this comment.
Thanks for flagging, revised to validate all publisherId and supplyId are the same and return error if not.
| "type": "object", | ||
| "description": "Banner-specific parameters", | ||
| "properties": { | ||
| "expdir": { |
There was a problem hiding this comment.
banner.expdir (and bidfloor) re-declare standard OpenRTB fields (static/bidder-params/stackadapt.json). The adapter copies them onto imp.banner.expdir / imp.bidfloor, which a publisher can set directly in the standard request. banner.expdir in particular isn't declared as a param by any other adapter in the repo — consider dropping it and reading imp.banner.expdir. (bidfloor as a param is common enough that it's fine to keep if you prefer.)
publisherId/supplyIdare placed into the endpoint query string viamacros.ResolveMacroswithouturl.QueryEscape(stackadapt.go:71); a value containing&would inject extra query parameters. Escape them, or add apattern/maxLengthto the schema. (No SSRF — scheme and host are fixed in the yaml.)getNativeAdm(:213) unmarshals the adm into amap[string]interface{}just to check for thenativekey, then re-parses the same bytes withjsonparser. You can drop the map and branch onjsonparser.Getalone.params_test.go: add data-type-mismatch cases forbidfloor(e.g."high") andexpdir(e.g.["a"])."Please include tests for required fields, optional fields, conditional fields such as
oneOf, regex filters, and data type mismatches."
— [Prebid Server · Adding a New Bidder (Go)](https://docs.prebid.org/prebid-server/developers/add-new-bidder-go.html)
There was a problem hiding this comment.
Thanks, I have now addressed these:
banner.expdirparam: keeping it intentionally. It's a documented optional bidder param in our existing Prebid.js adapter to allow overriding as requested by a partner. It's there for parity across our integrations rather than a re-declaration of a standard field.- Query escaping:
publisherId/supplyIdnow go throughurl.QueryEscapebefore macro resolution. Also added test. - getNativeAdm: simplified to branch on jsonparser.Get alone.
- params_test.go: added data-type-mismatch cases for
bidfloorandexpdir.
…lution, simplify native adm unwrap, add test cases
Code coverage summaryNote:
stackadaptRefer here for heat map coverage report |
|
Hi @postindustria-code thanks for your review. I've addressed the comments if you could take another look. Thanks! |
|
Thanks @franklong-sa — re-reviewed, everything's addressed and verified on the branch:
Verified: LGTM — APPROVE. |
Code coverage summaryNote:
stackadaptRefer here for heat map coverage report |
|
Hi @bsardo we've received the 2 required approvals. Can we proceed with merging the changes in? Thanks! |
Code coverage summaryNote:
stackadaptRefer here for heat map coverage report |
|
Hi @bsardo @przemkaczmarek @postindustria-code thanks for the reviews and approvals. Just want to follow up can we merge in now? |


This PR creates a new bidder adapter for StackAdapt
Related docs update: prebid/prebid.github.io#6496