Skip to content

Commit

Permalink
Oxxion Rtd Module: cleaning and change in sampling (prebid#10539)
Browse files Browse the repository at this point in the history
* remove video stuffs

* update sampling

* listen for 'ova' parameter

* update sampling
  • Loading branch information
matthieularere-msq authored Sep 29, 2023
1 parent 702bbbe commit 6c7356a
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 188 deletions.
2 changes: 1 addition & 1 deletion modules/oxxionAnalyticsAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ let auctionEnd = {}
let initOptions = {}
let mode = {};
let endpoint = 'https://default'
let requestsAttributes = ['adUnitCode', 'auctionId', 'bidder', 'bidderCode', 'bidId', 'cpm', 'creativeId', 'currency', 'width', 'height', 'mediaType', 'netRevenue', 'originalCpm', 'originalCurrency', 'requestId', 'size', 'source', 'status', 'timeToRespond', 'transactionId', 'ttl', 'sizes', 'mediaTypes', 'src', 'params', 'userId', 'labelAny', 'bids', 'adId'];
let requestsAttributes = ['adUnitCode', 'auctionId', 'bidder', 'bidderCode', 'bidId', 'cpm', 'creativeId', 'currency', 'width', 'height', 'mediaType', 'netRevenue', 'originalCpm', 'originalCurrency', 'requestId', 'size', 'source', 'status', 'timeToRespond', 'transactionId', 'ttl', 'sizes', 'mediaTypes', 'src', 'params', 'userId', 'labelAny', 'bids', 'adId', 'ova'];

function getAdapterNameForAlias(aliasName) {
return adapterManager.aliasRegistry[aliasName] || aliasName;
Expand Down
103 changes: 19 additions & 84 deletions modules/oxxionRtdProvider.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
import { submodule } from '../src/hook.js'
import { deepAccess, logInfo, logError } from '../src/utils.js'
import { logInfo, logError } from '../src/utils.js'
import { ajax } from '../src/ajax.js';
import adapterManager from '../src/adapterManager.js';

const oxxionRtdSearchFor = [ 'adUnitCode', 'auctionId', 'bidder', 'bidderCode', 'bidId', 'cpm', 'creativeId', 'currency', 'width', 'height', 'mediaType', 'netRevenue', 'originalCpm', 'originalCurrency', 'requestId', 'size', 'source', 'status', 'timeToRespond', 'transactionId', 'ttl', 'sizes', 'mediaTypes', 'src', 'userId', 'labelAny', 'adId' ];
const LOG_PREFIX = 'oxxionRtdProvider submodule: ';

const allAdUnits = [];
const bidderAliasRegistry = adapterManager.aliasRegistry || {};

/** @type {RtdSubmodule} */
export const oxxionSubmodule = {
name: 'oxxionRtd',
init: init,
getBidRequestData: getAdUnits,
onBidResponseEvent: insertVideoTracking,
getRequestsList: getRequestsList,
getFilteredAdUnitsOnBidRates: getFilteredAdUnitsOnBidRates,
};

function init(config, userConsent) {
if (!config.params || !config.params.domain) { return false }
if (config.params.contexts && Array.isArray(config.params.contexts) && config.params.contexts.length > 0) { return true; }
if (typeof config.params.threshold != 'undefined' && typeof config.params.samplingRate == 'number') { return true }
return false;
}
Expand Down Expand Up @@ -53,81 +49,6 @@ function getAdUnits(reqBidsConfigObj, callback, config, userConsent) {
if (typeof callback == 'function') { callback(); }
}).catch(error => logError(LOG_PREFIX, 'bidInterestError', error));
}
if (config.params.contexts && Array.isArray(config.params.contexts) && config.params.contexts.length > 0) {
const reqAdUnits = reqBidsConfigObj.adUnits;
if (Array.isArray(reqAdUnits)) {
reqAdUnits.forEach(adunit => {
if (config.params.contexts.includes(deepAccess(adunit, 'mediaTypes.video.context'))) {
allAdUnits.push(adunit);
}
});
}
if (!(typeof config.params.threshold != 'undefined' && typeof config.params.samplingRate == 'number') && typeof callback == 'function') {
callback();
}
}
}

