diff --git a/modules/improvedigitalBidAdapter.js b/modules/improvedigitalBidAdapter.js
index 0c9028133e0..22569f04cc3 100644
--- a/modules/improvedigitalBidAdapter.js
+++ b/modules/improvedigitalBidAdapter.js
@@ -6,7 +6,7 @@ import { BANNER, NATIVE } from '../src/mediaTypes';
const BIDDER_CODE = 'improvedigital';
export const spec = {
- version: '5.1.0',
+ version: '5.2.0',
code: BIDDER_CODE,
aliases: ['id'],
supportedMediaTypes: [BANNER, NATIVE],
@@ -43,6 +43,10 @@ export const spec = {
requestParameters.gdpr = bidderRequest.gdprConsent.consentString;
}
+ if (bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer) {
+ requestParameters.referrer = bidderRequest.refererInfo.referer;
+ }
+
let requestObj = idClient.createRequest(
normalizedBids, // requestObject
requestParameters
@@ -75,6 +79,8 @@ export const spec = {
if (bidObject.native) {
// Native
bid.native = getNormalizedNativeAd(bidObject.native);
+ // Expose raw oRTB response to the client to allow parsing assets not directly supported by Prebid
+ bid.ortbNative = bidObject.native;
if (bidObject.nurl) {
bid.native.impressionTrackers.unshift(bidObject.nurl);
}
@@ -169,11 +175,13 @@ function getNormalizedBidRequest(bid) {
publisherId = utils.getBidIdParameter('publisherId', bid.params) || null;
placementKey = utils.getBidIdParameter('placementKey', bid.params) || null;
}
- let keyValues = utils.getBidIdParameter('keyValues', bid.params) || null;
- let singleSizeFilter = utils.getBidIdParameter('size', bid.params) || null;
- let bidId = utils.getBidIdParameter('bidId', bid);
- let transactionId = utils.getBidIdParameter('transactionId', bid);
+ const keyValues = utils.getBidIdParameter('keyValues', bid.params) || null;
+ const singleSizeFilter = utils.getBidIdParameter('size', bid.params) || null;
+ const bidId = utils.getBidIdParameter('bidId', bid);
+ const transactionId = utils.getBidIdParameter('transactionId', bid);
const currency = config.getConfig('currency.adServerCurrency');
+ const bidFloor = utils.getBidIdParameter('bidFloor', bid.params);
+ const bidFloorCur = utils.getBidIdParameter('bidFloorCur', bid.params);
let normalizedBidRequest = {};
if (placementId) {
@@ -211,6 +219,10 @@ function getNormalizedBidRequest(bid) {
if (currency) {
normalizedBidRequest.currency = currency;
}
+ if (bidFloor) {
+ normalizedBidRequest.bidFloor = bidFloor;
+ normalizedBidRequest.bidFloorCur = bidFloorCur ? bidFloorCur.toUpperCase() : 'USD';
+ }
return normalizedBidRequest;
}
@@ -231,6 +243,33 @@ function getNormalizedNativeAd(rawNative) {
case 2:
native.body = asset.data.value;
break;
+ case 3:
+ native.rating = asset.data.value;
+ break;
+ case 4:
+ native.likes = asset.data.value;
+ break;
+ case 5:
+ native.downloads = asset.data.value;
+ break;
+ case 6:
+ native.price = asset.data.value;
+ break;
+ case 7:
+ native.salePrice = asset.data.value;
+ break;
+ case 8:
+ native.phone = asset.data.value;
+ break;
+ case 9:
+ native.address = asset.data.value;
+ break;
+ case 10:
+ native.body2 = asset.data.value;
+ break;
+ case 11:
+ native.displayUrl = asset.data.value;
+ break;
case 12:
native.cta = asset.data.value;
break;
@@ -255,26 +294,42 @@ function getNormalizedNativeAd(rawNative) {
}
});
// Trackers
- native.impressionTrackers = rawNative.imptrackers || [];
- native.javascriptTrackers = rawNative.jstracker;
+ if (rawNative.eventtrackers) {
+ native.impressionTrackers = [];
+ rawNative.eventtrackers.forEach(tracker => {
+ // Only handle impression event. Viewability events are not supported yet.
+ if (tracker.event !== 1) return;
+ switch (tracker.method) {
+ case 1: // img
+ native.impressionTrackers.push(tracker.url);
+ break;
+ case 2: // js
+ // javascriptTrackers is a string. If there's more than one JS tracker in bid response, the last script will be used.
+ native.javascriptTrackers = ``;
+ break;
+ }
+ });
+ } else {
+ native.impressionTrackers = rawNative.imptrackers || [];
+ native.javascriptTrackers = rawNative.jstracker;
+ }
if (rawNative.link) {
native.clickUrl = rawNative.link.url;
native.clickTrackers = rawNative.link.clicktrackers;
}
+ if (rawNative.privacy) {
+ native.privacyLink = rawNative.privacy;
+ }
return native;
}
registerBidder(spec);
export function ImproveDigitalAdServerJSClient(endPoint) {
this.CONSTANTS = {
- HTTP_SECURITY: {
- STANDARD: 0,
- SECURE: 1
- },
AD_SERVER_BASE_URL: 'ice.360yield.com',
END_POINT: endPoint || 'hb',
AD_SERVER_URL_PARAM: 'jsonp=',
- CLIENT_VERSION: 'JS-6.0.0',
+ CLIENT_VERSION: 'JS-6.2.0',
MAX_URL_LENGTH: 2083,
ERROR_CODES: {
MISSING_PLACEMENT_PARAMS: 2,
@@ -300,6 +355,7 @@ export function ImproveDigitalAdServerJSClient(endPoint) {
}
requestParameters.returnObjType = requestParameters.returnObjType || this.CONSTANTS.RETURN_OBJ_TYPE.DEFAULT;
+ requestParameters.adServerBaseUrl = 'https://' + (requestParameters.adServerBaseUrl || this.CONSTANTS.AD_SERVER_BASE_URL);
let impressionObjects = [];
let impressionObject;
@@ -325,7 +381,7 @@ export function ImproveDigitalAdServerJSClient(endPoint) {
}
let errors = null;
- let baseUrl = `${(requestParameters.secure === 1 ? 'https' : 'http')}://${this.CONSTANTS.AD_SERVER_BASE_URL}/${this.CONSTANTS.END_POINT}?${this.CONSTANTS.AD_SERVER_URL_PARAM}`;
+ let baseUrl = `${requestParameters.adServerBaseUrl}/${this.CONSTANTS.END_POINT}?${this.CONSTANTS.AD_SERVER_URL_PARAM}`;
let bidRequestObject = {
bid_request: this.createBasicBidRequestObject(requestParameters, extraRequestParameters)
@@ -386,12 +442,11 @@ export function ImproveDigitalAdServerJSClient(endPoint) {
case this.CONSTANTS.RETURN_OBJ_TYPE.URL_PARAMS_SPLIT:
return {
method: 'GET',
- url: `//${this.CONSTANTS.AD_SERVER_BASE_URL}/${this.CONSTANTS.END_POINT}`,
+ url: `${requestParameters.adServerBaseUrl}/${this.CONSTANTS.END_POINT}`,
data: `${this.CONSTANTS.AD_SERVER_URL_PARAM}${encodeURIComponent(JSON.stringify(bidRequestObject))}`
};
default:
- const baseUrl = `${(requestParameters.secure === 1 ? 'https' : 'http')}://` +
- `${this.CONSTANTS.AD_SERVER_BASE_URL}/` +
+ const baseUrl = `${requestParameters.adServerBaseUrl}/` +
`${this.CONSTANTS.END_POINT}?${this.CONSTANTS.AD_SERVER_URL_PARAM}`;
return {
url: baseUrl + encodeURIComponent(JSON.stringify(bidRequestObject))
@@ -401,6 +456,7 @@ export function ImproveDigitalAdServerJSClient(endPoint) {
this.createBasicBidRequestObject = function(requestParameters, extraRequestParameters) {
let impressionBidRequestObject = {};
+ impressionBidRequestObject.secure = 1;
if (requestParameters.requestId) {
impressionBidRequestObject.id = requestParameters.requestId;
} else {
@@ -418,9 +474,6 @@ export function ImproveDigitalAdServerJSClient(endPoint) {
if (requestParameters.callback) {
impressionBidRequestObject.callback = requestParameters.callback;
}
- if ('secure' in requestParameters) {
- impressionBidRequestObject.secure = requestParameters.secure;
- }
if (requestParameters.libVersion) {
impressionBidRequestObject.version = requestParameters.libVersion + '-' + this.CONSTANTS.CLIENT_VERSION;
}
@@ -455,6 +508,12 @@ export function ImproveDigitalAdServerJSClient(endPoint) {
if (placementObject.currency) {
impressionObject.currency = placementObject.currency.toUpperCase();
}
+ if (placementObject.bidFloor) {
+ impressionObject.bidfloor = placementObject.bidFloor;
+ }
+ if (placementObject.bidFloorCur) {
+ impressionObject.bidfloorcur = placementObject.bidFloorCur.toUpperCase();
+ }
if (placementObject.placementId) {
impressionObject.pid = placementObject.placementId;
}
diff --git a/modules/improvedigitalBidAdapter.md b/modules/improvedigitalBidAdapter.md
index d70b624171f..15602d11038 100644
--- a/modules/improvedigitalBidAdapter.md
+++ b/modules/improvedigitalBidAdapter.md
@@ -2,7 +2,7 @@
**Module Name**: Improve Digital Bidder Adapter
**Module Type**: Bidder Adapter
-**Maintainer**: hb@improvedigital.com
+**Maintainer**: hb@azerion.com
# Description
diff --git a/test/spec/modules/improvedigitalBidAdapter_spec.js b/test/spec/modules/improvedigitalBidAdapter_spec.js
index 6c78afca6b2..8b8f6c4bf4c 100644
--- a/test/spec/modules/improvedigitalBidAdapter_spec.js
+++ b/test/spec/modules/improvedigitalBidAdapter_spec.js
@@ -7,7 +7,7 @@ describe('Improve Digital Adapter Tests', function () {
let idClient = new ImproveDigitalAdServerJSClient('hb');
const METHOD = 'GET';
- const URL = '//ice.360yield.com/hb';
+ const URL = 'https://ice.360yield.com/hb';
const PARAM_PREFIX = 'jsonp=';
const simpleBidRequest = {
@@ -33,11 +33,17 @@ describe('Improve Digital Adapter Tests', function () {
}
};
- const bidderRequest = {
- 'gdprConsent': {
- 'consentString': 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==',
- 'vendorData': {},
- 'gdprApplies': true
+ const bidderRequestGdpr = {
+ gdprConsent: {
+ consentString: 'BOJ/P2HOJ/P2HABABMAAAAAZ+A==',
+ vendorData: {},
+ gdprApplies: true
+ },
+ };
+
+ const bidderRequestReferrer = {
+ refererInfo: {
+ referer: 'https://blah.com/test.html',
},
};
@@ -151,13 +157,42 @@ describe('Improve Digital Adapter Tests', function () {
getConfigStub.restore();
});
+ it('should add bid floor', function () {
+ const bidRequest = Object.assign({}, simpleBidRequest);
+ let request = spec.buildRequests([bidRequest])[0];
+ let params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
+ // Floor price currency shouldn't be populated without a floor price
+ expect(params.bid_request.imp[0].bidfloorcur).to.not.exist;
+
+ // Default floor price currency
+ bidRequest.params.bidFloor = 0.05;
+ request = spec.buildRequests([bidRequest])[0];
+ params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
+ expect(params.bid_request.imp[0].bidfloor).to.equal(0.05);
+ expect(params.bid_request.imp[0].bidfloorcur).to.equal('USD');
+
+ // Floor price currency
+ bidRequest.params.bidFloorCur = 'eUR';
+ request = spec.buildRequests([bidRequest])[0];
+ params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
+ expect(params.bid_request.imp[0].bidfloor).to.equal(0.05);
+ expect(params.bid_request.imp[0].bidfloorcur).to.equal('EUR');
+ });
+
it('should add GDPR consent string', function () {
const bidRequest = Object.assign({}, simpleBidRequest);
- const request = spec.buildRequests([bidRequest], bidderRequest)[0];
+ const request = spec.buildRequests([bidRequest], bidderRequestGdpr)[0];
const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
expect(params.bid_request.gdpr).to.equal('BOJ/P2HOJ/P2HABABMAAAAAZ+A==');
});
+ it('should add referrer', function () {
+ const bidRequest = Object.assign({}, simpleBidRequest);
+ const request = spec.buildRequests([bidRequest], bidderRequestReferrer)[0];
+ const params = JSON.parse(decodeURIComponent(request.data.substring(PARAM_PREFIX.length)));
+ expect(params.bid_request.referrer).to.equal('https://blah.com/test.html');
+ });
+
it('should return 2 requests', function () {
const requests = spec.buildRequests([
simpleBidRequest,
@@ -310,13 +345,61 @@ describe('Improve Digital Adapter Tests', function () {
{
data: {
type: 3,
- value: 'Should get ignored'
+ value: '4' // rating
+ }
+ },
+ {
+ data: {
+ type: 4,
+ value: '10105' // likes
+ }
+ },
+ {
+ data: {
+ type: 5,
+ value: '150000' // downloads
+ }
+ },
+ {
+ data: {
+ type: 6,
+ value: '3.99' // price
+ }
+ },
+ {
+ data: {
+ type: 7,
+ value: '4.49' // salePrice
+ }
+ },
+ {
+ data: {
+ type: 8,
+ value: '(123) 456-7890' // phone
+ }
+ },
+ {
+ data: {
+ type: 9,
+ value: '123 Main Street, Anywhere USA' // address
+ }
+ },
+ {
+ data: {
+ type: 10,
+ value: 'body2'
+ }
+ },
+ {
+ data: {
+ type: 11,
+ value: 'https://myurl.com' // displayUrl
}
},
{
data: {
type: 12,
- value: 'Do it'
+ value: 'Do it' // cta
}
},
{
@@ -334,6 +417,7 @@ describe('Improve Digital Adapter Tests', function () {
h: 30,
w: 40
}
+
},
{
img: {
@@ -354,7 +438,8 @@ describe('Improve Digital Adapter Tests', function () {
'http://imptrack1.com',
'http://imptrack2.com'
],
- jstracker: ''
+ jstracker: '',
+ privacy: 'https://www.myprivacyurl.com'
}
}
],
@@ -362,6 +447,19 @@ describe('Improve Digital Adapter Tests', function () {
}
};
+ const nativeEventtrackers = [
+ {
+ event: 1,
+ method: 1,
+ url: 'http://www.mytracker.com/imptracker'
+ },
+ {
+ event: 1,
+ method: 2,
+ url: 'http://www.mytracker.com/tracker.js'
+ }
+ ];
+
describe('interpretResponse', function () {
let expectedBid = [
{
@@ -411,8 +509,17 @@ describe('Improve Digital Adapter Tests', function () {
native: {
title: 'Native title',
body: 'Native body',
+ body2: 'body2',
cta: 'Do it',
sponsoredBy: 'Improve Digital',
+ rating: '4',
+ likes: '10105',
+ downloads: '150000',
+ price: '3.99',
+ salePrice: '4.49',
+ phone: '(123) 456-7890',
+ address: '123 Main Street, Anywhere USA',
+ displayUrl: 'https://myurl.com',
icon: {
url: 'http://blah.com/icon.jpg',
height: 30,
@@ -430,7 +537,8 @@ describe('Improve Digital Adapter Tests', function () {
'http://imptrack1.com',
'http://imptrack2.com'
],
- javascriptTrackers: ''
+ javascriptTrackers: '',
+ privacyLink: 'https://www.myprivacyurl.com'
}
}
];
@@ -532,8 +640,23 @@ describe('Improve Digital Adapter Tests', function () {
// Native ads
it('should return a well-formed native ad bid', function () {
- const bids = spec.interpretResponse(serverResponseNative);
+ let bids = spec.interpretResponse(serverResponseNative);
+ expect(bids[0].ortbNative).to.deep.equal(serverResponseNative.body.bid[0].native);
+ delete bids[0].ortbNative;
expect(bids).to.deep.equal(expectedBidNative);
+
+ // eventtrackers
+ const response = JSON.parse(JSON.stringify(serverResponseNative));
+ const expectedBids = JSON.parse(JSON.stringify(expectedBidNative));
+ response.body.bid[0].native.eventtrackers = nativeEventtrackers;
+ expectedBids[0].native.impressionTrackers = [
+ 'http://ice.360yield.com/imp_pixel?ic=wVm',
+ 'http://www.mytracker.com/imptracker'
+ ];
+ expectedBids[0].native.javascriptTrackers = '';
+ bids = spec.interpretResponse(response);
+ delete bids[0].ortbNative;
+ expect(bids).to.deep.equal(expectedBids);
});
});