Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b532636
add deferredBilling support using onBidBillable
talavital7 Nov 26, 2025
a0ffb60
update burl setting
talavital7 Nov 27, 2025
8239512
support nurl firing logic
talavital7 Dec 4, 2025
c99691e
Merge pull request #3 from taboola/taboola-support-deferred-billing
talavital7 Dec 7, 2025
86197f4
Merge branch 'prebid:master' into master
talavital7 Dec 9, 2025
fd4ca2e
Merge branch 'prebid:master' into master
talavital7 Dec 14, 2025
f89d229
add extra signals to taboola request
talavital7 Dec 24, 2025
ef52a90
add extra ad signals
talavital7 Dec 25, 2025
090f442
fix missing semicolon
talavital7 Dec 28, 2025
79840c8
Merge branch 'prebid:master' into master
talavital7 Dec 28, 2025
3525ebd
Merge pull request #4 from taboola/taboola-support-extra-signals
talavital7 Dec 28, 2025
124fda1
use Prebid's built-in counters
talavital7 Jan 13, 2026
cc1e999
Merge pull request #7 from taboola/taboola-support-extra-signals
talavital7 Jan 13, 2026
920bfe2
Merge branch 'prebid:master' into master
talavital7 Jan 14, 2026
ba8d780
updated detectBot logic
talavital7 Jan 15, 2026
5b3f6e7
Merge pull request #8 from taboola/taboola-support-extra-signals
talavital7 Jan 15, 2026
802e4a7
Merge branch 'prebid:master' into master
ronishefi9 Feb 2, 2026
d4de9d4
In Taboola adapter, added support for native and adjusted the existin…
ronishefi9 Jan 11, 2026
d7fae23
In Taboola adapter, added support for native and adjusted the existin…
ronishefi9 Jan 11, 2026
53fe2c5
removed test page pushed accidentally
ronishefi9 Jan 11, 2026
a9754e9
Wrapped native tests with NATIVE feature check
ronishefi9 Jan 11, 2026
3f7d7ae
updated media type checks
ronishefi9 Jan 14, 2026
15ad62f
added missing tab
ronishefi9 Jan 14, 2026
4cad25d
removed tab
ronishefi9 Feb 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 44 additions & 12 deletions modules/taboolaBidAdapter.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

