Skip to content

Commit

Permalink
EightPod Bid Adapter + EightPod Analytic Adapter - Support multiple a…
Browse files Browse the repository at this point in the history
…dUnit, updated event tracking, added UserId support (prebid#11944)

* Support multiple adUnit, updated event tracking, added UserId support

* remove unused params

* fix unit tests

* change MODULE_NAME

* added keepalive
  • Loading branch information
GreDiSe authored and mefjush committed Jul 19, 2024
1 parent 6cf3676 commit a39375d
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 104 deletions.
62 changes: 28 additions & 34 deletions modules/eightPodAnalyticsAdapter.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {logError, logInfo} from '../src/utils.js';
import {logError, logInfo, logMessage} from '../src/utils.js';
import {ajax} from '../src/ajax.js';
import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js';
import { EVENTS } from '../src/constants.js';
Expand All @@ -9,72 +9,72 @@ import {getStorageManager} from '../src/storageManager.js';
const analyticsType = 'endpoint';
const MODULE_NAME = `eightPod`;
const MODULE = `${MODULE_NAME}AnalyticProvider`;
let interval;

/**
* Custom tracking server that gets internal events from EightPod's ad unit
*/
const trackerUrl = 'https://demo.8pod.com/tracker/track';

export const storage = getStorageManager({moduleType: MODULE_TYPE_ANALYTICS, moduleName: MODULE_NAME})

const {
BID_WON
} = EVENTS;

export let queue = [];
export let context;
let context = {};

/**
* Create eightPod Analytic adapter
*/
let eightPodAnalytics = Object.assign(adapter({ analyticsType }), {
let eightPodAnalytics = Object.assign(adapter({url: trackerUrl, analyticsType}), {
/**
* Execute on bid won - setup basic settings, save context about EightPod's bid. We will send it with our events later
*/
track({ eventType, args }) {
switch (eventType) {
case BID_WON:
if (args.bidder === 'eightPod') {
context[args.adUnitCode] = makeContext(args);

eightPodAnalytics.setupPage(args);
context = makeContext(args);
break;
}
}
},

/**
* Execute on bid won - subscribe on events from adUnit
* Execute on bid won upload events from local storage
*/
setupPage() {
eightPodAnalytics.eventSubscribe();
queue = getEventFromLocalStorage();
queue = this.getEventFromLocalStorage();
},

/**
* Subscribe on internal ad unit tracking events
*/
eventSubscribe() {
window.addEventListener('message', async (event) => {
const data = event?.data;
const data = event.data;

if (!data?.detail?.name) {
return;
}
const frameElement = event.source.frameElement;
const parentElement = frameElement?.parentElement;
const adUnitCode = parentElement?.id;

trackEvent(data);
trackEvent(data, adUnitCode);
});

// Send queue of event every 10 seconds
if (!interval) {
interval = setInterval(sendEvents, 10_000);
}
setInterval(sendEvents, 10_000);
},
resetQueue() {
queue = [];
},
getContext() {
return context;
}
},
resetContext() {
context = {};
},
getEventFromLocalStorage,
});

/**
Expand All @@ -84,8 +84,8 @@ function makeContext(args) {
const params = args?.params?.[0];
return {
bidId: args.seatBidId,
variantId: args.creativeId || 'variantId',
campaignId: 'campaignId',
variantId: args.creativeId || '',
campaignId: args.cid || '',
publisherId: params.publisherId,
placementId: params.placementId,
};
Expand All @@ -94,19 +94,21 @@ function makeContext(args) {
/**
* Create event, add context and push it to queue
*/
export function trackEvent(event) {
export function trackEvent(event, adUnitCode) {
if (!event.detail) {
return;
}

const fullEvent = {
context: eightPodAnalytics.getContext(),
context: eightPodAnalytics.getContext()[adUnitCode],
eventType: event.detail.type,
eventClass: 'adunit',
timestamp: new Date().getTime(),
eventName: event.detail.name,
payload: event.detail.payload
};

logMessage(fullEvent);
addEvent(fullEvent);
}

Expand Down Expand Up @@ -158,7 +160,7 @@ function sendEvents() {
* Send event to our custom tracking server
*/
function sendEventsApi(eventList, callbacks) {
ajax(trackerUrl, callbacks, JSON.stringify(eventList));
ajax(trackerUrl, callbacks, JSON.stringify(eventList), {keepalive: true});
}

/**
Expand All @@ -173,21 +175,13 @@ eightPodAnalytics.originEnableAnalytics = eightPodAnalytics.enableAnalytics;
eightPodAnalytics.eventsStorage = [];

// override enableAnalytics so we can get access to the config passed in from the page
// Subscribe on events from adUnit
eightPodAnalytics.enableAnalytics = function (config) {
eightPodAnalytics.originEnableAnalytics(config);
logInfo(MODULE, 'init', config);
eightPodAnalytics.eventSubscribe();
};

eightPodAnalytics.disableAnalytics = (function (orig) {
return function (...args) {
if (interval) {
clearInterval(interval);
interval = null;
}
return orig.apply(this, args);
};
})(eightPodAnalytics.disableAnalytics);

/**
* Register Analytics Adapter
*/
Expand Down
170 changes: 113 additions & 57 deletions modules/eightPodBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { BANNER } from '../src/mediaTypes.js'
import * as utils from '../src/utils.js'

export const BIDDER_CODE = 'eightPod'
const url = 'https://demo.8pod.com/bidder/rtb/eightpod_exchange/bid?trace=true';
const url = 'https://demo.8pod.com/bidder/rtb/eightpod_exchange/bid';

export const spec = {
code: BIDDER_CODE,
Expand Down Expand Up @@ -49,8 +49,9 @@ function isBidRequestValid(bidRequest) {
function buildRequests(bids, bidderRequest) {
let bannerBids = bids.filter((bid) => isBannerBid(bid))
let requests = bannerBids.length
? [createRequest(bannerBids, bidderRequest, BANNER)]
? createRequest(bannerBids, bidderRequest, BANNER)
: []

return requests
}

Expand All @@ -61,8 +62,10 @@ function bidResponse(buildBidResponse, bid, context) {

bidResponse.height = context?.imp?.banner?.format?.[0].h;
bidResponse.width = context?.imp?.banner?.format?.[0].w;
bidResponse.cid = bid.cid;

bidResponse.burl = replacePriceInUrl(bid.burl, bidResponse.originalCpm || bidResponse.cpm);

return bidResponse;
}

Expand Down Expand Up @@ -119,64 +122,75 @@ export function getPageKeywords(win = window) {
}

function createRequest(bidRequests, bidderRequest, mediaType) {
const data = converter.toORTB({
bidRequests,
bidderRequest,
context: { mediaType },
});

data.adSlotPositionOnScreen = 'ABOVE_THE_FOLD';
data.at = 1;

const params = getBidderParams(bidRequests);

data.device = {
...data.device,
model: parseUserAgent().device,
os: parseUserAgent().platform,
osv: parseUserAgent().version,
geo: {
country: params.country || 'GRB'
},
language: params.language || data.device.language,
}
data.site = {
...data.site,
keywords: getPageKeywords(window),
}
data.imp = [
{
...data.imp?.[0],
pmp: params.dealId
? {
...data.pmp,
deals: [
{
bidfloor: 0.5,
at: 2,
id: params.dealId,
},
],
private_auction: 1,
}
: data.pmp,
const requests = bidRequests.map((bidRequest) => {
const data = converter.toORTB({
bidRequests: [bidRequest],
bidderRequest,
context: { mediaType },
});

data.adSlotPositionOnScreen = 'ABOVE_THE_FOLD';
data.at = 1;

const userId =
utils.deepAccess(bidRequest, 'userId.unifiedId.id') ||
utils.deepAccess(bidRequest, 'userId.id5id.uid') ||
utils.deepAccess(bidRequest, 'userId.idl_env');

const params = getBidderParams(bidRequest);
data.device = {
...data.device,
devicetype: 4,
geo: {
country: params.country || 'GRB'
},
language: params.language || data.device.language,
}
data.site = {
...data.site,
keywords: getPageKeywords(window),
publisher: {
id: params.publisherId
}
}
data.imp = [
{
...data.imp?.[0],
secure: 1,
pmp: params.dealId
? {
...data.pmp,
deals: [
{
id: params.dealId,
},
],
private_auction: 1,
}
: data.pmp,
}
]
data.adSlotPlacementId = params.placementId;

if (userId) {
data.user = {
id: userId
}
}
]
data.adSlotPlacementId = params.placementId;

const req = {
method: 'POST',
url,
data
}
return req
}
const req = {
method: 'POST',
url: url && params.trace ? url + '?trace=true' : url,
options: { withCredentials: false },
data
}
return req
})

function getBidderParams(bidRequests) {
const bid = bidRequests.find(bid => {
return bid.bidder === BIDDER_CODE
});
return requests;
}

function getBidderParams(bid) {
return bid?.params ? bid.params : undefined;
}

Expand All @@ -189,5 +203,47 @@ function isBannerBid(bid) {
}

function interpretResponse(resp, req) {
return converter.fromORTB({ request: req.data, response: resp.body })
const impressionId = resp.body.seatbid[0].bid[0].impid;
const bidResponses = converter.fromORTB({ request: req.data, response: resp.body });
const ad = bidResponses[0].ad;
const trackingTag = `<script src="https://cdn.doubleverify.com/dvtp_src.js?ctx=818052&cmp=APAC_Cert_20&sid=se_a551&plc=240411845&adsrv=0&btreg=ad-unit-container&auevent=${impressionId}&btadsrv=&crt=01&tagtype=&dvtagver=6.1.src" type="text/javascript"></script>
<script type="text/javascript">
(function() {
/** CONFIGURATION START **/
var _sf_async_config = window._sf_async_config = (window._sf_async_config || {});
_sf_async_config.uid = 67171;
_sf_async_config.domain = 'demo.8pod.com';
_sf_async_config.flickerControl = false;
_sf_async_config.useCanonical = true;
_sf_async_config.useCanonicalDomain = true;
_sf_async_config.sections = '';
_sf_async_config.authors = '';
/** CONFIGURATION END **/
function loadChartbeat() {
var e = document.createElement('script');
var n = document.getElementsByTagName('script')[0];
e.type = 'text/javascript';
e.async = true;
e.src = '//static.chartbeat.com/js/chartbeat.js';
n.parentNode.insertBefore(e, n);
}
loadChartbeat();
})();
</script>
<script async src="//static.chartbeat.com/js/chartbeat_mab.js"></script>
<script type="text/javascript">
var utag_data = {
}
</script>
<script type="text/javascript">
(function(a,b,c,d){
a='https://tags.tiqcdn.com/utag/sales-richard-coghlan/8pod/prod/utag.js';
b=document;c='script';d=b.createElement(c);d.src=a;d.type='text/java'+c;d.async=true;
a=b.getElementsByTagName(c)[0];a.parentNode.insertBefore(d,a);
})();
</script>`

bidResponses[0].ad = ad.replace('</head>', trackingTag + '</head>');
return bidResponses;
}
Loading

0 comments on commit a39375d

Please sign in to comment.