Skip to content
154 changes: 149 additions & 5 deletions modules/taboolaBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {BANNER} from '../src/mediaTypes.js';
import {config} from '../src/config.js';
import {deepSetValue, getWindowSelf, replaceAuctionPrice, isArray, safeJSONParse, isPlainObject} from '../src/utils.js';
import {deepSetValue, getWindowSelf, replaceAuctionPrice, isArray, safeJSONParse, isPlainObject, getWinDimensions} from '../src/utils.js';
import {getStorageManager} from '../src/storageManager.js';
import {ajax} from '../src/ajax.js';
import {ortbConverter} from '../libraries/ortbConverter/converter.js';
import {isWebdriverEnabled} from '../libraries/webdriver/webdriver.js';
import {getConnectionType} from '../libraries/connectionInfo/connectionUtils.js';
import {getViewportCoordinates} from '../libraries/viewport/viewport.js';
import {percentInView} from '../libraries/percentInView/percentInView.js';
import {getBoundingClientRect} from '../libraries/boundingClientRect/boundingClientRect.js';

const BIDDER_CODE = 'taboola';
const GVLID = 42;
Expand All @@ -21,6 +26,7 @@ const TGID_COOKIE_KEY = 't_gid';
const TGID_PT_COOKIE_KEY = 't_pt_gid';
const TBLA_ID_COOKIE_KEY = 'tbla_id';
export const EVENT_ENDPOINT = 'https://beacon.bidder.taboola.com';
export const refreshState = {};

/**
* extract User Id by that order:
Expand Down Expand Up @@ -95,6 +101,105 @@ export const internal = {
}
}

export function getRefreshInfo(adUnitCode) {
const now = Date.now();
const state = refreshState[adUnitCode];

if (!state) {
refreshState[adUnitCode] = {
count: 1,
first: now,
last: now
};
return {
count: 1,
first: now,
sinceLastSeconds: null,
sinceFirstSeconds: 0
};
}

const sinceLastSeconds = Math.round((now - state.last) / 1000);
const sinceFirstSeconds = Math.round((now - state.first) / 1000);
state.count++;
state.last = now;

return {
count: state.count,
first: state.first,
sinceLastSeconds,
sinceFirstSeconds
};
}

export function detectBot() {
try {
return {
detected: !!(
isWebdriverEnabled() ||
window.__nightmare ||
window.callPhantom ||
window._phantom ||
/HeadlessChrome/.test(navigator.userAgent)
)
};
} catch (e) {
return { detected: false };
}
}

export function getPageVisibility() {
try {
return {
hidden: document.hidden,
state: document.visibilityState,
hasFocus: document.hasFocus()
};
} catch (e) {
return { hidden: false, state: 'visible', hasFocus: true };
}
}

export function getDeviceExtSignals(existingExt = {}) {
const viewport = getViewportCoordinates();
return {
...existingExt,
bot: detectBot(),
visibility: getPageVisibility(),
scroll: {
top: Math.round(viewport.top),
left: Math.round(viewport.left)
}
};
}

export function getElementSignals(adUnitCode) {
try {
const element = document.getElementById(adUnitCode);
if (!element) return null;

const rect = getBoundingClientRect(element);
const winDimensions = getWinDimensions();
const rawViewability = percentInView(element);

const signals = {
placement: {
top: Math.round(rect.top),
left: Math.round(rect.left)
},
fold: rect.top < winDimensions.innerHeight ? 'above' : 'below'
};

if (rawViewability !== null && !isNaN(rawViewability)) {
signals.viewability = Math.round(rawViewability);
}

return signals;
} catch (e) {
return null;
}
}

const converter = ortbConverter({
context: {
netRevenue: true,
Expand All @@ -108,7 +213,7 @@ const converter = ortbConverter({
},
request(buildRequest, imps, bidderRequest, context) {
const reqData = buildRequest(imps, bidderRequest, context);
fillTaboolaReqData(bidderRequest, context.bidRequests[0], reqData)
fillTaboolaReqData(bidderRequest, context.bidRequests[0], reqData, context);
return reqData;
},
bidResponse(buildBidResponse, bid, context) {
Expand Down Expand Up @@ -137,7 +242,12 @@ export const spec = {
},
buildRequests: (validBidRequests, bidderRequest) => {
const [bidRequest] = validBidRequests;
const data = converter.toORTB({bidderRequest: bidderRequest, bidRequests: validBidRequests});
const auctionId = bidderRequest.auctionId || validBidRequests[0]?.auctionId;
const data = converter.toORTB({
bidderRequest: bidderRequest,
bidRequests: validBidRequests,
context: { auctionId }
});
const {publisherId} = bidRequest.params;
const url = END_POINT_URL + '?publisher=' + publisherId;

Expand Down Expand Up @@ -287,10 +397,19 @@ function getSiteProperties({publisherId}, refererInfo, ortb2) {
}
}

function fillTaboolaReqData(bidderRequest, bidRequest, data) {
function fillTaboolaReqData(bidderRequest, bidRequest, data, context) {
const {refererInfo, gdprConsent = {}, uspConsent} = bidderRequest;
const site = getSiteProperties(bidRequest.params, refererInfo, bidderRequest.ortb2);
deepSetValue(data, 'device', bidderRequest?.ortb2?.device);

const ortb2Device = bidderRequest?.ortb2?.device || {};
const connectionType = getConnectionType();
const device = {
...ortb2Device,
js: 1,
...(connectionType && { connectiontype: connectionType }),
ext: getDeviceExtSignals(ortb2Device.ext)
};
deepSetValue(data, 'device', device);
const extractedUserId = userData.getUserId(gdprConsent, uspConsent);
if (data.user === undefined || data.user === null) {
data.user = {
Expand Down Expand Up @@ -340,6 +459,10 @@ function fillTaboolaReqData(bidderRequest, bidRequest, data) {
data.wlang = ortb2.wlang || bidRequest.params.wlang || [];
deepSetValue(data, 'ext.pageType', ortb2?.ext?.data?.pageType || ortb2?.ext?.data?.section || bidRequest.params.pageType);
deepSetValue(data, 'ext.prebid.version', '$prebid.version$');
const auctionId = context?.auctionId;
if (auctionId) {
deepSetValue(data, 'ext.prebid.auctionId', auctionId);
}
}

function fillTaboolaImpData(bid, imp) {
Expand All @@ -362,6 +485,27 @@ function fillTaboolaImpData(bid, imp) {
imp.bidfloorcur = bidfloorcur;
}
deepSetValue(imp, 'ext.gpid', bid?.ortb2Imp?.ext?.gpid);

if (bid.bidId) {
deepSetValue(imp, 'ext.prebid.bidId', bid.bidId);
}
if (bid.adUnitCode) {
deepSetValue(imp, 'ext.prebid.adUnitCode', bid.adUnitCode);
const refreshInfo = getRefreshInfo(bid.adUnitCode);
deepSetValue(imp, 'ext.prebid.refresh', refreshInfo);
}
if (bid.adUnitId) {
deepSetValue(imp, 'ext.prebid.adUnitId', bid.adUnitId);
}

const elementSignals = getElementSignals(bid.adUnitCode);
if (elementSignals) {
if (elementSignals.viewability !== undefined) {
deepSetValue(imp, 'ext.viewability', elementSignals.viewability);
}
deepSetValue(imp, 'ext.placement', elementSignals.placement);
deepSetValue(imp, 'ext.fold', elementSignals.fold);
}
}

function getBanners(bid, pos) {
Expand Down
Loading
Loading