import {registerBidder} from '../src/adapters/bidderFactory.js';
import {BANNER} from '../src/mediaTypes.js';
import {BANNER, NATIVE} from '../src/mediaTypes.js';
import {config} from '../src/config.js';
import {deepSetValue, getWindowSelf, replaceAuctionPrice, isArray, safeJSONParse, isPlainObject, getWinDimensions} from '../src/utils.js';
import {getStorageManager} from '../src/storageManager.js';
Expand All @@ -15,7 +15,8 @@ import {getBoundingClientRect} from '../libraries/boundingClientRect/boundingCli
const BIDDER_CODE = 'taboola';
const GVLID = 42;
const CURRENCY = 'USD';
export const END_POINT_URL = 'https://display.bidder.taboola.com/OpenRTB/TaboolaHB/auction';
export const BANNER_ENDPOINT_URL = 'https://display.bidder.taboola.com/OpenRTB/TaboolaHB/auction';
export const NATIVE_ENDPOINT_URL = 'https://native.bidder.taboola.com/OpenRTB/TaboolaHB/auction';
export const USER_SYNC_IMG_URL = 'https://trc.taboola.com/sg/prebidJS/1/cm';
export const USER_SYNC_IFRAME_URL = 'https://cdn.taboola.com/scripts/prebid_iframe_sync.html';
const USER_ID = 'user-id';
Expand Down Expand Up @@ -169,7 +170,6 @@ export function getElementSignals(adUnitCode) {
const converter = ortbConverter({
context: {
netRevenue: true,
mediaType: BANNER,
ttl: 300
},
imp(buildImp, bidRequest, context) {
Expand All @@ -183,12 +183,24 @@ const converter = ortbConverter({
return reqData;
},
bidResponse(buildBidResponse, bid, context) {
const { mediaType } = getMediaType(context.bidRequest);
context.mediaType = mediaType;
Comment on lines +186 to +187

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve ORTB mtype when decoding mixed-format responses

The response converter unconditionally sets context.mediaType from the original bid request, and getMediaType resolves mixed banner+native requests to banner. That overrides the default ORTB media-type detection from bid.mtype, so native bids returned for mixed-format requests are interpreted as banner (missing native.ortb and getting banner ad handling instead).

Useful? React with 👍 / 👎.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ronishefi9 this seems like a significant issue, much of your native demand will be multiformat


if (context.mediaType === NATIVE) {
const admObj = safeJSONParse(bid.adm);
if (admObj?.native) {
bid.adm = JSON.stringify(admObj.native);
}
}

const bidResponse = buildBidResponse(bid, context);
bidResponse.nurl = bid.nurl;
if (bid.burl) {
bidResponse.burl = bid.burl;
}
bidResponse.ad = replaceAuctionPrice(bid.adm, bid.price);
if (bidResponse.mediaType !== NATIVE) {
bidResponse.ad = replaceAuctionPrice(bid.adm, bid.price);
}
if (bid.ext && bid.ext.dchain) {
deepSetValue(bidResponse, 'meta.dchain', bid.ext.dchain);
}
Expand All @@ -197,14 +209,18 @@ const converter = ortbConverter({
});

export const spec = {
supportedMediaTypes: [BANNER],
supportedMediaTypes: [BANNER, NATIVE],
gvlid: GVLID,
code: BIDDER_CODE,
isBidRequestValid: (bidRequest) => {
return !!(bidRequest.sizes &&
bidRequest.params &&
const hasPublisherAndTag = !!(bidRequest.params &&
bidRequest.params.publisherId &&
bidRequest.params.tagId);
if (!hasPublisherAndTag) {
return false;
}
const { hasBanner, hasNative } = getMediaType(bidRequest);
return hasBanner || hasNative;
},
buildRequests: (validBidRequests, bidderRequest) => {
const [bidRequest] = validBidRequests;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Split requests by media type before choosing endpoint

buildRequests picks the endpoint from only the first bid (validBidRequests[0]) but still converts and submits the full validBidRequests array in one ORTB payload. In auctions that include both Taboola banner and native ad units, this sends one media type to the wrong host (display... or native...), which can drop bids for whichever type doesn’t match the chosen URL.

Useful? React with 👍 / 👎.

Expand All @@ -215,7 +231,9 @@ export const spec = {
context: { auctionId }
});
const {publisherId} = bidRequest.params;
const url = END_POINT_URL + '?publisher=' + publisherId;
const { mediaType } = getMediaType(bidRequest);
const baseUrl = mediaType === NATIVE ? NATIVE_ENDPOINT_URL : BANNER_ENDPOINT_URL;
const url = baseUrl + '?publisher=' + publisherId;

return {
url,
Expand Down Expand Up @@ -433,12 +451,16 @@ function fillTaboolaReqData(bidderRequest, bidRequest, data, context) {

function fillTaboolaImpData(bid, imp) {
const {tagId, position} = bid.params;
imp.banner = getBanners(bid, position);
imp.tagid = tagId;
const { mediaType, hasBanner } = getMediaType(bid);
if (hasBanner) {
imp.banner = getBanners(bid.mediaTypes.banner.sizes, position);
}

imp.tagid = tagId;
if (typeof bid.getFloor === 'function') {
const floorInfo = bid.getFloor({
currency: CURRENCY,
mediaType: mediaType,
size: '*'
});
if (isPlainObject(floorInfo) && floorInfo.currency === CURRENCY && !isNaN(parseFloat(floorInfo.floor))) {
Expand Down Expand Up @@ -476,9 +498,9 @@ function fillTaboolaImpData(bid, imp) {
}
}

function getBanners(bid, pos) {
function getBanners(sizes, pos) {
return {
...getSizes(bid.sizes),
...getSizes(sizes),
pos: pos
}
}
Expand All @@ -494,4 +516,14 @@ function getSizes(sizes) {
}
}

function getMediaType(bidRequest) {
const hasBanner = !!bidRequest?.mediaTypes?.banner?.sizes;
const hasNative = !!bidRequest?.mediaTypes?.native;
return {
hasBanner,
hasNative,
mediaType: hasNative && !hasBanner ? NATIVE : BANNER
};
}

registerBidder(spec);
201 changes: 193 additions & 8 deletions test/spec/modules/taboolaBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {expect} from 'chai';
import {spec, internal, END_POINT_URL, userData, EVENT_ENDPOINT, detectBot, getPageVisibility} from 'modules/taboolaBidAdapter.js';
import {spec, internal, BANNER_ENDPOINT_URL, userData, EVENT_ENDPOINT, detectBot, getPageVisibility} from 'modules/taboolaBidAdapter.js';
import {config} from '../../../src/config.js'
import * as utils from '../../../src/utils.js'
import {server} from '../../mocks/xhr.js'
Expand Down Expand Up @@ -33,7 +33,11 @@ describe('Taboola Adapter', function () {
})

const displayBidRequestParams = {
sizes: [[300, 250], [300, 600]]
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]]
}
}
}

const createBidRequest = () => ({
Expand Down Expand Up @@ -270,18 +274,18 @@ describe('Taboola Adapter', function () {
const expectedData = {
'imp': [{
'id': res.data.imp[0].id,
'secure': 1,
'banner': {
format: [{
w: displayBidRequestParams.sizes[0][0],
h: displayBidRequestParams.sizes[0][1]
w: displayBidRequestParams.mediaTypes.banner.sizes[0][0],
h: displayBidRequestParams.mediaTypes.banner.sizes[0][1]
},
{
w: displayBidRequestParams.sizes[1][0],
h: displayBidRequestParams.sizes[1][1]
w: displayBidRequestParams.mediaTypes.banner.sizes[1][0],
h: displayBidRequestParams.mediaTypes.banner.sizes[1][1]
}
]
},
'secure': 1,
'tagid': commonBidRequest.params.tagId,
'bidfloor': null,
'bidfloorcur': 'USD',
Expand Down Expand Up @@ -315,7 +319,7 @@ describe('Taboola Adapter', function () {
'ext': res.data.ext
};

expect(res.url).to.equal(`${END_POINT_URL}?publisher=${commonBidRequest.params.publisherId}`);
expect(res.url).to.equal(`${BANNER_ENDPOINT_URL}?publisher=${commonBidRequest.params.publisherId}`);
expect(JSON.stringify(res.data)).to.deep.equal(JSON.stringify(expectedData));
expect(res.data.ext.prebid.version).to.equal('$prebid.version$');
});
Expand Down Expand Up @@ -1980,4 +1984,185 @@ describe('Taboola Adapter', function () {
});
});
})

describe('native', function () {
const commonBidderRequest = {
bidderRequestId: 'mock-uuid',
refererInfo: {
page: 'https://example.com/ref',
ref: 'https://ref',
domain: 'example.com',
},
ortb2: {
device: {
ua: navigator.userAgent,
},
}
};

const nativeBidRequestParams = {
mediaTypes: {
native: {
title: {required: true, len: 150},
image: {required: true, sizes: [300, 250]},
sponsoredBy: {required: true}
}
}
};

describe('isBidRequestValid', function () {
it('should return true for valid native bid without sizes', function () {
const bid = {
bidder: 'taboola',
params: {
publisherId: 'publisherId',
tagId: 'native-placement'
},
...nativeBidRequestParams
};
expect(spec.isBidRequestValid(bid)).to.equal(true);
});

it('should return false for native bid without publisherId', function () {
const bid = {
bidder: 'taboola',
params: {
tagId: 'native-placement'
},
...nativeBidRequestParams
};
expect(spec.isBidRequestValid(bid)).to.equal(false);
});

it('should return false for native bid without tagId', function () {
const bid = {
bidder: 'taboola',
params: {
publisherId: 'publisherId'
},
...nativeBidRequestParams
};
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
});

describe('buildRequests', function () {
if (FEATURES.NATIVE) {
it('should build native request without banner imp', function () {
const nativeBidRequest = {
bidder: 'taboola',
params: {
publisherId: 'publisherId',
tagId: 'native-placement'
},
...nativeBidRequestParams,
nativeOrtbRequest: {
ver: '1.2',
assets: [
{id: 1, required: 1, title: {len: 150}},
{id: 2, required: 1, img: {type: 3, w: 300, h: 250}},
{id: 3, required: 1, data: {type: 1}}
]
},
bidId: utils.generateUUID(),
auctionId: utils.generateUUID(),
};

const res = spec.buildRequests([nativeBidRequest], commonBidderRequest);

expect(res.data.imp[0]).to.not.have.property('banner');
expect(res.data.imp[0]).to.have.property('native');
expect(res.data.imp[0].tagid).to.equal('native-placement');
});
}

it('should build banner request without native imp', function () {
const bannerBidRequest = {
bidder: 'taboola',
params: {
publisherId: 'publisherId',
tagId: 'banner-placement'
},
mediaTypes: {
banner: {
sizes: [[300, 250]]
}
},
bidId: utils.generateUUID(),
auctionId: utils.generateUUID(),
};

const res = spec.buildRequests([bannerBidRequest], commonBidderRequest);

expect(res.data.imp[0]).to.have.property('banner');
expect(res.data.imp[0]).to.not.have.property('native');
expect(res.data.imp[0]).to.not.have.property('native');
});
});

describe('interpretResponse', function () {
if (FEATURES.NATIVE) {
it('should interpret native response correctly', function () {
const nativeBidRequest = {
bidder: 'taboola',
params: {
publisherId: 'publisherId',
tagId: 'native-placement'
},
...nativeBidRequestParams,
nativeOrtbRequest: {
ver: '1.2',
assets: [
{id: 1, required: 1, title: {len: 150}},
{id: 2, required: 1, img: {type: 3, w: 300, h: 250}}
]
},
bidId: utils.generateUUID(),
auctionId: utils.generateUUID(),
};

const request = spec.buildRequests([nativeBidRequest], commonBidderRequest);

const nativeAdm = {
ver: '1.2',
assets: [
{id: 1, title: {text: 'Native Ad Title'}},
{id: 2, img: {url: 'https://example.com/image.jpg', w: 300, h: 250}}
],
link: {
url: 'https://example.com/click'
}
};

const serverResponse = {
body: {
id: 'response-id',
seatbid: [{
bid: [{
id: 'bid-id',
impid: request.data.imp[0].id,
price: 1.5,
adm: JSON.stringify(nativeAdm),
adomain: ['example.com'],
crid: 'creative-id',
exp: 300,
nurl: 'https://example.com/win'
}],
seat: 'taboola'
}],
cur: 'USD'
}
};

const res = spec.interpretResponse(serverResponse, request);

expect(res).to.be.an('array').with.lengthOf(1);
expect(res[0].mediaType).to.equal('native');
expect(res[0].native).to.exist;
expect(res[0].native.ortb).to.deep.equal(nativeAdm);
expect(res[0]).to.not.have.property('ad');
});
}
});
});
})
Loading