-
Notifications
You must be signed in to change notification settings - Fork 2.4k
StackAdapt Bid Adapter: initial release #12896
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
Merged
patmmccann
merged 3 commits into
prebid:master
from
StackAdapt:stackadapt-bidder-adapter
Apr 2, 2025
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,200 @@ | ||
| import { registerBidder } from '../src/adapters/bidderFactory.js'; | ||
| import { ortbConverter } from '../libraries/ortbConverter/converter.js'; | ||
| import { BANNER, VIDEO } from '../src/mediaTypes.js'; | ||
| import { deepSetValue, logWarn, parseSizesInput, isNumber, isInteger, replaceAuctionPrice, formatQS, isFn, isPlainObject } from '../src/utils.js'; | ||
| import {getUserSyncParams} from '../libraries/userSyncUtils/userSyncUtils.js'; | ||
|
|
||
| const BIDDER_CODE = 'stackadapt'; | ||
| const ENDPOINT_URL = 'https://pjs.srv.stackadapt.com/br'; | ||
| const USER_SYNC_ENDPOINT = 'https://sync.srv.stackadapt.com/sync?nid=pjs'; | ||
| const CURRENCY = 'USD'; | ||
|
|
||
| export const converter = ortbConverter({ | ||
| context: { | ||
| netRevenue: true, | ||
| ttl: 300, | ||
| currency: CURRENCY, | ||
| }, | ||
|
|
||
| request(buildRequest, imps, bidderRequest, context) { | ||
| const request = buildRequest(imps, bidderRequest, context); | ||
| const bid = context.bidRequests[0]; | ||
| request.id = bidderRequest.bidderRequestId | ||
|
|
||
| deepSetValue(request, 'site.publisher.id', bid.params.publisherId); | ||
| deepSetValue(request, 'test', bid.params.testMode); | ||
|
|
||
| return request; | ||
| }, | ||
|
|
||
| imp(buildImp, bidRequest, context) { | ||
| const imp = buildImp(bidRequest, context); | ||
|
|
||
| if (bidRequest.params.placementId) { | ||
| deepSetValue(imp, 'tagid', bidRequest.params.placementId); | ||
| } | ||
| if (bidRequest.params.banner?.expdir) { | ||
| deepSetValue(imp, 'banner.expdir', bidRequest.params.banner.expdir); | ||
| } | ||
|
|
||
| const bidfloor = getBidFloor(bidRequest); | ||
| if (bidfloor) { | ||
| imp.bidfloor = parseFloat(bidfloor); | ||
| imp.bidfloorcur = CURRENCY; | ||
| } | ||
|
|
||
| if (!isNumber(imp.secure)) { | ||
| imp.secure = 1 | ||
| } | ||
|
|
||
| return imp; | ||
| }, | ||
|
|
||
| bidResponse(buildBidResponse, bid, context) { | ||
| const { bidRequest } = context; | ||
| const requestMediaTypes = Object.keys(bidRequest.mediaTypes); | ||
|
|
||
| if (requestMediaTypes.length === 1) { | ||
| context.mediaType = requestMediaTypes[0]; | ||
| } else { | ||
| if (bid.adm?.search(/^(<\?xml|<vast)/i) !== -1) { | ||
| context.mediaType = VIDEO; | ||
| } else { | ||
| context.mediaType = BANNER; | ||
| } | ||
| } | ||
|
|
||
| bid.adm = replaceAuctionPrice(bid.adm, bid.price) | ||
| return buildBidResponse(bid, context); | ||
| } | ||
| }); | ||
|
|
||
| export const spec = { | ||
| code: BIDDER_CODE, | ||
| gvlid: 238, | ||
| supportedMediaTypes: [BANNER, VIDEO], | ||
|
|
||
| isBidRequestValid: function(bid) { | ||
| if (!bid || !bid.params) { | ||
| logWarn('StackAdapt bidder adapter - Missing bid.params'); | ||
| return false; | ||
| } | ||
| if (!bid.params.publisherId) { | ||
| logWarn(BIDDER_CODE + 'StackAdapt bidder adapter - Missing required bid.params.publisherId'); | ||
| return false; | ||
| } | ||
| if (bid.params.bidfloor && isNaN(parseFloat(bid.params.bidfloor))) { | ||
| logWarn('StackAdapt bidder adapter - bid.params.bidfloor must be a float'); | ||
| return false; | ||
| } | ||
|
|
||
| const mediaTypesBanner = bid.mediaTypes?.banner; | ||
| const mediaTypesVideo = bid.mediaTypes?.video; | ||
| if (!mediaTypesBanner && !mediaTypesVideo) { | ||
| logWarn('StackAdapt bidder adapter - bid must contain bid.mediaTypes.banner or bid.mediaTypes.video'); | ||
| return false; | ||
| } | ||
|
|
||
| if (mediaTypesBanner) { | ||
| const sizes = mediaTypesBanner.sizes; | ||
| if (!sizes || parseSizesInput(sizes).length == 0) { | ||
| logWarn('StackAdapt bidder adapter - banner bid requires bid.mediaTypes.banner.sizes of valid format'); | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| if (mediaTypesVideo) { | ||
| if (!mediaTypesVideo.plcmt) { | ||
| logWarn('StackAdapt bidder adapter - video bid requires bid.mediaTypes.video.plcmt'); | ||
| return false; | ||
| } | ||
| if (!mediaTypesVideo.maxduration || !isInteger(mediaTypesVideo.maxduration)) { | ||
| logWarn('StackAdapt bidder adapter - video bid requires bid.mediaTypes.video.maxduration in seconds'); | ||
| return false; | ||
| } | ||
| if (!mediaTypesVideo.api || mediaTypesVideo.api.length === 0) { | ||
| logWarn('StackAdapt bidder adapter - video bid requires bid.mediaTypes.video.api to be an array of supported api frameworks. See ORTB spec for valid values'); | ||
| return false; | ||
| } | ||
| if (!mediaTypesVideo.mimes || mediaTypesVideo.mimes.length === 0) { | ||
| logWarn('StackAdapt bidder adapter - video bid requires bid.mediaTypes.video.mimes to be an array of supported mime types'); | ||
| return false; | ||
| } | ||
| if (!mediaTypesVideo.protocols) { | ||
| logWarn('StackAdapt bidder adapter - video bid bid.mediaTypes.video.protocols to be an array of supported protocols. See the ORTB spec for valid values'); | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
| }, | ||
|
|
||
| buildRequests: function(bidRequests, bidderRequest) { | ||
| if (!Array.isArray(bidRequests)) { | ||
| throw new TypeError('Expected bidRequests to be an array'); | ||
| } | ||
|
|
||
| const data = converter.toORTB({ | ||
| bidRequests: bidRequests, | ||
| bidderRequest: bidderRequest | ||
| }); | ||
|
|
||
| return { | ||
| method: 'POST', | ||
| url: ENDPOINT_URL, | ||
| data: data, | ||
| options: { | ||
| withCredentials: true | ||
| } | ||
| }; | ||
| }, | ||
|
|
||
| interpretResponse: function(response, request) { | ||
| if (!response || !response.body || !request || !request.data) { | ||
| return []; | ||
| } | ||
|
|
||
| const result = converter.fromORTB({ | ||
| response: response.body, | ||
| request: request.data | ||
| }); | ||
|
|
||
| return result.bids; | ||
| }, | ||
|
|
||
| getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) { | ||
| const syncs = []; | ||
|
|
||
| if (syncOptions.pixelEnabled) { | ||
| let params = getUserSyncParams(gdprConsent, uspConsent, gppConsent); | ||
| params = Object.keys(params).length ? `&${formatQS(params)}` : ''; | ||
|
|
||
| syncs.push({ | ||
| type: 'image', | ||
| url: USER_SYNC_ENDPOINT + params | ||
| }); | ||
| } | ||
|
|
||
| return syncs; | ||
| }, | ||
| }; | ||
|
|
||
| function getBidFloor(bidRequest) { | ||
| if (bidRequest.params.bidfloor) { | ||
| return bidRequest.params.bidfloor; | ||
| } | ||
|
|
||
| if (isFn(bidRequest.getFloor)) { | ||
| let floor = bidRequest.getFloor({ | ||
| currency: CURRENCY, | ||
| mediaType: '*', | ||
| size: '*' | ||
| }); | ||
| if (isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === CURRENCY) { | ||
| return floor.floor; | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
|
|
||
| registerBidder(spec); |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| # Overview | ||
|
|
||
| ``` | ||
| Module Name: StackAdapt Bidder Adapter | ||
| Module Type: Bidder Adapter | ||
| Maintainer: pjs@stackadapt.com | ||
| ``` | ||
|
|
||
| # Description | ||
|
|
||
| ``` | ||
| Module is the StackAdapt adapter for Prebid. | ||
| - Supports `banner` and `video` formats | ||
| - Uses `OpenRTB` standard | ||
| ``` | ||
|
|
||
| ### Bid Params | ||
|
|
||
| | Name | Scope | Description | Example | Type | | ||
| |---------------|----------|-----------------------------|--------------------|----------| | ||
| | `publisherId` | required | StackAdapt provided id | `'15'` | `string` | | ||
| | `placementId` | optional | StackAdapt provided id | `'2'` | `string` | | ||
| | `banner` | optional | banner supporting expdir | `{expdir: [1, 3]}` | `object` | | ||
| | `bidfloor` | optional | bid floor price | `1.01` | `float` | | ||
|
|
||
| # Test Parameters | ||
| ```js | ||
| var adUnits = [ | ||
| // Banner adUnit | ||
| { | ||
| code: 'div-test-ad-1', | ||
| mediaTypes: { | ||
| banner: { | ||
| sizes: [[300, 250]], | ||
| } | ||
| }, | ||
| bids: [{ | ||
| bidder: 'stackadapt', | ||
| params: { | ||
| publisherId: '123', | ||
| testMode: 1 | ||
| } | ||
| }] | ||
| }, | ||
| // Video adUnit | ||
| { | ||
| code: 'div-test-ad-2', | ||
| mediaTypes: { | ||
| video: { | ||
| context: 'instream', | ||
| playerSize: [640, 360], | ||
| mimes: ['video/mp4'], | ||
| protocols: [2, 3, 5, 6], | ||
| maxduration: 60, | ||
| api: [1, 2], | ||
| playback_method: ['auto_play_sound_off'], | ||
| plcmt: 1 | ||
| } | ||
| }, | ||
| bids: [{ | ||
| bidder: 'stackadapt', | ||
| params: { | ||
| publisherId: '123', | ||
| testMode: 1 | ||
| } | ||
| }] | ||
| } | ||
| ]; | ||
| ``` | ||
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.