function insertVideoTracking(bidResponse, config, userConsent) {
// this should only be do for video bids
if (bidResponse.mediaType === 'video') {
let maxCpm = 0;
const trackingUrl = getImpUrl(config, bidResponse, maxCpm);
if (!trackingUrl) {
return;
}
// Vast Impression URL
if (bidResponse.vastUrl) {
bidResponse.vastImpUrl = bidResponse.vastImpUrl
? trackingUrl + '&url=' + encodeURI(bidResponse.vastImpUrl)
: trackingUrl;
logInfo(LOG_PREFIX + 'insert into vastImpUrl for adId ' + bidResponse.adId);
}
// Vast XML document
if (bidResponse.vastXml !== undefined) {
const doc = new DOMParser().parseFromString(bidResponse.vastXml, 'text/xml');
const wrappers = doc.querySelectorAll('VAST Ad Wrapper, VAST Ad InLine');
let hasAltered = false;
if (wrappers.length) {
wrappers.forEach(wrapper => {
const impression = doc.createElement('Impression');
impression.appendChild(doc.createCDATASection(trackingUrl));
wrapper.appendChild(impression)
});
bidResponse.vastXml = new XMLSerializer().serializeToString(doc);
hasAltered = true;
}
if (hasAltered) {
logInfo(LOG_PREFIX + 'insert into vastXml for adId ' + bidResponse.adId);
}
}
}
}

function getImpUrl(config, data, maxCpm) {
const adUnitCode = data.adUnitCode;
const adUnits = allAdUnits.find(adunit => adunit.code === adUnitCode &&
'mediaTypes' in adunit &&
'video' in adunit.mediaTypes &&
typeof adunit.mediaTypes.video.context === 'string');
const context = adUnits !== undefined
? adUnits.mediaTypes.video.context
: 'unknown';
if (!config.params.contexts.includes(context)) {
return false;
}
let trackingImpUrl = 'https://' + config.params.domain + '.oxxion.io/analytics/vast_imp?';
trackingImpUrl += oxxionRtdSearchFor.reduce((acc, param) => {
switch (typeof data[param]) {
case 'string':
case 'number':
acc += param + '=' + data[param] + '&'
break;
}
return acc;
}, '');
const cpmIncrement = 0.0;
return trackingImpUrl + 'cpmIncrement=' + cpmIncrement + '&context=' + context;
}

