Skip to content

Commit

Permalink
Rubicon Analytics: General Enhancements (#6995)
Browse files Browse the repository at this point in the history
* Enhancements for the analytics adapter

* do not send empty gam or adserverTargeting
  • Loading branch information
robertrmartinez authored Jun 10, 2021
1 parent c54c2b8 commit 2eef939
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 21 deletions.
47 changes: 33 additions & 14 deletions modules/rubiconAnalyticsAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ function formatSource(src) {
return src.toLowerCase();
}

function sendMessage(auctionId, bidWonId) {
function sendMessage(auctionId, bidWonId, trigger) {
function formatBid(bid) {
return utils.pick(bid, [
'bidder',
Expand Down Expand Up @@ -152,7 +152,7 @@ function sendMessage(auctionId, bidWonId) {
'videoAdFormat', () => bid.videoAdFormat,
'mediaTypes'
]), {
adserverTargeting: stringProperties(cache.targeting[bid.adUnit.adUnitCode] || {}),
adserverTargeting: !utils.isEmpty(cache.targeting[bid.adUnit.adUnitCode]) ? stringProperties(cache.targeting[bid.adUnit.adUnitCode]) : undefined,
bidwonStatus: 'success', // hard-coded for now
accountId,
siteId: bid.siteId,
Expand All @@ -163,7 +163,12 @@ function sendMessage(auctionId, bidWonId) {
let auctionCache = cache.auctions[auctionId];
let referrer = config.getConfig('pageUrl') || (auctionCache && auctionCache.referrer);
let message = {
eventTimeMillis: Date.now(),
timestamps: {
prebidLoaded: rubiconAdapter.MODULE_INITIALIZED_TIME,
auctionEnded: auctionCache.endTs,
eventTime: Date.now()
},
trigger,
integration: rubiConf.int_type || DEFAULT_INTEGRATION,
version: '$prebid.version$',
referrerUri: referrer,
Expand All @@ -187,8 +192,8 @@ function sendMessage(auctionId, bidWonId) {
'transactionId',
'mediaTypes',
'dimensions',
'adserverTargeting', () => stringProperties(cache.targeting[bid.adUnit.adUnitCode] || {}),
'gam',
'adserverTargeting', () => !utils.isEmpty(cache.targeting[bid.adUnit.adUnitCode]) ? stringProperties(cache.targeting[bid.adUnit.adUnitCode]) : undefined,
'gam', gam => !utils.isEmpty(gam) ? gam : undefined,
'pbAdSlot',
'pattern'
]);
Expand Down Expand Up @@ -319,6 +324,10 @@ function sendMessage(auctionId, bidWonId) {
);
}

function adUnitIsOnlyInstream(adUnit) {
return adUnit.mediaTypes && Object.keys(adUnit.mediaTypes).length === 1 && utils.deepAccess(adUnit, 'mediaTypes.video.context') === 'instream';
}

function getBidPrice(bid) {
// get the cpm from bidResponse
let cpm;
Expand Down Expand Up @@ -498,9 +507,9 @@ function subscribeToGamSlots() {
clearTimeout(cache.timeouts[auctionId]);
delete cache.timeouts[auctionId];
if (rubiConf.analyticsEventDelay > 0) {
setTimeout(() => sendMessage.call(rubiconAdapter, auctionId), rubiConf.analyticsEventDelay)
setTimeout(() => sendMessage.call(rubiconAdapter, auctionId, undefined, 'delayedGam'), rubiConf.analyticsEventDelay)
} else {
sendMessage.call(rubiconAdapter, auctionId)
sendMessage.call(rubiconAdapter, auctionId, undefined, 'gam')
}
}
});
Expand All @@ -509,6 +518,7 @@ function subscribeToGamSlots() {

let baseAdapter = adapter({analyticsType: 'endpoint'});
let rubiconAdapter = Object.assign({}, baseAdapter, {
MODULE_INITIALIZED_TIME: Date.now(),
referrerHostname: '',
enableAnalytics(config = {}) {
let error = false;
Expand Down Expand Up @@ -594,7 +604,7 @@ let rubiconAdapter = Object.assign({}, baseAdapter, {
// mark adUnits we expect bidWon events for
cache.auctions[args.auctionId].bidsWon[bid.adUnitCode] = false;

if (rubiConf.waitForGamSlots) {
if (rubiConf.waitForGamSlots && !adUnitIsOnlyInstream(bid)) {
cache.auctions[args.auctionId].gamHasRendered[bid.adUnitCode] = false;
}

Expand Down Expand Up @@ -750,7 +760,7 @@ let rubiconAdapter = Object.assign({}, baseAdapter, {

// check if this BID_WON missed the boat, if so send by itself
if (auctionCache.sent === true) {
sendMessage.call(this, args.auctionId, args.requestId);
sendMessage.call(this, args.auctionId, args.requestId, 'soloBidWon');
} else if (!rubiConf.waitForGamSlots && Object.keys(auctionCache.bidsWon).reduce((memo, adUnitCode) => {
// only send if we've received bidWon events for all adUnits in auction
memo = memo && auctionCache.bidsWon[adUnitCode];
Expand All @@ -759,14 +769,23 @@ let rubiconAdapter = Object.assign({}, baseAdapter, {
clearTimeout(cache.timeouts[args.auctionId]);
delete cache.timeouts[args.auctionId];

sendMessage.call(this, args.auctionId);
sendMessage.call(this, args.auctionId, undefined, 'allBidWons');
}
break;
case AUCTION_END:
// start timer to send batched payload just in case we don't hear any BID_WON events
cache.timeouts[args.auctionId] = setTimeout(() => {
sendMessage.call(this, args.auctionId);
}, rubiConf.analyticsBatchTimeout || SEND_TIMEOUT);
// see how long it takes for the payload to come fire
cache.auctions[args.auctionId].endTs = Date.now();

const isOnlyInstreamAuction = args.adUnits && args.adUnits.every(adUnit => adUnitIsOnlyInstream(adUnit));
// If only instream, do not wait around, just send payload
if (isOnlyInstreamAuction) {
sendMessage.call(this, args.auctionId, undefined, 'instreamAuction');
} else {
// start timer to send batched payload just in case we don't hear any BID_WON events
cache.timeouts[args.auctionId] = setTimeout(() => {
sendMessage.call(this, args.auctionId, undefined, 'auctionEnd');
}, rubiConf.analyticsBatchTimeout || SEND_TIMEOUT);
}
break;
case BID_TIMEOUT:
args.forEach(badBid => {
Expand Down
15 changes: 13 additions & 2 deletions test/spec/modules/rubiconAnalyticsAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,12 @@ const MOCK = {
}
}
},
'mediaType': 'video',
'mediaTypes': {
'video': {
'context': 'instream',
'playerSize': [640, 480]
}
},
'adUnitCode': '/19968336/header-bid-tag-0',
'transactionId': 'ca4af27a-6d02-4f90-949d-d5541fa12014',
'sizes': [[640, 480]],
Expand Down Expand Up @@ -362,7 +367,6 @@ const STUBBED_UUID = '12345678-1234-1234-1234-123456789abc';

const ANALYTICS_MESSAGE = {
'channel': 'web',
'eventTimeMillis': 1519767013781,
'integration': 'pbjs',
'version': '$prebid.version$',
'referrerUri': 'http://www.test.com/page.html',
Expand All @@ -371,6 +375,12 @@ const ANALYTICS_MESSAGE = {
'id': STUBBED_UUID,
'start': 1519767013781
},
'timestamps': {
'auctionEnded': 1519767013781,
'eventTime': 1519767013781,
'prebidLoaded': rubiconAnalyticsAdapter.MODULE_INITIALIZED_TIME
},
'trigger': 'allBidWons',
'referrerHostname': 'www.test.com',
'auctions': [
{
Expand Down Expand Up @@ -1658,6 +1668,7 @@ describe('rubicon analytics adapter', function () {
lineItemId: 6666,
adSlot: '/19968336/header-bid-tag1'
};
expectedMessage.trigger = 'gam';
expect(message).to.deep.equal(expectedMessage);
});

Expand Down
5 changes: 0 additions & 5 deletions test/spec/modules/rubiconAnalyticsSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
"description": "A batched data object describing the lifecycle of an auction or multiple auction across a single page view.",
"type": "object",
"required": [
"eventTimeMillis",
"integration",
"version"
],
Expand All @@ -21,10 +20,6 @@
}
],
"properties": {
"eventTimeMillis": {
"type": "integer",
"description": "Unix timestamp of time of creation for this batched event in milliseconds."
},
"integration": {
"type": "string",
"description": "Integration type that generated this event.",
Expand Down

0 comments on commit 2eef939

Please sign in to comment.