forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
GumGum Adapter for Prebid.js 1.0 (prebid#1966)
* GumGum Adapter for Prebid.js 1.0 * removed getUserSyncs. Give cpm a non-zero value when bidRequest is for test unit so DFP chooses it. * parsing slot ID as integer from params * ADSS-78 removed bidderCode from response. Correctly parsing bidRequest.sizes to account for 1-dimensional array.
- Loading branch information
Showing
3 changed files
with
319 additions
and
442 deletions.
There are no files selected for viewing
This file contains 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 |
---|---|---|
@@ -1,176 +1,170 @@ | ||
const bidfactory = require('src/bidfactory'); | ||
const bidmanager = require('src/bidmanager'); | ||
const utils = require('src/utils'); | ||
const adloader = require('src/adloader'); | ||
var adaptermanager = require('src/adaptermanager'); | ||
|
||
const BIDDER_CODE = 'gumgum'; | ||
const CALLBACKS = {}; | ||
|
||
const GumgumAdapter = function GumgumAdapter() { | ||
const bidEndpoint = `https://g2.gumgum.com/hbid/imp`; | ||
|
||
let topWindow; | ||
let topScreen; | ||
let pageViewId; | ||
const requestCache = {}; | ||
const throttleTable = {}; | ||
const defaultThrottle = 3e4; | ||
const dtCredentials = { member: 'YcXr87z2lpbB' }; | ||
import * as utils from 'src/utils' | ||
|
||
import { config } from 'src/config' | ||
import { registerBidder } from 'src/adapters/bidderFactory' | ||
|
||
const BIDDER_CODE = 'gumgum' | ||
const ALIAS_BIDDER_CODE = ['gg'] | ||
const BID_ENDPOINT = `https://g2.gumgum.com/hbid/imp` | ||
const DT_CREDENTIALS = { member: 'YcXr87z2lpbB' } | ||
const TIME_TO_LIVE = 60 | ||
let browserParams = {}; | ||
|
||
// TODO: potential 0 values for browserParams sent to ad server | ||
function _getBrowserParams() { | ||
let topWindow | ||
let topScreen | ||
if (browserParams.vw) { | ||
// we've already initialized browserParams, just return it. | ||
return browserParams | ||
} | ||
|
||
try { | ||
topWindow = global.top; | ||
topScreen = topWindow.screen; | ||
} catch (error) { | ||
return utils.logError(error); | ||
} | ||
|
||
function _getTimeStamp() { | ||
return new Date().getTime(); | ||
} | ||
|
||
function _getDigiTrustQueryParams() { | ||
function getDigiTrustId () { | ||
var digiTrustUser = (window.DigiTrust && window.DigiTrust.getUser) ? window.DigiTrust.getUser(dtCredentials) : {}; | ||
return (digiTrustUser && digiTrustUser.success && digiTrustUser.identity) || ''; | ||
}; | ||
|
||
let digiTrustId = getDigiTrustId(); | ||
// Verify there is an ID and this user has not opted out | ||
if (!digiTrustId || (digiTrustId.privacy && digiTrustId.privacy.optout)) { | ||
return {}; | ||
} | ||
return { | ||
'dt': digiTrustId.id | ||
}; | ||
utils.logError(error); | ||
return browserParams | ||
} | ||
|
||
function _callBids({ bids }) { | ||
const browserParams = { | ||
vw: topWindow.innerWidth, | ||
vh: topWindow.innerHeight, | ||
sw: topScreen.width, | ||
sh: topScreen.height, | ||
pu: topWindow.location.href, | ||
ce: navigator.cookieEnabled, | ||
dpr: topWindow.devicePixelRatio || 1 | ||
}; | ||
|
||
utils._each(bids, bidRequest => { | ||
const { bidId | ||
, params = {} | ||
, placementCode | ||
} = bidRequest; | ||
const timestamp = _getTimeStamp(); | ||
const trackingId = params.inScreen; | ||
const nativeId = params['native']; | ||
const slotId = params.inSlot; | ||
const bid = { tmax: $$PREBID_GLOBAL$$.cbTimeout }; | ||
|
||
/* slot/native ads need the placement id */ | ||
switch (true) { | ||
case !!(params.inImage): bid.pi = 1; break; | ||
case !!(params.inScreen): bid.pi = 2; break; | ||
case !!(params.inSlot): bid.pi = 3; break; | ||
case !!(params['native']): bid.pi = 5; break; | ||
default: return utils.logWarn( | ||
`[GumGum] No product selected for the placement ${placementCode}` + | ||
', please check your implementation.' | ||
); | ||
} | ||
|
||
/* throttle based on the latest request for this product */ | ||
const productId = bid.pi; | ||
const requestKey = productId + '|' + placementCode; | ||
const throttle = throttleTable[productId]; | ||
const latestRequest = requestCache[requestKey]; | ||
if (latestRequest && throttle && (timestamp - latestRequest) < throttle) { | ||
return utils.logWarn( | ||
`[GumGum] The refreshes for "${placementCode}" with the params ` + | ||
`${JSON.stringify(params)} should be at least ${throttle / 1e3}s apart.` | ||
); | ||
} | ||
/* update the last request */ | ||
requestCache[requestKey] = timestamp; | ||
|
||
/* tracking id is required for in-image and in-screen */ | ||
if (trackingId) bid.t = trackingId; | ||
/* native ads require a native placement id */ | ||
if (nativeId) bid.ni = nativeId; | ||
/* slot ads require a slot id */ | ||
if (slotId) bid.si = slotId; | ||
|
||
/* include the pageViewId, if any */ | ||
if (pageViewId) bid.pv = pageViewId; | ||
|
||
const cachedBid = Object.assign({ | ||
placementCode, | ||
id: bidId | ||
}, bid); | ||
|
||
const callback = { jsonp: `$$PREBID_GLOBAL$$.handleGumGumCB['${bidId}']` }; | ||
CALLBACKS[bidId] = _handleGumGumResponse(cachedBid); | ||
const query = Object.assign(callback, browserParams, bid, _getDigiTrustQueryParams()); | ||
const bidCall = `${bidEndpoint}?${utils.parseQueryStringParameters(query)}`; | ||
adloader.loadScript(bidCall); | ||
}); | ||
browserParams = { | ||
vw: topWindow.innerWidth, | ||
vh: topWindow.innerHeight, | ||
sw: topScreen.width, | ||
sh: topScreen.height, | ||
pu: utils.getTopWindowUrl(), | ||
ce: utils.cookiesAreEnabled(), | ||
dpr: topWindow.devicePixelRatio || 1 | ||
} | ||
|
||
const _handleGumGumResponse = cachedBidRequest => (bidResponse = {}) => { | ||
const { pi: productId | ||
} = cachedBidRequest; | ||
const { ad = {} | ||
, pag = {} | ||
, thms: throttle | ||
} = bidResponse; | ||
/* cache the pageViewId */ | ||
if (pag && pag.pvid) pageViewId = pag.pvid; | ||
if (ad && ad.id) { | ||
/* set the new throttle */ | ||
throttleTable[productId] = throttle || defaultThrottle; | ||
/* create the bid */ | ||
const bid = bidfactory.createBid(1); | ||
const { t: trackingId | ||
} = pag; | ||
bidResponse.request = cachedBidRequest; | ||
const encodedResponse = encodeURIComponent(JSON.stringify(bidResponse)); | ||
const gumgumAdLoader = `<script> | ||
(function (context, topWindow, d, s, G) { | ||
G = topWindow.GUMGUM; | ||
d = topWindow.document; | ||
function loadAd() { | ||
topWindow.GUMGUM.pbjs("${trackingId}", ${productId}, "${encodedResponse}" , context); | ||
} | ||
if (G) { | ||
loadAd(); | ||
} else { | ||
topWindow.$$PREBID_GLOBAL$$.loadScript("https://js.gumgum.com/services.js", loadAd); | ||
} | ||
}(window, top)); | ||
</script>`; | ||
Object.assign(bid, { | ||
cpm: ad.price, | ||
ad: gumgumAdLoader, | ||
width: ad.width, | ||
height: ad.height, | ||
bidderCode: BIDDER_CODE | ||
}); | ||
bidmanager.addBidResponse(cachedBidRequest.placementCode, bid); | ||
} else { | ||
const noBid = bidfactory.createBid(2); | ||
noBid.bidderCode = BIDDER_CODE; | ||
bidmanager.addBidResponse(cachedBidRequest.placementCode, noBid); | ||
} | ||
delete CALLBACKS[cachedBidRequest.id]; | ||
return browserParams | ||
} | ||
|
||
function getWrapperCode(wrapper, data) { | ||
return wrapper.replace('AD_JSON', window.btoa(JSON.stringify(data))) | ||
} | ||
|
||
// TODO: use getConfig() | ||
function _getDigiTrustQueryParams() { | ||
function getDigiTrustId () { | ||
var digiTrustUser = (window.DigiTrust && window.DigiTrust.getUser) ? window.DigiTrust.getUser(DT_CREDENTIALS) : {}; | ||
return (digiTrustUser && digiTrustUser.success && digiTrustUser.identity) || ''; | ||
}; | ||
|
||
window.$$PREBID_GLOBAL$$.handleGumGumCB = CALLBACKS; | ||
|
||
let digiTrustId = getDigiTrustId(); | ||
// Verify there is an ID and this user has not opted out | ||
if (!digiTrustId || (digiTrustId.privacy && digiTrustId.privacy.optout)) { | ||
return {}; | ||
} | ||
return { | ||
callBids: _callBids | ||
'dt': digiTrustId.id | ||
}; | ||
}; | ||
|
||
adaptermanager.registerBidAdapter(new GumgumAdapter(), 'gumgum'); | ||
} | ||
|
||
/** | ||
* Determines whether or not the given bid request is valid. | ||
* | ||
* @param {BidRequest} bid The bid params to validate. | ||
* @return boolean True if this is a valid bid, and false otherwise. | ||
*/ | ||
function isBidRequestValid (bid) { | ||
const { | ||
params, | ||
adUnitCode | ||
} = bid; | ||
|
||
switch (true) { | ||
case !!(params.inScreen): break; | ||
case !!(params.inSlot): break; | ||
default: | ||
utils.logWarn(`[GumGum] No product selected for the placement ${adUnitCode}, please check your implementation.`); | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
/** | ||
* Make a server request from the list of BidRequests. | ||
* | ||
* @param {validBidRequests[]} - an array of bids | ||
* @return ServerRequest Info describing the request to the server. | ||
*/ | ||
function buildRequests (validBidRequests) { | ||
const bids = []; | ||
utils._each(validBidRequests, bidRequest => { | ||
const timeout = config.getConfig('bidderTimeout'); | ||
const { | ||
bidId, | ||
params = {}, | ||
transactionId | ||
} = bidRequest; | ||
const data = {} | ||
|
||
if (params.inScreen) { | ||
data.t = params.inScreen; | ||
data.pi = 2; | ||
} | ||
if (params.inSlot) { | ||
data.si = parseInt(params.inSlot, 10); | ||
data.pi = 3; | ||
} | ||
|
||
module.exports = GumgumAdapter; | ||
bids.push({ | ||
id: bidId, | ||
tmax: timeout, | ||
tId: transactionId, | ||
pi: data.pi, | ||
sizes: bidRequest.sizes, | ||
url: BID_ENDPOINT, | ||
method: 'GET', | ||
data: Object.assign(data, _getBrowserParams(), _getDigiTrustQueryParams()) | ||
}) | ||
}); | ||
return bids; | ||
} | ||
|
||
/** | ||
* Unpack the response from the server into a list of bids. | ||
* | ||
* @param {*} serverResponse A successful response from the server. | ||
* @return {Bid[]} An array of bids which were nested inside the server. | ||
*/ | ||
function interpretResponse (serverResponse, bidRequest) { | ||
const bidResponses = [] | ||
const serverResponseBody = serverResponse.body | ||
const { | ||
ad: { | ||
price: cpm, | ||
id: creativeId, | ||
markup | ||
}, | ||
cw: wrapper | ||
} = serverResponseBody | ||
let isTestUnit = (bidRequest.data && bidRequest.data.pi === 3 && bidRequest.data.si === 9) | ||
let [width, height] = utils.parseSizesInput(bidRequest.sizes)[0].split('x') | ||
|
||
if (creativeId) { | ||
bidResponses.push({ | ||
// dealId: DEAL_ID, | ||
// referrer: REFERER, | ||
ad: wrapper ? getWrapperCode(wrapper, Object.assign({}, serverResponseBody, { bidRequest })) : markup, | ||
cpm: isTestUnit ? 0.1 : cpm, | ||
creativeId, | ||
currency: 'USD', | ||
height, | ||
netRevenue: true, | ||
requestId: bidRequest.id, | ||
ttl: TIME_TO_LIVE, | ||
width | ||
}) | ||
} | ||
return bidResponses | ||
} | ||
|
||
export const spec = { | ||
code: BIDDER_CODE, | ||
aliases: ALIAS_BIDDER_CODE, | ||
isBidRequestValid, | ||
buildRequests, | ||
interpretResponse | ||
} | ||
registerBidder(spec) |
This file contains 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,40 @@ | ||
# Overview | ||
|
||
``` | ||
Module Name: GumGum Bidder Adapter | ||
Module Type: Bidder Adapter | ||
Maintainer: engineering@gumgum.com | ||
``` | ||
|
||
# Description | ||
|
||
GumGum adapter for Prebid.js 1.0 | ||
|
||
# Test Parameters | ||
``` | ||
var adUnits = [ | ||
{ | ||
code: 'test-div', | ||
sizes: [[300, 250]], | ||
bids: [ | ||
{ | ||
bidder: 'gumgum', | ||
params: { | ||
inSlot: '9' // GumGum Slot ID given to the client | ||
} | ||
} | ||
] | ||
},{ | ||
code: 'test-div', | ||
sizes: [[300, 50]], | ||
bids: [ | ||
{ | ||
bidder: 'gumgum', | ||
params: { | ||
inScreen: 'ggumtest' // GumGum Zone ID given to the client | ||
} | ||
} | ||
] | ||
} | ||
]; | ||
``` |
Oops, something went wrong.