function getPromisifiedAjax (url, data = {}, options = {}) {
Expand All @@ -146,22 +67,27 @@ function getPromisifiedAjax (url, data = {}, options = {}) {

function getFilteredAdUnitsOnBidRates (bidsRateInterests, adUnits, params, useSampling) {
const { threshold, samplingRate } = params;
const sampling = getRandomNumber(100) < samplingRate && useSampling;
const filteredBids = [];
// Separate bidsRateInterests in two groups against threshold & samplingRate
const { interestingBidsRates, uninterestingBidsRates } = bidsRateInterests.reduce((acc, interestingBid) => {
const { interestingBidsRates, uninterestingBidsRates, sampledBidsRates } = bidsRateInterests.reduce((acc, interestingBid) => {
const isBidRateUpper = typeof threshold == 'number' ? interestingBid.rate === true || interestingBid.rate > threshold : interestingBid.suggestion;
const isBidInteresting = isBidRateUpper || (getRandomNumber(100) < samplingRate && useSampling);
const isBidInteresting = isBidRateUpper || sampling;
const key = isBidInteresting ? 'interestingBidsRates' : 'uninterestingBidsRates';
acc[key].push(interestingBid);
if (!isBidRateUpper && sampling) {
acc['sampledBidsRates'].push(interestingBid);
}
return acc;
}, {
interestingBidsRates: [],
uninterestingBidsRates: [] // Do something with later
uninterestingBidsRates: [], // Do something with later
sampledBidsRates: []
});
logInfo(LOG_PREFIX, 'getFilteredAdUnitsOnBidRates()', interestingBidsRates, uninterestingBidsRates);
// Filter bids and adUnits against interesting bids rates
const newAdUnits = adUnits.filter(({ bids = [] }, adUnitIndex) => {
adUnits[adUnitIndex].bids = bids.filter(bid => {
adUnits[adUnitIndex].bids = bids.filter((bid, bidIndex) => {
if (!params.bidders || params.bidders.includes(bid.bidder)) {
const index = interestingBidsRates.findIndex(({ id }) => id === bid._id);
if (index == -1) {
Expand All @@ -173,10 +99,19 @@ function getFilteredAdUnitsOnBidRates (bidsRateInterests, adUnits, params, useSa
delete tmpBid.floorData;
}
filteredBids.push(tmpBid);
adUnits[adUnitIndex].bids[bidIndex]['ova'] = 'filtered';
} else {
if (sampledBidsRates.findIndex(({ id }) => id === bid._id) == -1) {
adUnits[adUnitIndex].bids[bidIndex]['ova'] = 'cleared';
} else {
adUnits[adUnitIndex].bids[bidIndex]['ova'] = 'sampled';
logInfo(LOG_PREFIX + ' sampled ! ');
}
}
delete bid._id;
return index !== -1;
} else {
adUnits[adUnitIndex].bids[bidIndex]['ova'] = 'protected';
return true;
}
});
Expand Down
9 changes: 1 addition & 8 deletions modules/oxxionRtdProvider.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Maintainer: tech@oxxion.io
# Oxxion Real-Time-Data submodule

Oxxion helps you to understand how your prebid stack performs.
This Rtd module is to use in order to improve video events tracking and/or to filter bidder requested.
This Rtd module purpose is to filter bidders requested.

# Integration

Expand All @@ -30,7 +30,6 @@ pbjs.setConfig(
waitForIt: true,
params: {
domain: "test.endpoint",
contexts: ["instream"],
threshold: false,
samplingRate: 10,
}
Expand All @@ -47,12 +46,6 @@ pbjs.setConfig(
|:---------------------------------|:---------|:------------------------------------------------------------------------------------------------------------|
| domain | String | This string identifies yourself in Oxxion's systems and is provided to you by your Oxxion representative. |

# setConfig Parameters for Video Tracking

| Name | Type | Description |
|:---------------------------------|:---------|:------------------------------------------------------------------------------------------------------------|
| contexts | Array | Array defining which video contexts to add tracking events into. Values can be instream and/or outstream. |

# setConfig Parameters for bidder filtering

| Name | Type | Description |
Expand Down
95 changes: 0 additions & 95 deletions test/spec/modules/oxxionRtdProvider_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,77 +113,6 @@ let bids = [{
},
];

let originalBidderRequests = [{
'bidderCode': 'rubicon',
'auctionId': 'dd42b870-2072-4b71-8ab7-e7789b14c5ce',
'bidderRequestId': '16c2bceb2e891a',
'bids': [
{
'bidder': 'rubicon',
'params': {
'accountId': 1234,
'siteId': 2345,
'zoneId': 3456
},
'auctionId': 'dd42b870-2072-4b71-8ab7-e7789b14c5ce',
'mediaTypes': {'banner': {'sizes': [[970, 250]]}},
'adUnitCode': 'adunit1',
'transactionId': '8f20b49c-5e47-4bb5-a7d5-0b816cf527f3',
'bidId': '2d9920072ab028',
'bidderRequestId': '16c2bceb2e891a',
},
{
'bidder': 'rubicon',
'params': {
'accountId': 1234,
'siteId': 2345,
'zoneId': 4567
},
'auctionId': 'dd42b870-2072-4b71-8ab7-e7789b14c5ce',
'mediaTypes': {'banner': {'sizes': [[300, 250]]}},
'adUnitCode': 'adunit2',
'transactionId': '4161f09e-7870-4486-b2a6-b4158a327bc4',
'bidId': '331c3d708f4864',
'bidderRequestId': '16c2bceb2e891a',
'src': 'client',
}
],
'auctionStart': 1683383333809,
'timeout': 3000,
'gdprConsent': {
'consentString': 'consent_hash',
'gdprApplies': true,
'apiVersion': 2
}
},
{
'bidderCode': 'appnexusAst',
'auctionId': 'dd42b870-2072-4b71-8ab7-e7789b14c5ce',
'bidderRequestId': '4d83b8c60d45e7',
'bids': [
{
'bidder': 'appnexusAst',
'params': {
'placementId': 10471298
},
'auctionId': 'dd42b870-2072-4b71-8ab7-e7789b14c5ce',
'mediaTypes': {'banner': {'sizes': [[300, 250]]}},
'adUnitCode': 'adunit2',
'transactionId': '4161f09e-7870-4486-b2a6-b4158a327bc4',
'bidId': '5b7cd5abc6aea3',
'bidderRequestId': '4d83b8c60d45e7',
}
],
'auctionStart': 1683383333809,
'timeout': 3000,
'gdprConsent': {
'consentString': 'consent_hash',
'gdprApplies': true,
'apiVersion': 2
}
}
];

let bidInterests = [
{'id': 0, 'rate': 50.0, 'suggestion': true},
{'id': 1, 'rate': 12.0, 'suggestion': false},
Expand Down Expand Up @@ -212,8 +141,6 @@ describe('oxxionRtdProvider', () => {
auctionEnd.bidsReceived = bids;
it('call everything', function() {
oxxionSubmodule.getBidRequestData(request, null, moduleConfig);
oxxionSubmodule.onBidResponseEvent(auctionEnd.bidsReceived[0], moduleConfig);
oxxionSubmodule.onBidResponseEvent(auctionEnd.bidsReceived[1], moduleConfig);
});
it('check bid filtering', function() {
let requestsList = oxxionSubmodule.getRequestsList(request);
Expand All @@ -229,27 +156,5 @@ describe('oxxionRtdProvider', () => {
expect(filteredBiddderRequests[1]).to.have.property('bids');
expect(filteredBiddderRequests[1].bids.length).to.equal(1);
});
it('check vastImpUrl', function() {
expect(auctionEnd.bidsReceived[0]).to.have.property('vastImpUrl');
let expectVastImpUrl = 'https://' + moduleConfig.params.domain + '.oxxion.io/analytics/vast_imp?';
expect(auctionEnd.bidsReceived[1].vastImpUrl).to.contain(expectVastImpUrl);
expect(auctionEnd.bidsReceived[1].vastImpUrl).to.contain(encodeURI('https://some.tracking-url.com'));
});
it('check vastXml', function() {
expect(auctionEnd.bidsReceived[0]).to.have.property('vastXml');
let vastWrapper = new DOMParser().parseFromString(auctionEnd.bidsReceived[0].vastXml, 'text/xml');
let impressions = vastWrapper.querySelectorAll('VAST Ad Wrapper Impression');
expect(impressions.length).to.equal(2);
expect(auctionEnd.bidsReceived[1]).to.have.property('vastXml');
expect(auctionEnd.bidsReceived[1].adId).to.equal('4b2e1581c0ca1a');
let vastInline = new DOMParser().parseFromString(auctionEnd.bidsReceived[1].vastXml, 'text/xml');
let inline = vastInline.querySelectorAll('VAST Ad InLine');
expect(inline).to.have.lengthOf(1);
let inlineImpressions = vastInline.querySelectorAll('VAST Ad InLine Impression');
expect(inlineImpressions).to.have.lengthOf.above(0);
});
it('check cpmIncrement', function() {
expect(auctionEnd.bidsReceived[1].vastImpUrl).to.contain(encodeURI('cpmIncrement=0'));
});
});
});

0 comments on commit 6c7356a

Please sign in to comment.