-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update Criteo bid adapter to Prebid 1.x (#2370)
* Convert Criteo adapter to bidderFactory * Add documentation for Prebid 1.0 Criteo adapter * Add support for zone-matching bids on Prebid 1.0 Criteo adapter * Add unit tests to the Prebid 1.0 Criteo adapter * Explicit the fact that Criteo bids are net revenue * Pass currency in Criteo 1.0 adapter * Update Criteo adapter to use PublisherTag if present * Implement fastbid in prebid 1.0 criteo adapter * Pass the bid requests to the Criteo interpret method * Add missing ttl and creativeId fields to Criteo bids * Add 'native' support to the Criteo adapter * Check that the Criteo adapter returned by PublisherTag is not empty * Update criteo prebid adapter to reload publisher tag once auction is finished * Fix 'assign to const' IE errors in Criteo native adapter * Disable the PublisherTag event queue * Fix Criteo adapter on older Prebid versions not using response.body * Fix TypeError if FastBid is outdated * Remove the success variable in tryGetCriteoFastBid * Fix events being overwritten with FastBid * Update PublisherTag loading comment * Use adUnitCode as impid * Add events handlers in Criteo adapter to fix timeouts not treated as such * Add handler for setTargeting event * Move the registeredEvents set higher up to reduce the chances of race conditions * Fix UTests following recent Criteo adapter changes * Add comment linking to the PublisherTag unminified source * Do not return a request in buildRequests on error In some cases, the buildCdbRequest function might return a falsy value, in case of error in creating the request or if we know in advance that this request will return a no-bid. In this case, the buildRequests() method should not return a request, causing a no-bid. * Use loadExternalScript instead of loadScript * Use spec.onTimeout instead of registering an event handler * GDPR support in Criteo adapter (#4) GDPR support in Criteo adapter * Remove BID_WON and SET_TARGETING events from Criteo adapter * Update adapter version * Add support for multi-size in Criteo adapter * Fix support for multi size in Criteo adapter * Update adapterVersion to 7
- Loading branch information
1 parent
8010ba5
commit ad1507b
Showing
3 changed files
with
563 additions
and
0 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 |
---|---|---|
@@ -0,0 +1,262 @@ | ||
import { loadExternalScript } from 'src/adloader'; | ||
import { registerBidder } from 'src/adapters/bidderFactory'; | ||
import { parse } from 'src/url'; | ||
import * as utils from 'src/utils'; | ||
|
||
const ADAPTER_VERSION = 7; | ||
const BIDDER_CODE = 'criteo'; | ||
const CDB_ENDPOINT = '//bidder.criteo.com/cdb'; | ||
const CRITEO_VENDOR_ID = 91; | ||
const INTEGRATION_MODES = { | ||
'amp': 1, | ||
}; | ||
const PROFILE_ID = 207; | ||
|
||
// Unminified source code can be found in: https://github.com/Prebid-org/prebid-js-external-js-criteo/blob/master/dist/prod.js | ||
const PUBLISHER_TAG_URL = '//static.criteo.net/js/ld/publishertag.prebid.js'; | ||
|
||
/** @type {BidderSpec} */ | ||
export const spec = { | ||
code: BIDDER_CODE, | ||
|
||
/** | ||
* @param {object} bid | ||
* @return {boolean} | ||
*/ | ||
isBidRequestValid: bid => ( | ||
!!(bid && bid.params && (bid.params.zoneId || bid.params.networkId)) | ||
), | ||
|
||
/** | ||
* @param {BidRequest[]} bidRequests | ||
* @param {*} bidderRequest | ||
* @return {ServerRequest} | ||
*/ | ||
buildRequests: (bidRequests, bidderRequest) => { | ||
let url; | ||
let data; | ||
|
||
// If publisher tag not already loaded try to get it from fast bid | ||
if (!publisherTagAvailable()) { | ||
window.Criteo = window.Criteo || {}; | ||
window.Criteo.usePrebidEvents = false; | ||
|
||
tryGetCriteoFastBid(); | ||
|
||
// Reload the PublisherTag after the timeout to ensure FastBid is up-to-date and tracking done properly | ||
setTimeout(() => { | ||
loadExternalScript(PUBLISHER_TAG_URL, BIDDER_CODE); | ||
}, bidderRequest.timeout); | ||
} | ||
|
||
if (publisherTagAvailable()) { | ||
const adapter = new Criteo.PubTag.Adapters.Prebid(PROFILE_ID, ADAPTER_VERSION, bidRequests, bidderRequest); | ||
url = adapter.buildCdbUrl(); | ||
data = adapter.buildCdbRequest(); | ||
} else { | ||
const context = buildContext(bidRequests); | ||
url = buildCdbUrl(context); | ||
data = buildCdbRequest(context, bidRequests, bidderRequest); | ||
} | ||
|
||
if (data) { | ||
return { method: 'POST', url, data, bidRequests }; | ||
} | ||
}, | ||
|
||
/** | ||
* @param {*} response | ||
* @param {ServerRequest} request | ||
* @return {Bid[]} | ||
*/ | ||
interpretResponse: (response, request) => { | ||
const body = response.body || response; | ||
|
||
if (publisherTagAvailable()) { | ||
const adapter = Criteo.PubTag.Adapters.Prebid.GetAdapter(request); | ||
if (adapter) { | ||
return adapter.interpretResponse(body, request); | ||
} | ||
} | ||
|
||
const bids = []; | ||
|
||
if (body && body.slots && utils.isArray(body.slots)) { | ||
body.slots.forEach(slot => { | ||
const bidRequest = request.bidRequests.find(b => b.adUnitCode === slot.impid && (!b.params.zoneId || parseInt(b.params.zoneId) === slot.zoneid)); | ||
const bidId = bidRequest.bidId; | ||
const bid = { | ||
requestId: bidId, | ||
cpm: slot.cpm, | ||
currency: slot.currency, | ||
netRevenue: true, | ||
ttl: slot.ttl || 60, | ||
creativeId: bidId, | ||
width: slot.width, | ||
height: slot.height, | ||
} | ||
if (slot.native) { | ||
bid.ad = createNativeAd(bidId, slot.native, bidRequest.params.nativeCallback); | ||
} else { | ||
bid.ad = slot.creative; | ||
} | ||
bids.push(bid); | ||
}); | ||
} | ||
|
||
return bids; | ||
}, | ||
|
||
/** | ||
* @param {TimedOutBid} timeoutData | ||
*/ | ||
onTimeout: (timeoutData) => { | ||
if (publisherTagAvailable()) { | ||
const adapter = Criteo.PubTag.Adapters.Prebid.GetAdapter(timeoutData.auctionId); | ||
adapter.handleBidTimeout(); | ||
} | ||
}, | ||
}; | ||
|
||
/** | ||
* @return {boolean} | ||
*/ | ||
function publisherTagAvailable() { | ||
return typeof Criteo !== 'undefined' && Criteo.PubTag && Criteo.PubTag.Adapters && Criteo.PubTag.Adapters.Prebid; | ||
} | ||
|
||
/** | ||
* @param {BidRequest[]} bidRequests | ||
* @return {CriteoContext} | ||
*/ | ||
function buildContext(bidRequests) { | ||
const url = utils.getTopWindowUrl(); | ||
const queryString = parse(url).search; | ||
|
||
const context = { | ||
url: url, | ||
debug: queryString['pbt_debug'] === '1', | ||
noLog: queryString['pbt_nolog'] === '1', | ||
integrationMode: undefined, | ||
}; | ||
|
||
bidRequests.forEach(bidRequest => { | ||
if (bidRequest.params.integrationMode) { | ||
context.integrationMode = bidRequest.params.integrationMode; | ||
} | ||
}) | ||
|
||
return context; | ||
} | ||
|
||
/** | ||
* @param {CriteoContext} context | ||
* @return {string} | ||
*/ | ||
function buildCdbUrl(context) { | ||
let url = CDB_ENDPOINT; | ||
url += '?profileId=' + PROFILE_ID; | ||
url += '&av=' + String(ADAPTER_VERSION); | ||
url += '&cb=' + String(Math.floor(Math.random() * 99999999999)); | ||
|
||
if (context.integrationMode in INTEGRATION_MODES) { | ||
url += '&im=' + INTEGRATION_MODES[context.integrationMode]; | ||
} | ||
if (context.debug) { | ||
url += '&debug=1'; | ||
} | ||
if (context.noLog) { | ||
url += '&nolog=1'; | ||
} | ||
|
||
return url; | ||
} | ||
|
||
/** | ||
* @param {CriteoContext} context | ||
* @param {BidRequest[]} bidRequests | ||
* @return {*} | ||
*/ | ||
function buildCdbRequest(context, bidRequests, bidderRequest) { | ||
let networkId; | ||
const request = { | ||
publisher: { | ||
url: context.url, | ||
}, | ||
slots: bidRequests.map(bidRequest => { | ||
networkId = bidRequest.params.networkId || networkId; | ||
const slot = { | ||
impid: bidRequest.adUnitCode, | ||
transactionid: bidRequest.transactionId, | ||
auctionId: bidRequest.auctionId, | ||
sizes: bidRequest.sizes.map(size => size[0] + 'x' + size[1]), | ||
}; | ||
if (bidRequest.params.zoneId) { | ||
slot.zoneid = bidRequest.params.zoneId; | ||
} | ||
if (bidRequest.params.publisherSubId) { | ||
slot.publishersubid = bidRequest.params.publisherSubId; | ||
} | ||
if (bidRequest.params.nativeCallback) { | ||
slot.native = true; | ||
} | ||
return slot; | ||
}), | ||
}; | ||
if (networkId) { | ||
request.publisher.networkid = networkId; | ||
} | ||
if (bidderRequest && bidderRequest.gdprConsent) { | ||
request.gdprConsent = { | ||
gdprApplies: !!(bidderRequest.gdprConsent.gdprApplies), | ||
consentData: bidderRequest.gdprConsent.consentString, | ||
consentGiven: !!(bidderRequest.gdprConsent.vendorData && bidderRequest.gdprConsent.vendorData.vendorConsents && | ||
bidderRequest.gdprConsent.vendorData.vendorConsents[ CRITEO_VENDOR_ID.toString(10) ]), | ||
}; | ||
} | ||
return request; | ||
} | ||
|
||
/** | ||
* @param {string} id | ||
* @param {*} payload | ||
* @param {*} callback | ||
* @return {string} | ||
*/ | ||
function createNativeAd(id, payload, callback) { | ||
// Store the callback and payload in a global object to be later accessed from the creative | ||
window.criteo_prebid_native_slots = window.criteo_prebid_native_slots || {}; | ||
window.criteo_prebid_native_slots[id] = { callback, payload }; | ||
|
||
// The creative is in an iframe so we have to get the callback and payload | ||
// from the parent window (doesn't work with safeframes) | ||
return `<script type="text/javascript"> | ||
var win = window; | ||
for (var i = 0; i < 10; ++i) { | ||
win = win.parent; | ||
if (win.criteo_prebid_native_slots) { | ||
var responseSlot = win.criteo_prebid_native_slots["${id}"]; | ||
responseSlot.callback(responseSlot.payload); | ||
break; | ||
} | ||
} | ||
</script>`; | ||
} | ||
|
||
/** | ||
* @return {boolean} | ||
*/ | ||
function tryGetCriteoFastBid() { | ||
try { | ||
const fastBid = localStorage.getItem('criteo_fast_bid'); | ||
if (fastBid !== null) { | ||
eval(fastBid); // eslint-disable-line no-eval | ||
return true; | ||
} | ||
} catch (e) { | ||
// Unable to get fast bid | ||
} | ||
return false; | ||
} | ||
|
||
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,27 @@ | ||
# Overview | ||
|
||
Module Name: Criteo Bidder Adapter | ||
Module Type: Bidder Adapter | ||
Maintainer: pi-direct@criteo.com | ||
|
||
# Description | ||
|
||
Module that connects to Criteo's demand sources. | ||
|
||
# Test Parameters | ||
``` | ||
var adUnits = [ | ||
{ | ||
code: 'banner-ad-div', | ||
sizes: [[300, 250], [728, 90]], | ||
bids: [ | ||
{ | ||
bidder: 'criteo', | ||
params: { | ||
zoneId: 497747 | ||
} | ||
} | ||
] | ||
} | ||
]; | ||
``` |
Oops, something went wrong.