diff --git a/integrationExamples/gpt/pbjs_example_gpt.html b/integrationExamples/gpt/pbjs_example_gpt.html
index 536bc5a655d..88d4839d984 100644
--- a/integrationExamples/gpt/pbjs_example_gpt.html
+++ b/integrationExamples/gpt/pbjs_example_gpt.html
@@ -302,6 +302,16 @@
channelCode: 2264002816, //REQUIRED
dimId: 9 //REQUIRED
}
+ },
+ {
+ bidder: 'openxoutstream',
+ params: {
+ unit: '53943996499',
+ delDomain: 'se-demo-d.openx.net',
+ publisher_page_url: 'yieldmo.com',
+ width: '300',
+ height: '250',
+ }
}
]
diff --git a/modules/adkernelBidAdapter.js b/modules/adkernelBidAdapter.js
index dffcaacec3d..9bdab13de7b 100644
--- a/modules/adkernelBidAdapter.js
+++ b/modules/adkernelBidAdapter.js
@@ -3,6 +3,7 @@ import { BANNER, VIDEO } from 'src/mediaTypes';
import {registerBidder} from 'src/adapters/bidderFactory';
import find from 'core-js/library/fn/array/find';
import includes from 'core-js/library/fn/array/includes';
+import {parse as parseUrl} from 'src/url'
const VIDEO_TARGETING = ['mimes', 'minduration', 'maxduration', 'protocols',
'startdelay', 'linearity', 'boxingallowed', 'playbackmethod', 'delivery',
@@ -22,13 +23,13 @@ export const spec = {
'zoneId' in bidRequest.params && !isNaN(Number(bidRequest.params.zoneId));
},
buildRequests: function(bidRequests, bidderRequest) {
- let impDispatch = dispatchImps(bidRequests);
+ let impDispatch = dispatchImps(bidRequests, bidderRequest.refererInfo);
const gdprConsent = bidderRequest.gdprConsent;
const auctionId = bidderRequest.auctionId;
const requests = [];
Object.keys(impDispatch).forEach(host => {
Object.keys(impDispatch[host]).forEach(zoneId => {
- const request = buildRtbRequest(impDispatch[host][zoneId], auctionId, gdprConsent);
+ const request = buildRtbRequest(impDispatch[host][zoneId], auctionId, gdprConsent, bidderRequest.refererInfo);
requests.push({
method: 'GET',
url: `${window.location.protocol}//${host}/rtbg`,
@@ -96,8 +97,9 @@ registerBidder(spec);
/**
* Dispatch impressions by ad network host and zone
*/
-function dispatchImps(bidRequests) {
- return bidRequests.map(buildImp)
+function dispatchImps(bidRequests, refererInfo) {
+ let secure = (refererInfo && refererInfo.referer.indexOf('https:') === 0);
+ return bidRequests.map(bidRequest => buildImp(bidRequest, secure))
.reduce((acc, curr, index) => {
let bidRequest = bidRequests[index];
let zoneId = bidRequest.params.zoneId;
@@ -112,7 +114,7 @@ function dispatchImps(bidRequests) {
/**
* Builds parameters object for single impression
*/
-function buildImp(bidRequest) {
+function buildImp(bidRequest, secure) {
const imp = {
'id': bidRequest.bidId,
'tagid': bidRequest.adUnitCode
@@ -137,7 +139,7 @@ function buildImp(bidRequest) {
.forEach(param => imp.video[param] = bidRequest.params.video[param]);
}
}
- if (utils.getTopWindowLocation().protocol === 'https:') {
+ if (secure) {
imp.secure = 1;
}
return imp;
@@ -149,7 +151,7 @@ function buildImp(bidRequest) {
* @return Array[Array[Number]]
*/
function canonicalizeSizesArray(sizes) {
- if (sizes.length == 2 && !utils.isArray(sizes[0])) {
+ if (sizes.length === 2 && !utils.isArray(sizes[0])) {
return [sizes];
}
return sizes;
@@ -160,12 +162,14 @@ function canonicalizeSizesArray(sizes) {
* @param imps collection of impressions
* @param auctionId
* @param gdprConsent
+ * @param refInfo
+ * @return Object complete rtb request
*/
-function buildRtbRequest(imps, auctionId, gdprConsent) {
+function buildRtbRequest(imps, auctionId, gdprConsent, refInfo) {
let req = {
'id': auctionId,
'imp': imps,
- 'site': createSite(),
+ 'site': createSite(refInfo),
'at': 1,
'device': {
'ip': 'caller',
@@ -197,12 +201,20 @@ function getLanguage() {
/**
* Creates site description object
*/
-function createSite() {
- var location = utils.getTopWindowLocation();
- return {
- 'domain': location.hostname,
- 'page': location.href.split('?')[0]
+function createSite(refInfo) {
+ let url = parseUrl(refInfo.referer);
+ let result = {
+ 'domain': url.hostname,
+ 'page': url.protocol + '://' + url.hostname + url.pathname
};
+ if (self === top && document.referrer) {
+ result.ref = document.referrer;
+ }
+ let keywords = document.getElementsByTagName('meta')['keywords'];
+ if (keywords && keywords.content) {
+ result.keywords = keywords.content;
+ }
+ return result;
}
/**
diff --git a/modules/adliveBidAdapter.js b/modules/adliveBidAdapter.js
new file mode 100644
index 00000000000..54a11270133
--- /dev/null
+++ b/modules/adliveBidAdapter.js
@@ -0,0 +1,68 @@
+import * as utils from 'src/utils';
+import { registerBidder } from 'src/adapters/bidderFactory';
+import { BANNER } from 'src/mediaTypes';
+
+const BIDDER_CODE = 'adlive';
+const ENDPOINT_URL = 'https://api.publishers.adlive.io/get?pbjs=1';
+const CURRENCY = 'USD';
+const TIME_TO_LIVE = 360;
+
+export const spec = {
+ code: BIDDER_CODE,
+ supportedMediaTypes: [BANNER],
+
+ isBidRequestValid: function(bid) {
+ return !!(bid.params.hashes && utils.isArray(bid.params.hashes));
+ },
+
+ buildRequests: function(validBidRequests) {
+ let requests = [];
+
+ utils._each(validBidRequests, function(bid) {
+ requests.push({
+ method: 'POST',
+ url: ENDPOINT_URL,
+ options: {
+ contentType: 'application/json',
+ withCredentials: true
+ },
+ data: JSON.stringify({
+ transaction_id: bid.bidId,
+ hashes: utils.getBidIdParameter('hashes', bid.params)
+ }),
+ bidId: bid.bidId
+ });
+ });
+
+ return requests;
+ },
+
+ interpretResponse: function(serverResponse, bidRequest) {
+ try {
+ const response = serverResponse.body;
+ const bidResponses = [];
+
+ utils._each(response, function(bidResponse) {
+ if (!bidResponse.is_passback) {
+ bidResponses.push({
+ requestId: bidRequest.bidId,
+ cpm: bidResponse.price,
+ width: bidResponse.size[0],
+ height: bidResponse.size[1],
+ creativeId: bidResponse.hash,
+ currency: CURRENCY,
+ netRevenue: false,
+ ttl: TIME_TO_LIVE,
+ ad: bidResponse.content
+ });
+ }
+ });
+
+ return bidResponses;
+ } catch (err) {
+ utils.logError(err);
+ return [];
+ }
+ }
+};
+registerBidder(spec);
diff --git a/modules/adliveBidAdapter.md b/modules/adliveBidAdapter.md
new file mode 100644
index 00000000000..4fc6a112e82
--- /dev/null
+++ b/modules/adliveBidAdapter.md
@@ -0,0 +1,28 @@
+# Overview
+```
+Module Name: Adlive Bid Adapter
+Module Type: Bidder Adapter
+Maintainer: traffic@adlive.io
+```
+
+# Description
+Module that connects to Adlive's server for bids.
+Currently module supports only banner mediaType.
+
+# Test Parameters
+```
+ var adUnits = [{
+ code: '/test/div',
+ mediaTypes: {
+ banner: {
+ sizes: [[300, 250]]
+ }
+ },
+ bids: [{
+ bidder: 'adlive',
+ params: {
+ hashes: ['1e100887dd614b0909bf6c49ba7f69fdd1360437']
+ }
+ }]
+ }];
+```
\ No newline at end of file
diff --git a/modules/appnexusBidAdapter.js b/modules/appnexusBidAdapter.js
index f65a3409684..aaec207dc1e 100644
--- a/modules/appnexusBidAdapter.js
+++ b/modules/appnexusBidAdapter.js
@@ -11,7 +11,6 @@ const VIDEO_TARGETING = ['id', 'mimes', 'minduration', 'maxduration',
'startdelay', 'skippable', 'playback_method', 'frameworks'];
const USER_PARAMS = ['age', 'external_uid', 'segments', 'gender', 'dnt', 'language'];
const APP_DEVICE_PARAMS = ['geo', 'device_id']; // appid is collected separately
-const DEBUG_PARAMS = ['enabled', 'dongle', 'member_id', 'debug_timeout'];
const NATIVE_MAPPING = {
body: 'description',
cta: 'ctatext',
@@ -78,32 +77,6 @@ export const spec = {
};
}
- let debugObj = {};
- let debugObjParams = {};
- const debugCookieName = 'apn_prebid_debug';
- const debugCookie = getCookie(debugCookieName) || null;
-
- if (debugCookie) {
- try {
- debugObj = JSON.parse(debugCookie);
- } catch (e) {
- utils.logError('AppNexus Debug Auction Cookie Error:\n\n' + e);
- }
- } else {
- const debugBidRequest = find(bidRequests, hasDebug);
- if (debugBidRequest && debugBidRequest.debug) {
- debugObj = debugBidRequest.debug;
- }
- }
-
- if (debugObj && debugObj.enabled) {
- Object.keys(debugObj)
- .filter(param => includes(DEBUG_PARAMS, param))
- .forEach(param => {
- debugObjParams[param] = debugObj[param];
- });
- }
-
const memberIdBid = find(bidRequests, hasMemberId);
const member = memberIdBid ? parseInt(memberIdBid.params.member, 10) : 0;
@@ -126,11 +99,6 @@ export const spec = {
payload.app = appIdObj;
}
- if (debugObjParams.enabled) {
- payload.debug = debugObjParams;
- utils.logInfo('AppNexus Debug Auction Settings:\n\n' + JSON.stringify(debugObjParams, null, 4));
- }
-
if (bidderRequest && bidderRequest.gdprConsent) {
// note - objects for impbus use underscore instead of camelCase
payload.gdpr_consent = {
@@ -186,22 +154,6 @@ export const spec = {
}
});
}
-
- if (serverResponse.debug && serverResponse.debug.debug_info) {
- let debugHeader = 'AppNexus Debug Auction for Prebid\n\n';
- let debugText = debugHeader + serverResponse.debug.debug_info;
- debugText = debugText
- .replace(/(
| | )/gm, '\t') // Tables
- .replace(/(<\/td>|<\/th>)/gm, '\n') // Tables
- .replace(/^ /gm, '') // Remove leading
- .replace(/( \n| )/gm, '\n') //
- .replace(/(.*)<\/h1>/gm, '\n\n===== $1 =====\n\n') // Header H1
- .replace(/(.*)<\/h[2-6]>/gm, '\n\n*** $1 ***\n\n') // Headers
- .replace(/(<([^>]+)>)/igm, ''); // Remove any other tags
- utils.logMessage('AppNexus Debug Auction Glossary: https://wiki.appnexus.com/x/qwmHAg');
- utils.logMessage(debugText);
- }
-
return bids;
},
@@ -477,15 +429,6 @@ function hasAppId(bid) {
return !!bid.params.app
}
-function hasDebug(bid) {
- return !!bid.debug
-}
-
-function getCookie(name) {
- let m = window.document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]*)\\s*(;|$)');
- return m ? decodeURIComponent(m[2]) : null;
-}
-
function getRtbBid(tag) {
return tag && tag.ads && tag.ads.length && find(tag.ads, ad => ad.rtb);
}
diff --git a/modules/beachfrontBidAdapter.js b/modules/beachfrontBidAdapter.js
index ccb45d0a041..064b647f64d 100644
--- a/modules/beachfrontBidAdapter.js
+++ b/modules/beachfrontBidAdapter.js
@@ -1,11 +1,13 @@
import * as utils from 'src/utils';
+import { parse as parseUrl } from 'src/url';
+import { config } from 'src/config';
import { registerBidder } from 'src/adapters/bidderFactory';
import { Renderer } from 'src/Renderer';
import { VIDEO, BANNER } from 'src/mediaTypes';
import find from 'core-js/library/fn/array/find';
import includes from 'core-js/library/fn/array/includes';
-const ADAPTER_VERSION = '1.3';
+const ADAPTER_VERSION = '1.4';
const ADAPTER_NAME = 'BFIO_PREBID';
const OUTSTREAM = 'outstream';
@@ -237,6 +239,19 @@ function isBannerBidValid(bid) {
return isBannerBid(bid) && getBannerBidParam(bid, 'appId') && getBannerBidParam(bid, 'bidfloor');
}
+function getTopWindowLocation(bidderRequest) {
+ let url = bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer;
+ return parseUrl(config.getConfig('pageUrl') || url, { decodeSearchAsString: true });
+}
+
+function getTopWindowReferrer() {
+ try {
+ return window.top.document.referrer;
+ } catch (e) {
+ return '';
+ }
+}
+
function getVideoTargetingParams(bid) {
return Object.keys(Object(bid.params.video))
.filter(param => includes(VIDEO_TARGETING, param))
@@ -252,7 +267,7 @@ function createVideoRequestData(bid, bidderRequest) {
let video = getVideoTargetingParams(bid);
let appId = getVideoBidParam(bid, 'appId');
let bidfloor = getVideoBidParam(bid, 'bidfloor');
- let topLocation = utils.getTopWindowLocation();
+ let topLocation = getTopWindowLocation(bidderRequest);
let payload = {
isPrebid: true,
appId: appId,
@@ -294,8 +309,8 @@ function createVideoRequestData(bid, bidderRequest) {
}
function createBannerRequestData(bids, bidderRequest) {
- let topLocation = utils.getTopWindowLocation();
- let referrer = utils.getTopWindowReferrer();
+ let topLocation = getTopWindowLocation(bidderRequest);
+ let topReferrer = getTopWindowReferrer();
let slots = bids.map(bid => {
return {
slot: bid.adUnitCode,
@@ -309,8 +324,8 @@ function createBannerRequestData(bids, bidderRequest) {
page: topLocation.href,
domain: topLocation.hostname,
search: topLocation.search,
- secure: topLocation.protocol === 'https:' ? 1 : 0,
- referrer: referrer,
+ secure: topLocation.protocol.indexOf('https') === 0 ? 1 : 0,
+ referrer: topReferrer,
ua: navigator.userAgent,
deviceOs: getOsVersion(),
isMobile: isMobile() ? 1 : 0,
diff --git a/modules/consumableBidAdapter.js b/modules/consumableBidAdapter.js
index 7d8cc1b2deb..8ed0f6dfc91 100644
--- a/modules/consumableBidAdapter.js
+++ b/modules/consumableBidAdapter.js
@@ -127,7 +127,7 @@ export const spec = {
if (syncOptions.iframeEnabled) {
return [{
type: 'iframe',
- url: '//s.zkcdn.net/ss/' + siteId + '.html'
+ url: '//sync.serverbid.com/ss/' + siteId + '.html'
}];
} else {
utils.logWarn(bidder + ': Please enable iframe based user syncing.');
diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js
index 0595fc890f0..284c3f57406 100755
--- a/modules/criteoBidAdapter.js
+++ b/modules/criteoBidAdapter.js
@@ -3,8 +3,10 @@ import { registerBidder } from 'src/adapters/bidderFactory';
import { parse } from 'src/url';
import * as utils from 'src/utils';
import find from 'core-js/library/fn/array/find';
+import JSEncrypt from 'jsencrypt/bin/jsencrypt';
+import sha256 from 'crypto-js/sha256';
-const ADAPTER_VERSION = 11;
+const ADAPTER_VERSION = 14;
const BIDDER_CODE = 'criteo';
const CDB_ENDPOINT = '//bidder.criteo.com/cdb';
const CRITEO_VENDOR_ID = 91;
@@ -17,6 +19,13 @@ const PROFILE_ID_PUBLISHERTAG = 185;
// 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';
+export const FAST_BID_PUBKEY = `-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDO1BjAITkFTtP0IMzmF7qsqhpu
+y1dGaTPHnjMU9mRZsrnfR3C0sEN5pYEzEcFRPnkJjJuhH8Rnh5+CE+LcKg0Z8ZZ7
+OmOSj0/qnYTAYCu0cR5LiyWG79KlIgUyMbp92ulGg24gAyGrVn4+v/4c53WlOEUp
+4YWvb82G0CD5NcDNpQIDAQAB
+-----END PUBLIC KEY-----`;
+
/** @type {BidderSpec} */
export const spec = {
code: BIDDER_CODE,
@@ -251,6 +260,34 @@ function createNativeAd(id, payload, callback) {
`;
}
+export function cryptoVerify(key, hash, code) {
+ var jse = new JSEncrypt();
+ jse.setPublicKey(key);
+ return jse.verify(code, hash, sha256);
+}
+
+function validateFastBid(fastBid) {
+ // The value stored must contain the file's encrypted hash as first line
+ const firstLineEnd = fastBid.indexOf('\n');
+ const firstLine = fastBid.substr(0, firstLineEnd).trim();
+ if (firstLine.substr(0, 9) !== '// Hash: ') {
+ utils.logWarn('No hash found in FastBid');
+ return false;
+ }
+
+ // Remove the hash part from the locally stored value
+ const fileEncryptedHash = firstLine.substr(9);
+ const publisherTag = fastBid.substr(firstLineEnd + 1);
+
+ // Verify the hash using cryptography
+ try {
+ return cryptoVerify(FAST_BID_PUBKEY, fileEncryptedHash, publisherTag);
+ } catch (e) {
+ utils.logWarn('Failed to verify Criteo FastBid');
+ return undefined;
+ }
+}
+
/**
* @return {boolean}
*/
@@ -258,13 +295,17 @@ function tryGetCriteoFastBid() {
try {
const fastBid = localStorage.getItem('criteo_fast_bid');
if (fastBid !== null) {
- eval(fastBid); // eslint-disable-line no-eval
- return true;
+ if (validateFastBid(fastBid) === false) {
+ utils.logWarn('Invalid Criteo FastBid found');
+ localStorage.removeItem('criteo_fast_bid');
+ } else {
+ utils.logInfo('Using Criteo FastBid');
+ eval(fastBid); // eslint-disable-line no-eval
+ }
}
} catch (e) {
// Unable to get fast bid
}
- return false;
}
registerBidder(spec);
diff --git a/modules/dspxBidAdapter.js b/modules/dspxBidAdapter.js
new file mode 100644
index 00000000000..6cf0b32a7d7
--- /dev/null
+++ b/modules/dspxBidAdapter.js
@@ -0,0 +1,96 @@
+import * as utils from 'src/utils';
+import {config} from 'src/config';
+import {registerBidder} from 'src/adapters/bidderFactory';
+
+const BIDDER_CODE = 'dspx';
+const ENDPOINT_URL = 'https://buyer.dspx.tv/request/';
+
+export const spec = {
+ code: BIDDER_CODE,
+ aliases: ['dspx'],
+ isBidRequestValid: function(bid) {
+ return !!(bid.params.placement);
+ },
+ buildRequests: function(validBidRequests, bidderRequest) {
+ return validBidRequests.map(bidRequest => {
+ const params = bidRequest.params;
+ const sizes = utils.parseSizesInput(bidRequest.sizes)[0];
+ const width = sizes.split('x')[0];
+ const height = sizes.split('x')[1];
+ const placementId = params.placement;
+
+ const rnd = Math.floor(Math.random() * 99999999999);
+ const referrer = encodeURIComponent(bidderRequest.refererInfo.referer);
+ const bidId = bidRequest.bidId;
+ const payload = {
+ _f: 'html',
+ alternative: 'prebid_js',
+ inventory_item_id: placementId,
+ srw: width,
+ srh: height,
+ idt: 100,
+ rnd: rnd,
+ ref: referrer,
+ bid_id: bidId,
+ };
+ if (params.pfilter !== undefined) {
+ payload.pfilter = params.pfilter;
+ }
+ if (params.bcat !== undefined) {
+ payload.bcat = params.bcat;
+ }
+ if (params.dvt !== undefined) {
+ payload.dvt = params.dvt;
+ }
+ return {
+ method: 'GET',
+ url: ENDPOINT_URL,
+ data: objectToQueryString(payload),
+ }
+ });
+ },
+ interpretResponse: function(serverResponse, bidRequest) {
+ const bidResponses = [];
+ const response = serverResponse.body;
+ const crid = response.crid || 0;
+ const cpm = response.cpm / 1000000 || 0;
+ if (cpm !== 0 && crid !== 0) {
+ const dealId = response.dealid || '';
+ const currency = response.currency || 'EUR';
+ const netRevenue = (response.netRevenue === undefined) ? true : response.netRevenue;
+ const referrer = utils.getTopWindowUrl();
+ const bidResponse = {
+ requestId: response.bid_id,
+ cpm: cpm,
+ width: response.width,
+ height: response.height,
+ creativeId: crid,
+ dealId: dealId,
+ currency: currency,
+ netRevenue: netRevenue,
+ ttl: config.getConfig('_bidderTimeout'),
+ referrer: referrer,
+ ad: response.adTag
+ };
+ bidResponses.push(bidResponse);
+ }
+ return bidResponses;
+ }
+}
+
+function objectToQueryString(obj, prefix) {
+ let str = [];
+ let p;
+ for (p in obj) {
+ if (obj.hasOwnProperty(p)) {
+ let k = prefix ? prefix + '[' + p + ']' : p;
+ let v = obj[p];
+ str.push((v !== null && typeof v === 'object')
+ ? objectToQueryString(v, k)
+ : encodeURIComponent(k) + '=' + encodeURIComponent(v));
+ }
+ }
+ return str.join('&');
+}
+
+registerBidder(spec);
diff --git a/modules/dspxBidAdapter.md b/modules/dspxBidAdapter.md
new file mode 100644
index 00000000000..362f4fbcb69
--- /dev/null
+++ b/modules/dspxBidAdapter.md
@@ -0,0 +1,73 @@
+# Overview
+
+```
+Module Name: Dspx Bidder Adapter
+Module Type: Bidder Adapter
+Maintainer: prebid@dspx.tv
+```
+
+# Description
+
+Dspx adapter for Prebid.js 1.0
+
+# Test Parameters
+```
+ var adUnits = [
+ {
+ code: 'test-div',
+ mediaTypes: {
+ banner: {
+ sizes: [
+ [300, 250],
+ [300, 600],
+ ], // a display size
+ }
+ },
+ bids: [
+ {
+ bidder: "dspx",
+ params: {
+ placement: '101',
+ pfilter: {
+ floorprice: 1000000, // EUR * 1,000,000
+ private_auction: 1, // Is private auction? 0 - no, 1 - yes
+ deals: [
+ "666-9315-d58a7f9a-bdb9-4450-a3a2-046ba8ab2489;3;25000000;dspx-tv",// DEAL_ID;at;bidfloor;wseat1,wseat2;wadomain1,wadomain2"
+ "666-9315-d58a7f9a-bdb9-4450-a6a2-046ba8ab2489;3;25000000;dspx-tv",// DEAL_ID;at;bidfloor;wseat1,wseat2;wadomain1,wadomain2"
+ ],
+ geo: { // set client geo info manually (empty for auto detect)
+ lat: 52.52437, // Latitude from -90.0 to +90.0, where negative is south.
+ lon: 13.41053, // Longitude from -180.0 to +180.0, where negative is west
+ type: 1, // Source of location data: 1 - GPS/Location Services, 2 - IP Address, 3 - User provided (e.g. registration form)
+ country: 'DE', // Region of a country using FIPS 10-4 notation
+ region: 'DE-BE', // Region code using ISO-3166-2; 2-letter state code if USA.
+ regionfips104: 'GM', // Region of a country using FIPS 10-4 notation
+ city: 'BER', // City using United Nations Code for Trade and Transport Locations
+ zip: '10115' // Zip or postal code.
+ }
+ },
+ bcat: "IAB2,IAB4", // List of Blocked Categories (IAB) - comma separated
+ dvt: "desktop|smartphone|tv|tablet" // DeVice Type (autodetect if not exists)
+ }
+ }
+ ]
+ },{
+ code: 'test-div',
+ mediaTypes: {
+ banner: {
+ sizes: [[320, 50]], // a mobile size
+ }
+ },
+ bids: [
+ {
+ bidder: "dspx",
+ params: {
+ placement: 101
+ }
+ }
+ ]
+ }
+ ];
+```
+
+Required param field is only `placement`.
\ No newline at end of file
diff --git a/modules/gumgumBidAdapter.js b/modules/gumgumBidAdapter.js
index 55a22c23ef8..33baaf83548 100644
--- a/modules/gumgumBidAdapter.js
+++ b/modules/gumgumBidAdapter.js
@@ -13,76 +13,6 @@ const TIME_TO_LIVE = 60
let browserParams = {};
let pageViewId = null
-function hasTopAccess () {
- var hasTopAccess = false
- try { hasTopAccess = !!top.document } catch (e) {}
- return hasTopAccess
-}
-
-function isInSafeFrame (windowRef) {
- const w = windowRef || window
- if (w.$sf) return w.$sf
- else if (hasTopAccess() && w !== top) return isInSafeFrame(w.parent)
- return null
-}
-
-function getGoogleTag (windowRef) {
- try {
- const w = windowRef || window
- var GOOGLETAG = null
- if ('googletag' in w) {
- GOOGLETAG = w.googletag
- } else if (w !== top) {
- GOOGLETAG = getGoogleTag(w.parent)
- }
- return GOOGLETAG
- } catch (error) {
- utils.logError('Error getting googletag ', error)
- return null
- }
-}
-
-function getAMPContext (windowRef) {
- const w = windowRef || window
- var context = null
- var nameJSON = null
- if (utils.isPlainObject(w.context)) {
- context = w.context
- } else {
- try {
- nameJSON = JSON.parse(w.name || null)
- } catch (error) {
- utils.logError('Error getting w.name', error)
- }
- if (utils.isPlainObject(nameJSON)) {
- context = nameJSON._context || (nameJSON.attributes ? nameJSON.attributes._context : null)
- }
- if (utils.isPlainObject(w.AMP_CONTEXT_DATA)) {
- context = w.AMP_CONTEXT_DATA
- }
- }
- return context
-}
-
-function getJCSI () {
- const entrypointOffset = 7
- const inFrame = (window.top && window.top !== window)
- const frameType = (!inFrame ? 1 : (isInSafeFrame() ? 2 : (hasTopAccess() ? 3 : 4)))
- const context = []
- if (getAMPContext()) {
- context.push(1)
- }
- if (getGoogleTag()) {
- context.push(2)
- }
- const jcsi = {
- ep: entrypointOffset,
- fc: frameType,
- ctx: context
- }
- return JSON.stringify(jcsi)
-}
-
// TODO: potential 0 values for browserParams sent to ad server
function _getBrowserParams() {
let topWindow
@@ -111,7 +41,10 @@ function _getBrowserParams() {
pu: topUrl,
ce: utils.cookiesAreEnabled(),
dpr: topWindow.devicePixelRatio || 1,
- jcsi: getJCSI()
+ jcsi: {
+ t: 0,
+ rq: 7
+ }
}
ggad = (topUrl.match(/#ggad=(\w+)$/) || [0, 0])[1]
if (ggad) {
diff --git a/modules/improvedigitalBidAdapter.js b/modules/improvedigitalBidAdapter.js
index 2cc1d8b39b0..54eb3bb6574 100644
--- a/modules/improvedigitalBidAdapter.js
+++ b/modules/improvedigitalBidAdapter.js
@@ -5,7 +5,7 @@ import { config } from 'src/config';
const BIDDER_CODE = 'improvedigital';
export const spec = {
- version: '4.3.0',
+ version: '4.4.0',
code: BIDDER_CODE,
aliases: ['id'],
@@ -78,11 +78,24 @@ export const spec = {
bid.cpm = parseFloat(bidObject.price);
bid.creativeId = bidObject.crid;
bid.currency = bidObject.currency ? bidObject.currency.toUpperCase() : 'USD';
- if (utils.isNumber(bidObject.lid)) {
+
+ // Deal ID. Composite ads can have multiple line items and the ID of the first
+ // dealID line item will be used.
+ if (utils.isNumber(bidObject.lid) && bidObject.buying_type === 'deal_id') {
bid.dealId = bidObject.lid;
- } else if (typeof bidObject.lid === 'object' && bidObject.lid['1']) {
- bid.dealId = bidObject.lid['1'];
+ } else if (Array.isArray(bidObject.lid) &&
+ Array.isArray(bidObject.buying_type) &&
+ bidObject.lid.length === bidObject.buying_type.length) {
+ let isDeal = false;
+ bidObject.buying_type.forEach((bt, i) => {
+ if (isDeal) return;
+ if (bt === 'deal_id') {
+ isDeal = true;
+ bid.dealId = bidObject.lid[i];
+ }
+ });
}
+
bid.height = bidObject.h;
bid.netRevenue = bidObject.isNet ? bidObject.isNet : false;
bid.requestId = bidObject.id;
diff --git a/modules/openxBidAdapter.js b/modules/openxBidAdapter.js
index 952e706ef7d..ee1fa58a4e9 100644
--- a/modules/openxBidAdapter.js
+++ b/modules/openxBidAdapter.js
@@ -8,7 +8,7 @@ import {parse} from 'src/url';
const SUPPORTED_AD_TYPES = [BANNER, VIDEO];
const BIDDER_CODE = 'openx';
const BIDDER_CONFIG = 'hb_pb';
-const BIDDER_VERSION = '2.1.4';
+const BIDDER_VERSION = '2.1.5';
let shouldSendBoPixel = true;
@@ -222,6 +222,10 @@ function buildCommonQueryParamsFromBids(bids, bidderRequest) {
}
}
+ if (bids[0].crumbs && bids[0].crumbs.pubcid) {
+ defaultParams.pubcid = bids[0].crumbs.pubcid;
+ }
+
return defaultParams;
}
diff --git a/modules/openxoutstreamBidAdapter.js b/modules/openxoutstreamBidAdapter.js
new file mode 100644
index 00000000000..dde101f25d5
--- /dev/null
+++ b/modules/openxoutstreamBidAdapter.js
@@ -0,0 +1,216 @@
+import { config } from 'src/config';
+import { registerBidder } from 'src/adapters/bidderFactory';
+import * as utils from 'src/utils';
+import { BANNER } from 'src/mediaTypes';
+
+const SUPPORTED_AD_TYPES = [BANNER];
+const BIDDER_CODE = 'openxoutstream';
+const BIDDER_CONFIG = 'hb_pb_ym';
+const BIDDER_VERSION = '1.0.0';
+const CURRENCY = 'USD';
+const NET_REVENUE = true;
+const TIME_TO_LIVE = 300;
+const YM_SCRIPT = `!function(e,t){if(void 0===t._ym){var a=Math.round(5*Math.random()/3)+'';t._ym='';var m=e.createElement('script');m.type='text/javascript',m.async=!0,m.src='//static.yieldmo.com/ym.'+a+'.js',(e.getElementsByTagName('head')[0]||e.getElementsByTagName('body')[0]).appendChild(m)}else t._ym instanceof String||void 0===t._ym.chkPls||t._ym.chkPls()}(document,window);`;
+const PLACEMENT_ID = '1986307928000988495';
+const PUBLISHER_ID = '1986307525700126029';
+const CR_ID = '2052941939925262540';
+const AD_ID = '1991358644725162800';
+
+export const spec = {
+ code: BIDDER_CODE,
+ supportedMediaTypes: SUPPORTED_AD_TYPES,
+ isBidRequestValid: function(bidRequest) {
+ if (bidRequest.params.delDomain) {
+ return !!bidRequest.params.unit || utils.deepAccess(bidRequest, 'mediaTypes.banner.sizes.length') > 0;
+ }
+ return false;
+ },
+ buildRequests: function(bidRequests, bidderRequest) {
+ if (bidRequests.length === 0) {
+ return [];
+ }
+ let requests = [];
+ requests.push(buildOXBannerRequest(bidRequests, bidderRequest));
+ return requests;
+ },
+ interpretResponse: function(serverResponse, serverRequest) {
+ return handleVastResponse(serverResponse, serverRequest.payload)
+ },
+
+ transformBidParams: function(params, isOpenRtb) {
+ return utils.convertTypes({
+ 'unit': 'string',
+ }, params);
+ }
+};
+
+function getViewportDimensions(isIfr) {
+ let width;
+ let height;
+ let tWin = window;
+ let body;
+
+ if (isIfr) {
+ let tDoc;
+ try {
+ tWin = window.top;
+ tDoc = window.top.document;
+ } catch (e) {
+ return;
+ }
+ body = tDoc.body;
+
+ width = tWin.innerWidth || docEl.clientWidth || body.clientWidth;
+ height = tWin.innerHeight || docEl.clientHeight || body.clientHeight;
+ } else {
+ width = tWin.innerWidth || docEl.clientWidth;
+ height = tWin.innerHeight || docEl.clientHeight;
+ }
+
+ return `${width}x${height}`;
+}
+
+function buildCommonQueryParamsFromBids(bids, bidderRequest) {
+ const isInIframe = utils.inIframe();
+ let defaultParams;
+ defaultParams = {
+ ju: config.getConfig('pageUrl') || utils.getTopWindowUrl(),
+ jr: utils.getTopWindowReferrer(),
+ ch: document.charSet || document.characterSet,
+ res: `${screen.width}x${screen.height}x${screen.colorDepth}`,
+ ifr: isInIframe,
+ tz: new Date().getTimezoneOffset(),
+ tws: getViewportDimensions(isInIframe),
+ be: 1,
+ bc: bids[0].params.bc || `${BIDDER_CONFIG}_${BIDDER_VERSION}`,
+ auid: '540141567',
+ dddid: utils._map(bids, bid => bid.transactionId).join(','),
+ openrtb: '%7B%22mimes%22%3A%5B%22video%2Fmp4%22%5D%7D',
+ nocache: new Date().getTime(),
+ vht: bids[0].params.height || bids[0].sizes[0][1],
+ vwd: bids[0].params.width || bids[0].sizes[0][0]
+ };
+
+ if (utils.deepAccess(bidderRequest, 'gdprConsent')) {
+ let gdprConsentConfig = bidderRequest.gdprConsent;
+
+ if (gdprConsentConfig.consentString !== undefined) {
+ defaultParams.gdpr_consent = gdprConsentConfig.consentString;
+ }
+
+ if (gdprConsentConfig.gdprApplies !== undefined) {
+ defaultParams.gdpr = gdprConsentConfig.gdprApplies ? 1 : 0;
+ }
+
+ if (config.getConfig('consentManagement.cmpApi') === 'iab') {
+ defaultParams.x_gdpr_f = 1;
+ }
+ }
+
+ return defaultParams;
+}
+
+function buildOXBannerRequest(bids, bidderRequest) {
+ let queryParams = buildCommonQueryParamsFromBids(bids, bidderRequest);
+ queryParams.aus = utils._map(bids, bid => utils.parseSizesInput(bid.sizes).join(',')).join('|');
+
+ if (bids.some(bid => bid.params.doNotTrack)) {
+ queryParams.ns = 1;
+ }
+
+ if (bids.some(bid => bid.params.coppa)) {
+ queryParams.tfcd = 1;
+ }
+
+ let url = `https://${bids[0].params.delDomain}/v/1.0/avjp`
+ return {
+ method: 'GET',
+ url: url,
+ data: queryParams,
+ payload: {'bids': bids}
+ };
+}
+
+function handleVastResponse(response, serverResponse) {
+ const body = response.body
+ let bidResponses = [];
+ if (response !== undefined && body.vastUrl !== '' && body.pub_rev && body.pub_rev > 0) {
+ const openHtmlTag = '';
+ const closeHtmlTag = '';
+ const sdkScript = createSdkScript().outerHTML;
+ const placementDiv = createPlacementDiv();
+ placementDiv.dataset.pId = PUBLISHER_ID;
+ const placementDivString = placementDiv.outerHTML;
+ const adResponse = getTemplateAdResponse(body.vastUrl);
+ const adResponseString = JSON.stringify(adResponse);
+ const ymAdsScript = '';
+
+ let bidResponse = {};
+ bidResponse.requestId = serverResponse.bids[0].bidId;
+ bidResponse.bidderCode = BIDDER_CODE;
+ bidResponse.netRevenue = NET_REVENUE;
+ bidResponse.currency = CURRENCY;
+ bidResponse.cpm = Number(body.pub_rev) / 1000;
+ bidResponse.creativeId = body.adid;
+ bidResponse.height = body.height;
+ bidResponse.width = body.width;
+ bidResponse.vastUrl = body.vastUrl;
+ bidResponse.ttl = TIME_TO_LIVE;
+ bidResponse.mediaType = BANNER;
+ bidResponse.ad = openHtmlTag + placementDivString + ymAdsScript + sdkScript + closeHtmlTag;
+
+ bidResponses.push(bidResponse);
+ }
+ return bidResponses;
+}
+registerBidder(spec);
+
+// HELPER FUNCTIONS
+function createSdkScript() {
+ const script = document.createElement('script');
+ script.innerHTML = YM_SCRIPT;
+ return script;
+}
+function createPlacementDiv() {
+ const div = document.createElement('div');
+ div.id = `ym_${PLACEMENT_ID}`;
+ div.classList.add('ym');
+ div.dataset.lfId = CR_ID;
+ return div
+}
+
+/**
+ * Create a nativeplay template with the placement id and vastURL.
+ * @param vastUrl
+ */
+const getTemplateAdResponse = (vastUrl) => {
+ return {
+ availability_zone: 'us-east-1a',
+ data: [
+ {
+ ads: [
+ {
+ actions: {},
+ adv_id: AD_ID,
+ configurables: {
+ cta_button_copy: 'Learn More',
+ vast_click_tracking: 'true',
+ vast_url: vastUrl,
+ },
+ cr_id: CR_ID,
+ }
+ ],
+ column_count: 1,
+ configs: {
+ allowable_height: '248',
+ header_copy: 'You May Like',
+ ping: 'true',
+ },
+ creative_format_id: 40,
+ css: '',
+ placement_id: PLACEMENT_ID,
+ }
+ ],
+ nc: 0,
+ };
+};
diff --git a/modules/openxoutstreamBidAdapter.md b/modules/openxoutstreamBidAdapter.md
new file mode 100644
index 00000000000..a77b4560f97
--- /dev/null
+++ b/modules/openxoutstreamBidAdapter.md
@@ -0,0 +1,41 @@
+# Overview
+
+```
+Module Name: OpenX Outstream Bidder Adapter
+Module Type: Bidder Adapter
+Maintainer: opensource@yieldmo.com, jimmy.tu@openx.com
+Note: Ads will only render in mobile
+```
+
+# Description
+
+Module that connects to OpenX's demand sources for outstream to Yieldmo.
+
+This bid adapter supports Banner.
+
+# Example
+```javascript
+var adUnits = [
+ {
+ code: 'test-div',
+ sizes: [[300, 250]], // a display size
+ mediaTypes: {'banner': {}},
+ bids: [
+ {
+ bidder: 'openxoutstream',
+ params: {
+ unit: '53943996499',
+ delDomain: 'se-demo-d.openx.net',
+ publisher_page_url: 'yieldmo.com',
+ width: '300',
+ height: '250',
+ }
+ }
+ ]
+ }
+];
+```
+
+# Additional Details
+[Banner Ads](https://docs.openx.com/Content/developers/containers/prebid-adapter.html)
+
diff --git a/modules/polymorphBidAdapter.js b/modules/polymorphBidAdapter.js
index 8d07a66d0da..da5f7f711ec 100644
--- a/modules/polymorphBidAdapter.js
+++ b/modules/polymorphBidAdapter.js
@@ -2,8 +2,18 @@ import * as utils from 'src/utils';
import { registerBidder } from 'src/adapters/bidderFactory';
import { BANNER } from 'src/mediaTypes';
+const PROTOCOL = getProtocol();
const BIDDER_CODE = 'polymorph';
const URL = '//api.adsnative.com/v1/ad-template.json';
+const USER_SYNC_URL = PROTOCOL + '//rudy.adsnative.com/cm.gif';
+
+function getProtocol() {
+ if (location.protocol && location.protocol.indexOf('https') === 0) {
+ return 'https:';
+ } else {
+ return 'http:';
+ }
+}
export const polymorphAdapterSpec = {
code: BIDDER_CODE,
@@ -17,7 +27,7 @@ export const polymorphAdapterSpec = {
* @return boolean True if this is a valid bid, and false otherwise.
*/
isBidRequestValid: function(bid) {
- return !!(bid.params.placementId);
+ return !!(bid.params.placementId) || (!!(bid.params.network_key) && !!(bid.params.widget_id) && !!(bid.params.cat));
},
/**
@@ -31,11 +41,18 @@ export const polymorphAdapterSpec = {
var payload = {
url: utils.getTopWindowUrl(),
ref: utils.getTopFrameReferrer(),
- zid: bid.params.placementId,
sizes: bid.sizes,
hb: 1,
- hb_source: 'prebid'
+ hb_source: 'prebid',
+ bid_id: bid.bidId,
};
+ if (bid.params.placementId) {
+ payload.zid = bid.params.placementId;
+ } else if (bid.params.network_key && bid.params.widget_id && bid.params.cat) {
+ payload.network_key = bid.params.network_key;
+ payload.widget_id = bid.params.widget_id;
+ payload.cat = bid.params.cat;
+ }
Object.keys(bid.params).forEach(function(key) {
if (key != 'defaultWidth' && key != 'defaultHeight') {
payload[key] = bid.params[key];
@@ -100,6 +117,14 @@ export const polymorphAdapterSpec = {
utils.logError(e);
}
return bidResponses;
+ },
+ getUserSyncs: function(syncOptions) {
+ if (syncOptions.pixelEnabled) {
+ return [{
+ type: 'image',
+ url: USER_SYNC_URL
+ }];
+ }
}
}
diff --git a/modules/prebidServerBidAdapter/config.js b/modules/prebidServerBidAdapter/config.js
index 74eb4a95744..835d09e2010 100644
--- a/modules/prebidServerBidAdapter/config.js
+++ b/modules/prebidServerBidAdapter/config.js
@@ -2,7 +2,6 @@
export const S2S_VENDORS = {
'appnexus': {
adapter: 'prebidServer',
- cookieSet: false,
enabled: true,
endpoint: '//prebid.adnxs.com/pbs/v1/openrtb2/auction',
syncEndpoint: '//prebid.adnxs.com/pbs/v1/cookie_sync',
@@ -10,7 +9,6 @@ export const S2S_VENDORS = {
},
'rubicon': {
adapter: 'prebidServer',
- cookieSet: false,
enabled: true,
endpoint: '//prebid-server.rubiconproject.com/openrtb2/auction',
syncEndpoint: '//prebid-server.rubiconproject.com/cookie_sync',
diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js
index 5d23a0366ea..80724630da9 100644
--- a/modules/prebidServerBidAdapter/index.js
+++ b/modules/prebidServerBidAdapter/index.js
@@ -3,7 +3,6 @@ import bidfactory from 'src/bidfactory';
import * as utils from 'src/utils';
import { ajax } from 'src/ajax';
import { STATUS, S2S, EVENTS } from 'src/constants';
-import { cookieSet } from 'src/cookie.js';
import adaptermanager from 'src/adaptermanager';
import { config } from 'src/config';
import { VIDEO } from 'src/mediaTypes';
@@ -44,7 +43,6 @@ config.setDefaults({
* @property {boolean} [cacheMarkup] whether to cache the adm result
* @property {string} [adapter] adapter code to use for S2S
* @property {string} [syncEndpoint] endpoint URL for syncing cookies
- * @property {string} [cookieSetUrl] url for cookie set library, if passed then cookieSet is enabled
*/
function setS2sConfig(options) {
if (options.defaultVendor) {
@@ -355,10 +353,8 @@ const LEGACY_PROTOCOL = {
* Protocol spec for OpenRTB endpoint
* e.g., https:///v1/openrtb2/auction
*/
+let bidIdMap = {};
const OPEN_RTB_PROTOCOL = {
-
- bidMap: {},
-
buildRequest(s2sBidRequest, bidRequests, adUnits) {
let imps = [];
let aliases = {};
@@ -368,8 +364,7 @@ const OPEN_RTB_PROTOCOL = {
adUnit.bids.forEach(bid => {
// OpenRTB response contains the adunit code and bidder name. These are
// combined to create a unique key for each bid since an id isn't returned
- const key = `${adUnit.code}${bid.bidder}`;
- this.bidMap[key] = bid;
+ bidIdMap[`${adUnit.code}${bid.bidder}`] = bid.bid_id;
// check for and store valid aliases to add to the request
if (adaptermanager.aliasRegistry[bid.bidder]) {
@@ -481,17 +476,22 @@ const OPEN_RTB_PROTOCOL = {
// a seatbid object contains a `bid` array and a `seat` string
response.seatbid.forEach(seatbid => {
(seatbid.bid || []).forEach(bid => {
- const bidRequest = utils.getBidRequest(
- this.bidMap[`${bid.impid}${seatbid.seat}`].bid_id,
- bidderRequests
- );
+ let bidRequest;
+ let key = `${bid.impid}${seatbid.seat}`;
+ if (bidIdMap[key]) {
+ bidRequest = utils.getBidRequest(
+ bidIdMap[key],
+ bidderRequests
+ );
+ }
const cpm = bid.price;
const status = cpm !== 0 ? STATUS.GOOD : STATUS.NO_BID;
- let bidObject = bidfactory.createBid(status, bidRequest);
+ let bidObject = bidfactory.createBid(status, bidRequest || {
+ bidder: seatbid.seat,
+ src: TYPE
+ });
- bidObject.source = TYPE;
- bidObject.bidderCode = seatbid.seat;
bidObject.cpm = cpm;
let serverResponseTimeMs = utils.deepAccess(response, ['ext', 'responsetimemillis', seatbid.seat].join('.'));
@@ -618,11 +618,6 @@ export function PrebidServer() {
});
bidderRequests.forEach(bidderRequest => events.emit(EVENTS.BIDDER_DONE, bidderRequest));
-
- if (result.status === 'no_cookie' && _s2sConfig.cookieSet && typeof _s2sConfig.cookieSetUrl === 'string') {
- // cookie sync
- cookieSet(_s2sConfig.cookieSetUrl);
- }
} catch (error) {
utils.logError(error);
}
diff --git a/modules/pubmaticBidAdapter.js b/modules/pubmaticBidAdapter.js
index 452f6149091..354addc6def 100644
--- a/modules/pubmaticBidAdapter.js
+++ b/modules/pubmaticBidAdapter.js
@@ -1,6 +1,7 @@
import * as utils from 'src/utils';
import { registerBidder } from 'src/adapters/bidderFactory';
import { BANNER, VIDEO } from 'src/mediaTypes';
+import {config} from 'src/config';
const constants = require('src/constants.json');
const BIDDER_CODE = 'pubmatic';
@@ -8,6 +9,7 @@ const ENDPOINT = '//hbopenbid.pubmatic.com/translator?source=prebid-client';
const USYNCURL = '//ads.pubmatic.com/AdServer/js/showad.js#PIX&kdntuid=1&p=';
const DEFAULT_CURRENCY = 'USD';
const AUCTION_TYPE = 1;
+const PUBMATIC_DIGITRUST_KEY = 'nFIn8aLzbd';
const UNDEFINED = undefined;
const CUSTOM_PARAMS = {
'kadpageurl': '', // Custom page url
@@ -275,6 +277,45 @@ function _createImpressionObject(bid, conf) {
return impObj;
}
+function _getDigiTrustObject(key) {
+ function getDigiTrustId() {
+ let digiTrustUser = window.DigiTrust && (config.getConfig('digiTrustId') || window.DigiTrust.getUser({member: key}));
+ return (digiTrustUser && digiTrustUser.success && digiTrustUser.identity) || null;
+ }
+ let digiTrustId = getDigiTrustId();
+ // Verify there is an ID and this user has not opted out
+ if (!digiTrustId || (digiTrustId.privacy && digiTrustId.privacy.optout)) {
+ return null;
+ }
+ return digiTrustId;
+}
+
+function _handleDigitrustId(eids) {
+ let digiTrustId = _getDigiTrustObject(PUBMATIC_DIGITRUST_KEY);
+ if (digiTrustId !== null) {
+ eids.push({
+ 'source': 'digitru.st',
+ 'uids': [
+ {
+ 'id': digiTrustId.id || '',
+ 'atype': 1,
+ 'ext': {
+ 'keyv': parseInt(digiTrustId.keyv) || 0
+ }
+ }
+ ]
+ });
+ }
+}
+
+function _handleEids(payload) {
+ let eids = [];
+ _handleDigitrustId(eids);
+ if (eids.length > 0) {
+ payload.user.eids = eids;
+ }
+}
+
export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [BANNER, VIDEO],
@@ -414,6 +455,8 @@ export const spec = {
utils.logWarn(BIDDER_CODE + ': dctr value not found in 1st adunit, ignoring values from subsequent adunits');
}
+ _handleEids(payload);
+
return {
method: 'POST',
url: ENDPOINT,
diff --git a/modules/realvuAnalyticsAdapter.js b/modules/realvuAnalyticsAdapter.js
index 1ce854b539e..217ccb2b596 100644
--- a/modules/realvuAnalyticsAdapter.js
+++ b/modules/realvuAnalyticsAdapter.js
@@ -20,8 +20,8 @@ try {
} catch (e) {
/* continue regardless of error */
}
-window.top1.realvu_aa_fifo = window.top1.realvu_aa_fifo || [];
-window.top1.realvu_aa = window.top1.realvu_aa || {
+
+export let lib = {
ads: [],
x1: 0,
y1: 0,
@@ -35,6 +35,7 @@ window.top1.realvu_aa = window.top1.realvu_aa || {
c: '', // owner id
sr: '', //
beacons: [], // array of beacons to collect while 'conf' is not responded
+ defer: [],
init: function () {
let z = this;
let u = navigator.userAgent;
@@ -75,13 +76,10 @@ window.top1.realvu_aa = window.top1.realvu_aa || {
},
add_evt: function (elem, evtType, func) {
- if (elem.addEventListener) {
- elem.addEventListener(evtType, func, true);
- } else if (elem.attachEvent) {
- elem.attachEvent('on' + evtType, func);
- } else {
- elem['on' + evtType] = func;
- }
+ elem.addEventListener(evtType, func, true);
+ this.defer.push(function() {
+ elem.removeEventListener(evtType, func, true);
+ });
},
update: function () {
@@ -849,6 +847,9 @@ window.top1.realvu_aa = window.top1.realvu_aa || {
}
};
+window.top1.realvu_aa_fifo = window.top1.realvu_aa_fifo || [];
+window.top1.realvu_aa = window.top1.realvu_aa || lib;
+
if (typeof (window.top1.boost_poll) == 'undefined') {
window.top1.realvu_aa.init();
window.top1.boost_poll = setInterval(function () {
@@ -937,9 +938,17 @@ realvuAnalyticsAdapter.isInView = function (adUnitCode) {
return r;
};
+let disableAnalyticsSuper = realvuAnalyticsAdapter.disableAnalytics;
+realvuAnalyticsAdapter.disableAnalytics = function () {
+ while (lib.defer.length) {
+ lib.defer.pop()();
+ }
+ disableAnalyticsSuper.apply(this, arguments);
+};
+
adaptermanager.registerAnalyticsAdapter({
adapter: realvuAnalyticsAdapter,
code: 'realvuAnalytics'
});
-module.exports = realvuAnalyticsAdapter;
+export default realvuAnalyticsAdapter;
diff --git a/modules/rexrtbBidAdapter.js b/modules/rexrtbBidAdapter.js
index 4048bf40afe..f8388e1e74f 100644
--- a/modules/rexrtbBidAdapter.js
+++ b/modules/rexrtbBidAdapter.js
@@ -4,7 +4,7 @@ import {registerBidder} from 'src/adapters/bidderFactory';
import {config} from 'src/config';
const BIDDER_CODE = 'rexrtb';
-const DEFAULT_HOST = 'bid.rxrtb.bid';
+const DEFAULT_HOST = 'bid.rxrtb.com';
const AUCTION_TYPE = 2;
const RESPONSE_TTL = 900;
diff --git a/modules/rtbhouseBidAdapter.js b/modules/rtbhouseBidAdapter.js
index bb527528e43..e4a30782dbe 100644
--- a/modules/rtbhouseBidAdapter.js
+++ b/modules/rtbhouseBidAdapter.js
@@ -1,5 +1,5 @@
import * as utils from 'src/utils';
-import { BANNER } from 'src/mediaTypes';
+import { BANNER, NATIVE } from 'src/mediaTypes';
import { registerBidder } from 'src/adapters/bidderFactory';
import includes from 'core-js/library/fn/array/includes';
@@ -7,68 +7,34 @@ const BIDDER_CODE = 'rtbhouse';
const REGIONS = ['prebid-eu', 'prebid-us', 'prebid-asia'];
const ENDPOINT_URL = 'creativecdn.com/bidder/prebid/bids';
const DEFAULT_CURRENCY_ARR = ['USD']; // NOTE - USD is the only supported currency right now; Hardcoded for bids
+const TTL = 55;
-/**
- * Helpers
- */
-
-function buildEndpointUrl(region) {
- return 'https://' + region + '.' + ENDPOINT_URL;
-}
-
-/**
- * Produces an OpenRTBImpression from a slot config.
- */
-function mapImpression(slot) {
- return {
- id: slot.bidId,
- banner: mapBanner(slot),
- tagid: slot.adUnitCode.toString(),
- };
-}
-
-/**
- * Produces an OpenRTB Banner object for the slot given.
- */
-function mapBanner(slot) {
- return {
- w: slot.sizes[0][0],
- h: slot.sizes[0][1],
- format: mapSizes(slot.sizes)
- };
-}
-
-/**
- * Produce openRTB banner.format object
- */
-function mapSizes(slotSizes) {
- const format = [];
- slotSizes.forEach(elem => {
- format.push({
- w: elem[0],
- h: elem[1]
- });
- });
- return format;
-}
-
-/**
- * Produces an OpenRTB site object.
- */
-function mapSite(validRequest) {
- const pubId = validRequest && validRequest.length > 0 ? validRequest[0].params.publisherId : 'unknown';
- return {
- publisher: {
- id: pubId.toString(),
+// Codes defined by OpenRTB Native Ads 1.1 specification
+export const OPENRTB = {
+ NATIVE: {
+ IMAGE_TYPE: {
+ ICON: 1,
+ MAIN: 3,
+ },
+ ASSET_ID: {
+ TITLE: 1,
+ IMAGE: 2,
+ ICON: 3,
+ BODY: 4,
+ SPONSORED: 5,
+ CTA: 6
+ },
+ DATA_ASSET_TYPE: {
+ SPONSORED: 1,
+ DESC: 2,
+ CTA_TEXT: 12,
},
- page: utils.getTopWindowUrl(),
- name: utils.getOrigin()
}
-}
+};
export const spec = {
code: BIDDER_CODE,
- supportedMediaTypes: [BANNER],
+ supportedMediaTypes: [BANNER, NATIVE],
isBidRequestValid: function (bid) {
return !!(includes(REGIONS, bid.params.region) && bid.params.publisherId);
@@ -87,39 +53,262 @@ export const spec = {
const gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0;
request.regs = {ext: {gdpr: gdpr}};
request.user = {ext: {consent: consentStr}};
- };
+ }
return {
method: 'POST',
- url: buildEndpointUrl(validBidRequests[0].params.region),
+ url: 'https://' + validBidRequests[0].params.region + '.' + ENDPOINT_URL,
data: JSON.stringify(request)
};
},
interpretResponse: function (serverResponse, originalRequest) {
- serverResponse = serverResponse.body;
- const bids = [];
-
- if (utils.isArray(serverResponse)) {
- serverResponse.forEach(serverBid => {
- if (serverBid.price !== 0) {
- const bid = {
- requestId: serverBid.impid,
- mediaType: BANNER,
- cpm: serverBid.price,
- creativeId: serverBid.adid,
- ad: serverBid.adm,
- width: serverBid.w,
- height: serverBid.h,
- ttl: 55,
- netRevenue: true,
- currency: 'USD'
- };
- bids.push(bid);
- }
- });
+ const responseBody = serverResponse.body;
+ if (!utils.isArray(responseBody)) {
+ return [];
}
+
+ const bids = [];
+ responseBody.forEach(serverBid => {
+ if (serverBid.price === 0) {
+ return;
+ }
+ // try...catch would be risky cause JSON.parse throws SyntaxError
+ if (serverBid.adm.indexOf('{') === 0) {
+ bids.push(interpretNativeBid(serverBid));
+ } else {
+ bids.push(interpretBannerBid(serverBid));
+ }
+ });
return bids;
}
};
-
registerBidder(spec);
+
+/**
+ * @param {object} slot Ad Unit Params by Prebid
+ * @returns {object} Imp by OpenRTB 2.5 §3.2.4
+ */
+function mapImpression(slot) {
+ return {
+ id: slot.bidId,
+ banner: mapBanner(slot),
+ native: mapNative(slot),
+ tagid: slot.adUnitCode.toString()
+ };
+}
+
+/**
+ * @param {object} slot Ad Unit Params by Prebid
+ * @returns {object} Banner by OpenRTB 2.5 §3.2.6
+ */
+function mapBanner(slot) {
+ if (slot.mediaType === 'banner' ||
+ utils.deepAccess(slot, 'mediaTypes.banner') ||
+ (!slot.mediaType && !slot.mediaTypes)) {
+ return {
+ w: slot.sizes[0][0],
+ h: slot.sizes[0][1],
+ format: slot.sizes.map(size => ({
+ w: size[0],
+ h: size[1]
+ }))
+ };
+ }
+}
+
+/**
+ * @param {object} slot Ad Unit Params by Prebid
+ * @returns {object} Site by OpenRTB 2.5 §3.2.13
+ */
+function mapSite(slot) {
+ const pubId = slot && slot.length > 0
+ ? slot[0].params.publisherId
+ : 'unknown';
+ return {
+ publisher: {
+ id: pubId.toString(),
+ },
+ page: utils.getTopWindowUrl(),
+ name: utils.getOrigin()
+ }
+}
+
+/**
+ * @param {object} slot Ad Unit Params by Prebid
+ * @returns {object} Request by OpenRTB Native Ads 1.1 §4
+ */
+function mapNative(slot) {
+ if (slot.mediaType === 'native' || utils.deepAccess(slot, 'mediaTypes.native')) {
+ return {
+ request: {
+ assets: mapNativeAssets(slot)
+ },
+ ver: '1.1'
+ }
+ }
+}
+
+/**
+ * @param {object} slot Slot config by Prebid
+ * @returns {array} Request Assets by OpenRTB Native Ads 1.1 §4.2
+ */
+function mapNativeAssets(slot) {
+ const params = slot.nativeParams || utils.deepAccess(slot, 'mediaTypes.native');
+ const assets = [];
+ if (params.title) {
+ assets.push({
+ id: OPENRTB.NATIVE.ASSET_ID.TITLE,
+ required: params.title.required ? 1 : 0,
+ title: {
+ len: params.title.len || 25
+ }
+ })
+ }
+ if (params.image) {
+ assets.push({
+ id: OPENRTB.NATIVE.ASSET_ID.IMAGE,
+ required: params.image.required ? 1 : 0,
+ img: mapNativeImage(params.image, OPENRTB.NATIVE.IMAGE_TYPE.MAIN)
+ })
+ }
+ if (params.icon) {
+ assets.push({
+ id: OPENRTB.NATIVE.ASSET_ID.ICON,
+ required: params.icon.required ? 1 : 0,
+ img: mapNativeImage(params.icon, OPENRTB.NATIVE.IMAGE_TYPE.ICON)
+ })
+ }
+ if (params.sponsoredBy) {
+ assets.push({
+ id: OPENRTB.NATIVE.ASSET_ID.SPONSORED,
+ required: params.sponsoredBy.required ? 1 : 0,
+ data: {
+ type: OPENRTB.NATIVE.DATA_ASSET_TYPE.SPONSORED,
+ len: params.sponsoredBy.len
+ }
+ })
+ }
+ if (params.body) {
+ assets.push({
+ id: OPENRTB.NATIVE.ASSET_ID.BODY,
+ required: params.body.request ? 1 : 0,
+ data: {
+ type: OPENRTB.NATIVE.DATA_ASSET_TYPE.DESC,
+ len: params.body.len
+ }
+ })
+ }
+ if (params.cta) {
+ assets.push({
+ id: OPENRTB.NATIVE.ASSET_ID.CTA,
+ required: params.cta.required ? 1 : 0,
+ data: {
+ type: OPENRTB.NATIVE.DATA_ASSET_TYPE.CTA_TEXT,
+ len: params.cta.len
+ }
+ })
+ }
+ return assets;
+}
+
+/**
+ * @param {object} image Prebid native.image/icon
+ * @param {int} type Image or icon code
+ * @returns {object} Request Image by OpenRTB Native Ads 1.1 §4.4
+ */
+function mapNativeImage(image, type) {
+ const img = {type: type};
+ if (image.aspect_ratios) {
+ const ratio = image.aspect_ratios[0];
+ const minWidth = ratio.min_width || 100;
+ img.wmin = minWidth;
+ img.hmin = (minWidth / ratio.ratio_width * ratio.ratio_height);
+ }
+ if (image.sizes) {
+ const size = Array.isArray(image.sizes[0]) ? image.sizes[0] : image.sizes;
+ img.w = size[0];
+ img.h = size[1];
+ }
+ return img
+}
+
+/**
+ * @param {object} serverBid Bid by OpenRTB 2.5 §4.2.3
+ * @returns {object} Prebid banner bidObject
+ */
+function interpretBannerBid(serverBid) {
+ return {
+ requestId: serverBid.impid,
+ mediaType: BANNER,
+ cpm: serverBid.price,
+ creativeId: serverBid.adid,
+ ad: serverBid.adm,
+ width: serverBid.w,
+ height: serverBid.h,
+ ttl: TTL,
+ netRevenue: true,
+ currency: 'USD'
+ }
+}
+
+/**
+ * @param {object} serverBid Bid by OpenRTB 2.5 §4.2.3
+ * @returns {object} Prebid native bidObject
+ */
+function interpretNativeBid(serverBid) {
+ return {
+ requestId: serverBid.impid,
+ mediaType: NATIVE,
+ cpm: serverBid.price,
+ creativeId: serverBid.adid,
+ width: 1,
+ height: 1,
+ ttl: TTL,
+ netRevenue: true,
+ currency: 'USD',
+ native: interpretNativeAd(serverBid.adm),
+ }
+}
+
+/**
+ * @param {string} adm JSON-encoded Request by OpenRTB Native Ads 1.1 §4.1
+ * @returns {object} Prebid bidObject.native
+ */
+function interpretNativeAd(adm) {
+ const native = JSON.parse(adm).native;
+ const result = {
+ clickUrl: encodeURIComponent(native.link.url),
+ impressionTrackers: native.imptrackers
+ };
+ native.assets.forEach(asset => {
+ switch (asset.id) {
+ case OPENRTB.NATIVE.ASSET_ID.TITLE:
+ result.title = asset.title.text;
+ break;
+ case OPENRTB.NATIVE.ASSET_ID.IMAGE:
+ result.image = {
+ url: encodeURIComponent(asset.img.url),
+ width: asset.img.w,
+ height: asset.img.h
+ };
+ break;
+ case OPENRTB.NATIVE.ASSET_ID.ICON:
+ result.icon = {
+ url: encodeURIComponent(asset.img.url),
+ width: asset.img.w,
+ height: asset.img.h
+ };
+ break;
+ case OPENRTB.NATIVE.ASSET_ID.BODY:
+ result.body = asset.data.value;
+ break;
+ case OPENRTB.NATIVE.ASSET_ID.SPONSORED:
+ result.sponsoredBy = asset.data.value;
+ break;
+ case OPENRTB.NATIVE.ASSET_ID.CTA:
+ result.cta = asset.data.value;
+ break;
+ }
+ });
+ return result;
+}
diff --git a/modules/rtbhouseBidAdapter.md b/modules/rtbhouseBidAdapter.md
index 47deed1a277..a2d7e2aedda 100644
--- a/modules/rtbhouseBidAdapter.md
+++ b/modules/rtbhouseBidAdapter.md
@@ -14,6 +14,7 @@ Please reach out to pmp@rtbhouse.com to receive your own
# Test Parameters
```
var adUnits = [
+ // banner
{
code: 'test-div',
sizes: [[300, 250]],
@@ -26,6 +27,32 @@ Please reach out to pmp@rtbhouse.com to receive your own
}
}
]
+ },
+ // native
+ {
+ code: 'test-div',
+ mediaTypes: {
+ native: {
+ title: {
+ required: true
+ },
+ image: {
+ required: true
+ },
+ body: {
+ required: true
+ }
+ }
+ },
+ bids: [
+ {
+ bidder: "rtbhouse",
+ params: {
+ region: 'prebid-eu',
+ publisherId: 'PREBID_TEST_ID'
+ }
+ }
+ ]
}
];
```
diff --git a/modules/rubiconBidAdapter.js b/modules/rubiconBidAdapter.js
index 7f219886057..20175ceb550 100644
--- a/modules/rubiconBidAdapter.js
+++ b/modules/rubiconBidAdapter.js
@@ -92,11 +92,9 @@ export const spec = {
if (typeof bid.params !== 'object') {
return false;
}
-
if (!/^\d+$/.test(bid.params.accountId)) {
return false;
}
-
return !!bidType(bid, true);
},
/**
@@ -111,7 +109,7 @@ export const spec = {
bidRequest.startTime = new Date().getTime();
let params = bidRequest.params;
- let size = parseSizes(bidRequest);
+ let size = parseSizes(bidRequest, 'video');
let data = {
page_url: _getPageUrl(bidRequest, bidderRequest),
@@ -306,7 +304,7 @@ export const spec = {
const params = bidRequest.params;
// use rubicon sizes if provided, otherwise adUnit.sizes
- const parsedSizes = parseSizes(bidRequest);
+ const parsedSizes = parseSizes(bidRequest, 'banner');
const [latitude, longitude] = params.latLong || [];
@@ -341,14 +339,18 @@ export const spec = {
// visitor properties
if (params.visitor !== null && typeof params.visitor === 'object') {
Object.keys(params.visitor).forEach((key) => {
- data[`tg_v.${key}`] = params.visitor[key].toString();
+ if (params.visitor[key] != null) {
+ data[`tg_v.${key}`] = params.visitor[key].toString(); // initialize array;
+ }
});
}
// inventory properties
if (params.inventory !== null && typeof params.inventory === 'object') {
Object.keys(params.inventory).forEach((key) => {
- data[`tg_i.${key}`] = params.inventory[key].toString();
+ if (params.inventory[key] != null) {
+ data[`tg_i.${key}`] = params.inventory[key].toString();
+ }
});
}
@@ -525,9 +527,9 @@ function _renderCreative(script, impId) {
|