Skip to content

Commit

Permalink
IX Bid Adapter: Add support for IMG based user syncs (#8606)
Browse files Browse the repository at this point in the history
Co-authored-by: Chris Corbo <[email protected]>
  • Loading branch information
2 people authored and ahmadlob committed Jul 27, 2022
1 parent 323836f commit d9f3de5
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 13 deletions.
76 changes: 68 additions & 8 deletions modules/ixBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ const OUTSTREAM_MINIMUM_PLAYER_SIZE = [144, 144];
const PRICE_TO_DOLLAR_FACTOR = {
JPY: 1
};
const USER_SYNC_URL = 'https://js-sec.indexww.com/um/ixmatch.html';

const IFRAME_USER_SYNC_URL = 'https://js-sec.indexww.com/um/ixmatch.html';
const FLOOR_SOURCE = { PBJS: 'p', IX: 'x' };
const IMG_USER_SYNC_URL = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid'
export const ERROR_CODES = {
BID_SIZE_INVALID_FORMAT: 1,
BID_SIZE_NOT_INCLUDED: 2,
Expand Down Expand Up @@ -191,6 +191,9 @@ const NATIVE_EVENT_TRACKING_METHOD = {
const LOCAL_STORAGE_KEY = 'ixdiag';
let hasRegisteredHandler = false;
export const storage = getStorageManager({gvlid: GLOBAL_VENDOR_ID, bidderCode: BIDDER_CODE});
let siteID = 0;
let gdprConsent = '';
let usPrivacy = '';

// Possible values for bidResponse.seatBid[].bid[].mtype which indicates the type of the creative markup so that it can properly be associated with the right sub-object of the BidRequest.Imp.
const MEDIA_TYPES = {
Expand Down Expand Up @@ -882,6 +885,11 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
if (tmax) {
r.ext.ixdiag.tmax = tmax
}

if (config.getConfig('userSync')) {
r.ext.ixdiag.syncsPerBidder = config.getConfig('userSync').syncsPerBidder;
}

// Get cached errors stored in LocalStorage
const cachedErrors = getCachedErrors();

Expand Down Expand Up @@ -910,7 +918,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
// Apply GDPR information to the request if GDPR is enabled.
if (bidderRequest) {
if (bidderRequest.gdprConsent) {
const gdprConsent = bidderRequest.gdprConsent;
gdprConsent = bidderRequest.gdprConsent;

if (gdprConsent.hasOwnProperty('gdprApplies')) {
r.regs = {
Expand All @@ -936,6 +944,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {

if (bidderRequest.uspConsent) {
deepSetValue(r, 'regs.ext.us_privacy', bidderRequest.uspConsent);
usPrivacy = bidderRequest.uspConsent;
}

if (pageUrl) {
Expand All @@ -949,7 +958,9 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {

const payload = {};
// Use the siteId in the first bid request as the main siteId.
payload.s = validBidRequests[0].params.siteId;
siteID = validBidRequests[0].params.siteId;
payload.s = siteID;
payload.v = version;
if (version) {
payload.v = version;
}
Expand Down Expand Up @@ -1763,11 +1774,60 @@ export const spec = {
* @returns {array} User sync pixels
*/
getUserSyncs: function (syncOptions, serverResponses) {
return (syncOptions.iframeEnabled) ? [{
type: 'iframe',
url: USER_SYNC_URL
}] : [];
const syncs = [];
let publisherSyncsPerBidderOverride = null;
if (serverResponses.length > 0) {
publisherSyncsPerBidderOverride = deepAccess(serverResponses[0], 'body.ext.publishersyncsperbidderoverride');
}
if (publisherSyncsPerBidderOverride !== undefined && publisherSyncsPerBidderOverride == 0) {
return [];
}
if (syncOptions.iframeEnabled) {
syncs.push({
type: 'iframe',
url: IFRAME_USER_SYNC_URL
})
} else {
let publisherSyncsPerBidder = null;
if (config.getConfig('userSync')) {
publisherSyncsPerBidder = config.getConfig('userSync').syncsPerBidder
}
if (publisherSyncsPerBidder === 0) {
publisherSyncsPerBidder = publisherSyncsPerBidderOverride
}
if (publisherSyncsPerBidderOverride && (publisherSyncsPerBidder === 0 || publisherSyncsPerBidder)) {
publisherSyncsPerBidder = publisherSyncsPerBidderOverride > publisherSyncsPerBidder ? publisherSyncsPerBidder : publisherSyncsPerBidderOverride
} else {
publisherSyncsPerBidder = 1
}
for (let i = 0; i < publisherSyncsPerBidder; i++) {
syncs.push({
type: 'image',
url: buildImgSyncUrl(publisherSyncsPerBidder, i)
})
}
}
return syncs;
}
};

/**
* Build img user sync url
* @param {int} syncsPerBidder number of syncs Per Bidder
* @param {int} index index to pass
* @returns {string} img user sync url
*/
function buildImgSyncUrl(syncsPerBidder, index) {
let consentString = '';
let gdprApplies = '0';
if (gdprConsent && gdprConsent.hasOwnProperty('gdprApplies')) {
gdprApplies = gdprConsent.gdprApplies ? '1' : '0';
}
if (gdprConsent && gdprConsent.hasOwnProperty('consentString')) {
consentString = gdprConsent.consentString || '';
}

return IMG_USER_SYNC_URL + '&site_id=' + siteID.toString() + '&p=' + syncsPerBidder.toString() + '&i=' + index.toString() + '&gdpr=' + gdprApplies + '&gdpr_consent=' + consentString + '&us_privacy=' + (usPrivacy || '');
}

registerBidder(spec);
101 changes: 96 additions & 5 deletions test/spec/modules/ixBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -677,18 +677,109 @@ describe('IndexexchangeAdapter', function () {
const syncOptions = {
'iframeEnabled': true
}
let userSync = spec.getUserSyncs(syncOptions);
let userSync = spec.getUserSyncs(syncOptions, []);
expect(userSync[0].type).to.equal('iframe');
const USER_SYNC_URL = 'https://js-sec.indexww.com/um/ixmatch.html';
expect(userSync[0].url).to.equal(USER_SYNC_URL);
});

it('When iframeEnabled is false, no userSync should be returned', function () {
it('When iframeEnabled = false, default to img', function () {
const syncOptions = {
'iframeEnabled': false
'iframeEnabled': false,
}
let userSync = spec.getUserSyncs(syncOptions);
expect(userSync).to.be.an('array').that.is.empty;
let userSync = spec.getUserSyncs(syncOptions, []);
expect(userSync[0].type).to.equal('image');
const USER_SYNC_URL = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=1&i=0&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy=';
expect(userSync[0].url).to.equal(USER_SYNC_URL);
});

it('UserSync test : check type = pixel, check usermatch URL, no exchange data, only drop 1', function () {
const syncOptions = {
'pixelEnabled': true
}
config.setConfig({
userSync: {
pixelEnabled: true,
syncsPerBidder: 3
}
})
let userSync = spec.getUserSyncs(syncOptions, []);
expect(userSync[0].type).to.equal('image');
const USER_SYNC_URL = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=1&i=0&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy=';
expect(userSync[0].url).to.equal(USER_SYNC_URL);
});

it('UserSync test : check type = pixel, check usermatch URL with override set to 0', function () {
const syncOptions = {
'pixelEnabled': true
}
config.setConfig({
userSync: {
pixelEnabled: true,
syncsPerBidder: 3
}
});
let userSync = spec.getUserSyncs(syncOptions, [{'body': {'ext': {'publishersyncsperbidderoverride': 0}}}]);
expect(userSync.length).to.equal(0);
});

it('UserSync test : check type = pixel, check usermatch URL with override set', function () {
const syncOptions = {
'pixelEnabled': true
}
config.setConfig({
userSync: {
pixelEnabled: true,
syncsPerBidder: 3
}
});
let userSync = spec.getUserSyncs(syncOptions, [{'body': {'ext': {'publishersyncsperbidderoverride': 2}}}]);
expect(userSync[0].type).to.equal('image');
const USER_SYNC_URL_0 = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=2&i=0&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy=';
const USER_SYNC_URL_1 = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=2&i=1&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy=';
expect(userSync[0].url).to.equal(USER_SYNC_URL_0);
expect(userSync[1].url).to.equal(USER_SYNC_URL_1);
expect(userSync.length).to.equal(2);
});

it('UserSync test : check type = pixel, check usermatch URL with override greater than publisher syncs per bidder , use syncsperbidder', function () {
const syncOptions = {
'pixelEnabled': true
}
config.setConfig({
userSync: {
pixelEnabled: true,
syncsPerBidder: 3
}
});
let userSync = spec.getUserSyncs(syncOptions, [{'body': {'ext': {'publishersyncsperbidderoverride': 4}}}]);
expect(userSync[0].type).to.equal('image');
const USER_SYNC_URL_0 = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=3&i=0&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy=';
const USER_SYNC_URL_1 = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=3&i=1&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy=';
const USER_SYNC_URL_2 = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=3&i=2&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy=';
expect(userSync[0].url).to.equal(USER_SYNC_URL_0);
expect(userSync[1].url).to.equal(USER_SYNC_URL_1);
expect(userSync[2].url).to.equal(USER_SYNC_URL_2);
expect(userSync.length).to.equal(3);
});

it('UserSync test : check type = pixel, syncsPerBidder = 0, still use override', function () {
const syncOptions = {
'pixelEnabled': true
}
config.setConfig({
userSync: {
pixelEnabled: true,
syncsPerBidder: 0
}
});
let userSync = spec.getUserSyncs(syncOptions, [{'body': {'ext': {'publishersyncsperbidderoverride': 2}}}]);
expect(userSync[0].type).to.equal('image');
const USER_SYNC_URL_0 = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=2&i=0&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy=';
const USER_SYNC_URL_1 = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid&site_id=123&p=2&i=1&gdpr=1&gdpr_consent=3huaa11=qu3198ae&us_privacy=';
expect(userSync[0].url).to.equal(USER_SYNC_URL_0);
expect(userSync[1].url).to.equal(USER_SYNC_URL_1);
expect(userSync.length).to.equal(2);
});
});

Expand Down

0 comments on commit d9f3de5

Please sign in to comment.