forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
LiveIntent Analytics Adapter: initial release (prebid#8960)
* CM-552 Liveintent Analytics Adapter (#4) * start work * send analytics event * Add first test and get winning bids from auctionManager * Add event test data and fix bugs * Remove duplicate userIds * add bidWonTimeout in configOptions * add sampling and adjust test * Add server test * Compare expected request body in the test * refactoring * update description * remove comment * comments * make sure we map defined data * refactoring * some refactoring * comments Co-authored-by: wiem <welabidine@liveintent.com> * fix typo * Use getRefererInfo to get url and ?? operator for default values Co-authored-by: Leonel Cuevas Valeriano <leonel.cvs@gmail.com> Co-authored-by: leonelcuevas <lcuevas@liveintent.com>
- Loading branch information
1 parent
ceb96ab
commit cac0902
Showing
3 changed files
with
467 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import {ajax} from '../src/ajax.js'; | ||
import { generateUUID, logInfo, logWarn } from '../src/utils.js'; | ||
import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; | ||
import CONSTANTS from '../src/constants.json'; | ||
import adapterManager from '../src/adapterManager.js'; | ||
import { auctionManager } from '../src/auctionManager.js'; | ||
import { getRefererInfo } from '../src/refererDetection.js'; | ||
|
||
const ANALYTICS_TYPE = 'endpoint'; | ||
const URL = 'https://wba.liadm.com/analytic-events'; | ||
const GVL_ID = 148; | ||
const ADAPTER_CODE = 'liveintent'; | ||
const DEFAULT_SAMPLING = 0.1; | ||
const DEFAULT_BID_WON_TIMEOUT = 2000; | ||
const { EVENTS: { AUCTION_END } } = CONSTANTS; | ||
let initOptions = {}; | ||
let isSampled; | ||
let bidWonTimeout; | ||
|
||
function handleAuctionEnd(args) { | ||
setTimeout(() => { | ||
const auction = auctionManager.index.getAuction(args.auctionId); | ||
const winningBids = (auction) ? auction.getWinningBids() : []; | ||
const data = createAnalyticsEvent(args, winningBids); | ||
sendAnalyticsEvent(data); | ||
}, bidWonTimeout); | ||
} | ||
|
||
function getAnalyticsEventBids(bidsReceived) { | ||
return bidsReceived.map(bid => { | ||
return { | ||
adUnitCode: bid.adUnitCode, | ||
timeToRespond: bid.timeToRespond, | ||
cpm: bid.cpm, | ||
currency: bid.currency, | ||
ttl: bid.ttl, | ||
bidder: bid.bidder | ||
}; | ||
}); | ||
} | ||
|
||
function getBannerSizes(banner) { | ||
if (banner && banner.sizes) { | ||
return banner.sizes.map(size => { | ||
const [width, height] = size; | ||
return {w: width, h: height}; | ||
}); | ||
} else return []; | ||
} | ||
|
||
function getUniqueBy(arr, key) { | ||
return [...new Map(arr.map(item => [item[key], item])).values()] | ||
} | ||
|
||
function createAnalyticsEvent(args, winningBids) { | ||
let payload = { | ||
instanceId: generateUUID(), | ||
url: getRefererInfo().page, | ||
bidsReceived: getAnalyticsEventBids(args.bidsReceived), | ||
auctionStart: args.timestamp, | ||
auctionEnd: args.auctionEnd, | ||
adUnits: [], | ||
userIds: [], | ||
bidders: [] | ||
} | ||
let allUserIds = []; | ||
|
||
if (args.adUnits) { | ||
args.adUnits.forEach(unit => { | ||
if (unit.mediaTypes && unit.mediaTypes.banner) { | ||
payload['adUnits'].push({ | ||
code: unit.code, | ||
mediaType: 'banner', | ||
sizes: getBannerSizes(unit.mediaTypes.banner), | ||
ortb2Imp: unit.ortb2Imp | ||
}); | ||
} | ||
if (unit.bids) { | ||
let userIds = unit.bids.flatMap(getAnalyticsEventUserIds); | ||
allUserIds.push(...userIds); | ||
let bidders = unit.bids.map(({bidder, params}) => { | ||
return { bidder, params } | ||
}); | ||
|
||
payload['bidders'].push(...bidders); | ||
} | ||
}) | ||
let uniqueUserIds = getUniqueBy(allUserIds, 'source'); | ||
payload['userIds'] = uniqueUserIds; | ||
} | ||
payload['winningBids'] = getAnalyticsEventBids(winningBids); | ||
payload['auctionId'] = args.auctionId; | ||
return payload; | ||
} | ||
|
||
function getAnalyticsEventUserIds(bid) { | ||
if (bid && bid.userIdAsEids) { | ||
return bid.userIdAsEids.map(({source, uids, ext}) => { | ||
let analyticsEventUserId = {source, uids, ext}; | ||
return ignoreUndefined(analyticsEventUserId) | ||
}); | ||
} else { return []; } | ||
} | ||
|
||
function sendAnalyticsEvent(data) { | ||
ajax(URL, { | ||
success: function () { | ||
logInfo('LiveIntent Prebid Analytics: send data success'); | ||
}, | ||
error: function (e) { | ||
logWarn('LiveIntent Prebid Analytics: send data error' + e); | ||
} | ||
}, JSON.stringify(data), { | ||
contentType: 'application/json', | ||
method: 'POST' | ||
}) | ||
} | ||
|
||
function ignoreUndefined(data) { | ||
const filteredData = Object.entries(data).filter(([key, value]) => value) | ||
return Object.fromEntries(filteredData) | ||
} | ||
|
||
let liAnalytics = Object.assign(adapter({URL, ANALYTICS_TYPE}), { | ||
track({ eventType, args }) { | ||
if (eventType == AUCTION_END && args && isSampled) { handleAuctionEnd(args); } | ||
} | ||
}); | ||
|
||
// save the base class function | ||
liAnalytics.originEnableAnalytics = liAnalytics.enableAnalytics; | ||
|
||
// override enableAnalytics so we can get access to the config passed in from the page | ||
liAnalytics.enableAnalytics = function (config) { | ||
initOptions = config.options; | ||
const sampling = (initOptions && initOptions.sampling) ?? DEFAULT_SAMPLING; | ||
isSampled = Math.random() < parseFloat(sampling); | ||
bidWonTimeout = (initOptions && initOptions.bidWonTimeout) ?? DEFAULT_BID_WON_TIMEOUT; | ||
liAnalytics.originEnableAnalytics(config); // call the base class function | ||
}; | ||
|
||
adapterManager.registerAnalyticsAdapter({ | ||
adapter: liAnalytics, | ||
code: ADAPTER_CODE, | ||
gvlid: GVL_ID | ||
}); | ||
|
||
export default liAnalytics; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Overview | ||
Module Name: LiveIntent Analytics Adapter | ||
|
||
Module Type: Analytics Adapter | ||
|
||
Maintainer: product@liveintent.com | ||
|
||
# Description | ||
|
||
Analytics adapter for [LiveIntent](https://www.liveintent.com/). Contact product@liveintent.com for information. | ||
|
||
# Test Parameters | ||
|
||
``` | ||
{ | ||
provider: 'liveintent', | ||
options: { | ||
bidWonTimeout: 2000, | ||
sampling: 0.5 // the tracked event percentage, a number between 0 to 1 | ||
} | ||
} | ||
``` |
Oops, something went wrong.