prebid.js 7.13.0 → 7.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/dist/33acrossBidAdapter.js +1 -1
  2. package/dist/adagioBidAdapter.js +1 -1
  3. package/dist/adbookpspBidAdapter.js +1 -1
  4. package/dist/adgenerationBidAdapter.js +1 -1
  5. package/dist/adrelevantisBidAdapter.js +1 -1
  6. package/dist/adrinoBidAdapter.js +1 -1
  7. package/dist/adtelligentBidAdapter.js +1 -1
  8. package/dist/adtrgtmeBidAdapter.js +1 -1
  9. package/dist/adxcgBidAdapter.js +1 -1
  10. package/dist/ajaBidAdapter.js +1 -1
  11. package/dist/amxBidAdapter.js +1 -1
  12. package/dist/amxIdSystem.js +1 -1
  13. package/dist/appierAnalyticsAdapter.js +1 -1
  14. package/dist/appnexusBidAdapter.js +1 -1
  15. package/dist/asoBidAdapter.js +1 -1
  16. package/dist/axonixBidAdapter.js +1 -1
  17. package/dist/bidglassBidAdapter.js +1 -1
  18. package/dist/bidwatchAnalyticsAdapter.js +1 -1
  19. package/dist/big-richmediaBidAdapter.js +1 -1
  20. package/dist/bridgewellBidAdapter.js +1 -1
  21. package/dist/brightMountainMediaBidAdapter.js +1 -1
  22. package/dist/concertBidAdapter.js +1 -1
  23. package/dist/connectadBidAdapter.js +1 -1
  24. package/dist/consumableBidAdapter.js +1 -1
  25. package/dist/conversantBidAdapter.js +1 -1
  26. package/dist/craftBidAdapter.js +1 -1
  27. package/dist/criteoBidAdapter.js +1 -1
  28. package/dist/discoveryBidAdapter.js +1 -0
  29. package/dist/dspxBidAdapter.js +1 -1
  30. package/dist/eplanningBidAdapter.js +1 -1
  31. package/dist/finativeBidAdapter.js +1 -1
  32. package/dist/fledgeForGpt.js +1 -0
  33. package/dist/glimpseBidAdapter.js +1 -1
  34. package/dist/gmosspBidAdapter.js +1 -1
  35. package/dist/goldbachBidAdapter.js +1 -1
  36. package/dist/gridBidAdapter.js +1 -1
  37. package/dist/gridNMBidAdapter.js +1 -1
  38. package/dist/gumgumBidAdapter.js +1 -1
  39. package/dist/h12mediaBidAdapter.js +1 -1
  40. package/dist/id5IdSystem.js +1 -1
  41. package/dist/improvedigitalBidAdapter.js +1 -1
  42. package/dist/inmarBidAdapter.js +1 -1
  43. package/dist/insticatorBidAdapter.js +1 -1
  44. package/dist/invibesBidAdapter.js +1 -1
  45. package/dist/ixBidAdapter.js +1 -1
  46. package/dist/justpremiumBidAdapter.js +1 -1
  47. package/dist/kargoBidAdapter.js +1 -1
  48. package/dist/konduitAnalyticsAdapter.js +1 -1
  49. package/dist/kueezBidAdapter.js +1 -1
  50. package/dist/lassoBidAdapter.js +1 -1
  51. package/dist/lifestreetBidAdapter.js +1 -1
  52. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  53. package/dist/logicadBidAdapter.js +1 -1
  54. package/dist/loglyliftBidAdapter.js +1 -1
  55. package/dist/malltvAnalyticsAdapter.js +1 -1
  56. package/dist/marsmediaBidAdapter.js +1 -1
  57. package/dist/mediafuseBidAdapter.js +1 -1
  58. package/dist/mediasquareBidAdapter.js +1 -1
  59. package/dist/mgidBidAdapter.js +1 -1
  60. package/dist/minutemediaBidAdapter.js +1 -1
  61. package/dist/not-for-prod/prebid.js +117 -114
  62. package/dist/oguryBidAdapter.js +1 -1
  63. package/dist/onetagBidAdapter.js +1 -1
  64. package/dist/ooloAnalyticsAdapter.js +1 -1
  65. package/dist/openxOrtbBidAdapter.js +1 -1
  66. package/dist/outbrainBidAdapter.js +1 -1
  67. package/dist/parrableIdSystem.js +1 -1
  68. package/dist/pixfutureBidAdapter.js +1 -1
  69. package/dist/prebid-core.js +1 -1
  70. package/dist/publinkIdSystem.js +1 -1
  71. package/dist/pubmaticBidAdapter.js +1 -1
  72. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  73. package/dist/pxyzBidAdapter.js +1 -1
  74. package/dist/quantcastBidAdapter.js +1 -1
  75. package/dist/readpeakBidAdapter.js +1 -1
  76. package/dist/relaidoBidAdapter.js +1 -1
  77. package/dist/rhythmoneBidAdapter.js +1 -1
  78. package/dist/riseBidAdapter.js +1 -1
  79. package/dist/rubiconAnalyticsAdapter.js +1 -1
  80. package/dist/rubiconBidAdapter.js +1 -1
  81. package/dist/seedingAllianceBidAdapter.js +1 -1
  82. package/dist/seedtagBidAdapter.js +1 -1
  83. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  84. package/dist/sharethroughBidAdapter.js +1 -1
  85. package/dist/shinezBidAdapter.js +1 -1
  86. package/dist/smaatoBidAdapter.js +1 -1
  87. package/dist/smartadserverBidAdapter.js +1 -1
  88. package/dist/smartxBidAdapter.js +1 -1
  89. package/dist/smilewantedBidAdapter.js +1 -1
  90. package/dist/sonobiBidAdapter.js +1 -1
  91. package/dist/sovrnAnalyticsAdapter.js +1 -1
  92. package/dist/sovrnBidAdapter.js +1 -1
  93. package/dist/spotxBidAdapter.js +1 -1
  94. package/dist/sspBCBidAdapter.js +1 -1
  95. package/dist/sublimeBidAdapter.js +1 -1
  96. package/dist/synacormediaBidAdapter.js +1 -1
  97. package/dist/taboolaBidAdapter.js +1 -1
  98. package/dist/targetVideoBidAdapter.js +1 -1
  99. package/dist/teadsBidAdapter.js +1 -1
  100. package/dist/trionBidAdapter.js +1 -1
  101. package/dist/tripleliftBidAdapter.js +1 -1
  102. package/dist/ttdBidAdapter.js +1 -1
  103. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  104. package/dist/underdogmediaBidAdapter.js +1 -1
  105. package/dist/undertoneBidAdapter.js +1 -1
  106. package/dist/vidazooBidAdapter.js +1 -1
  107. package/dist/videobyteBidAdapter.js +1 -1
  108. package/dist/visxBidAdapter.js +1 -1
  109. package/dist/vuukleBidAdapter.js +1 -1
  110. package/dist/widespaceBidAdapter.js +1 -1
  111. package/dist/winrBidAdapter.js +1 -1
  112. package/dist/xeBidAdapter.js +1 -0
  113. package/dist/yahoosspBidAdapter.js +1 -1
  114. package/dist/yieldlabBidAdapter.js +1 -1
  115. package/dist/yieldmoBidAdapter.js +1 -1
  116. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  117. package/modules/adrinoBidAdapter.js +1 -1
  118. package/modules/adtelligentBidAdapter.js +1 -1
  119. package/modules/bidwatchAnalyticsAdapter.js +10 -2
  120. package/modules/discoveryBidAdapter.js +467 -0
  121. package/modules/discoveryBidAdapter.md +60 -0
  122. package/modules/fledgeForGpt.js +52 -0
  123. package/modules/fledgeForGpt.md +60 -0
  124. package/modules/invibesBidAdapter.js +22 -11
  125. package/modules/kargoBidAdapter.js +7 -0
  126. package/modules/onetagBidAdapter.js +2 -3
  127. package/modules/openxOrtbBidAdapter.js +28 -2
  128. package/modules/outbrainBidAdapter.js +6 -3
  129. package/modules/spotxBidAdapter.js +10 -26
  130. package/modules/taboolaBidAdapter.js +2 -2
  131. package/modules/taboolaBidAdapter.md +10 -8
  132. package/modules/xeBidAdapter.js +206 -0
  133. package/modules/xeBidAdapter.md +54 -0
  134. package/modules/yieldlabBidAdapter.js +34 -3
  135. package/modules/yieldmoBidAdapter.js +16 -1
  136. package/package.json +2 -2
  137. package/src/adapterManager.js +8 -0
  138. package/src/adapters/bidderFactory.js +34 -4
  139. package/src/debugging.js +14 -6
  140. package/src/refererDetection.js +1 -12
  141. package/src/utils.js +10 -2
  142. package/test/spec/modules/adrinoBidAdapter_spec.js +10 -0
  143. package/test/spec/modules/bidwatchAnalyticsAdapter_spec.js +2 -0
  144. package/test/spec/modules/discoveryBidAdapter_spec.js +92 -0
  145. package/test/spec/modules/enrichmentFpdModule_spec.js +1 -2
  146. package/test/spec/modules/fledge_spec.js +37 -0
  147. package/test/spec/modules/fpdModule_spec.js +1 -2
  148. package/test/spec/modules/invibesBidAdapter_spec.js +31 -2
  149. package/test/spec/modules/openxOrtbBidAdapter_spec.js +132 -18
  150. package/test/spec/modules/outbrainBidAdapter_spec.js +21 -0
  151. package/test/spec/modules/spotxBidAdapter_spec.js +30 -8
  152. package/test/spec/modules/taboolaBidAdapter_spec.js +77 -0
  153. package/test/spec/modules/xeBidAdapter_spec.js +450 -0
  154. package/test/spec/modules/yieldlabBidAdapter_spec.js +37 -0
  155. package/test/spec/modules/yieldmoBidAdapter_spec.js +43 -3
  156. package/test/spec/unit/core/adapterManager_spec.js +58 -0
  157. package/test/spec/unit/core/bidderFactory_spec.js +64 -0
@@ -9,11 +9,12 @@ const CONSTANTS = {
9
9
  SYNC_ENDPOINT: 'https://k.r66net.com/GetUserSync',
10
10
  TIME_TO_LIVE: 300,
11
11
  DEFAULT_CURRENCY: 'EUR',
12
- PREBID_VERSION: 8,
12
+ PREBID_VERSION: 9,
13
13
  METHOD: 'GET',
14
14
  INVIBES_VENDOR_ID: 436,
15
15
  USERID_PROVIDERS: ['pubcid', 'pubProvidedId', 'uid2', 'zeotapIdPlus', 'id5id'],
16
- META_TAXONOMY: ['networkId', 'networkName', 'agencyId', 'agencyName', 'advertiserId', 'advertiserName', 'advertiserDomains', 'brandId', 'brandName', 'primaryCatId', 'secondaryCatIds', 'mediaType']
16
+ META_TAXONOMY: ['networkId', 'networkName', 'agencyId', 'agencyName', 'advertiserId', 'advertiserName', 'advertiserDomains', 'brandId', 'brandName', 'primaryCatId', 'secondaryCatIds', 'mediaType'],
17
+ DISABLE_USER_SYNC: true
17
18
  };
18
19
 
19
20
  const storage = getStorageManager({gvlid: CONSTANTS.INVIBES_VENDOR_ID, bidderCode: CONSTANTS.BIDDER_CODE});
@@ -40,15 +41,7 @@ export const spec = {
40
41
  interpretResponse: function (responseObj, requestParams) {
41
42
  return handleResponse(responseObj, requestParams != null ? requestParams.bidRequests : null);
42
43
  },
43
- getUserSyncs: function (syncOptions) {
44
- if (syncOptions.iframeEnabled) {
45
- const syncUrl = buildSyncUrl();
46
- return {
47
- type: 'iframe',
48
- url: syncUrl
49
- };
50
- }
51
- }
44
+ getUserSyncs: getUserSync,
52
45
  };
53
46
 
54
47
  registerBidder(spec);
@@ -60,7 +53,9 @@ invibes.purposes = invibes.purposes || [false, false, false, false, false, false
60
53
  invibes.legitimateInterests = invibes.legitimateInterests || [false, false, false, false, false, false, false, false, false, false];
61
54
  invibes.placementBids = invibes.placementBids || [];
62
55
  invibes.pushedCids = invibes.pushedCids || {};
56
+ let preventPageViewEvent = false;
63
57
  let _customUserSync;
58
+ let _disableUserSyncs;
64
59
 
65
60
  function isBidRequestValid(bid) {
66
61
  if (typeof bid.params !== 'object') {
@@ -75,6 +70,18 @@ function isBidRequestValid(bid) {
75
70
  return true;
76
71
  }
77
72
 
73
+ function getUserSync(syncOptions) {
74
+ if (syncOptions.iframeEnabled) {
75
+ if (!(_disableUserSyncs == null || _disableUserSyncs == undefined ? CONSTANTS.DISABLE_USER_SYNC : _disableUserSyncs)) {
76
+ const syncUrl = buildSyncUrl();
77
+ return {
78
+ type: 'iframe',
79
+ url: syncUrl
80
+ };
81
+ }
82
+ }
83
+ }
84
+
78
85
  function buildRequest(bidRequests, bidderRequest) {
79
86
  bidderRequest = bidderRequest || {};
80
87
  const _placementIds = [];
@@ -89,6 +96,7 @@ function buildRequest(bidRequests, bidderRequest) {
89
96
  _domainId = _domainId || bidRequest.params.domainId;
90
97
  _customEndpoint = _customEndpoint || bidRequest.params.customEndpoint;
91
98
  _customUserSync = _customUserSync || bidRequest.params.customUserSync;
99
+ _disableUserSyncs = bidRequest?.params?.disableUserSyncs;
92
100
  _userId = _userId || bidRequest.userId;
93
101
  });
94
102
 
@@ -129,6 +137,7 @@ function buildRequest(bidRequests, bidderRequest) {
129
137
 
130
138
  tc: invibes.gdpr_consent,
131
139
  isLocalStorageEnabled: storage.hasLocalStorage(),
140
+ preventPageViewEvent: preventPageViewEvent,
132
141
  };
133
142
 
134
143
  let lid = readFromLocalStorage('ivbsdid');
@@ -158,6 +167,8 @@ function buildRequest(bidRequests, bidderRequest) {
158
167
 
159
168
  let endpoint = createEndpoint(_customEndpoint, _domainId, _placementIds);
160
169
 
170
+ preventPageViewEvent = true;
171
+
161
172
  return {
162
173
  method: CONSTANTS.METHOD,
163
174
  url: endpoint,
@@ -61,6 +61,13 @@ export const spec = {
61
61
  },
62
62
  prebidRawBidRequests: validBidRequests
63
63
  }, spec._getAllMetadata(bidderRequest, tdid));
64
+
65
+ // Pull Social Canvas segments and embed URL
66
+ if (validBidRequests.length > 0 && validBidRequests[0].params.socialCanvas) {
67
+ transformedParams.socialCanvasSegments = validBidRequests[0].params.socialCanvas.segments;
68
+ transformedParams.socialEmbedURL = validBidRequests[0].params.socialCanvas.embedURL;
69
+ }
70
+
64
71
  const encodedParams = encodeURIComponent(JSON.stringify(transformedParams));
65
72
  return Object.assign({}, bidderRequest, {
66
73
  method: 'GET',
@@ -6,7 +6,6 @@ import { Renderer } from '../src/Renderer.js';
6
6
  import {find} from '../src/polyfill.js';
7
7
  import { getStorageManager } from '../src/storageManager.js';
8
8
  import { registerBidder } from '../src/adapters/bidderFactory.js';
9
- import { createEidsArray } from './userId/eids.js';
10
9
  import { deepClone, logError, deepAccess } from '../src/utils.js';
11
10
 
12
11
  const ENDPOINT = 'https://onetag-sys.com/prebid-request';
@@ -65,8 +64,8 @@ function buildRequests(validBidRequests, bidderRequest) {
65
64
  if (bidderRequest && bidderRequest.uspConsent) {
66
65
  payload.usPrivacy = bidderRequest.uspConsent;
67
66
  }
68
- if (validBidRequests && validBidRequests.length !== 0 && validBidRequests[0].userId) {
69
- payload.userId = createEidsArray(validBidRequests[0].userId);
67
+ if (validBidRequests && validBidRequests.length !== 0 && validBidRequests[0].userIdAsEids) {
68
+ payload.userId = validBidRequests[0].userIdAsEids;
70
69
  }
71
70
  if (validBidRequests && validBidRequests.length !== 0 && validBidRequests[0].schain && isSchainValid(validBidRequests[0].schain)) {
72
71
  payload.schain = validBidRequests[0].schain;
@@ -67,12 +67,17 @@ function createBannerRequest(bids, bidderRequest) {
67
67
  },
68
68
  ext: {divid: bid.adUnitCode}
69
69
  };
70
+
71
+ if (bidderRequest.fledgeEnabled) {
72
+ imp.ext.ae = bid?.ortb2Imp?.ext?.ae
73
+ }
74
+
70
75
  enrichImp(imp, bid, floor);
71
76
  return imp;
72
77
  });
73
78
  return {
74
79
  method: 'POST',
75
- url: REQUEST_URL,
80
+ url: config.getConfig('openxOrtbUrl') || REQUEST_URL,
76
81
  data: data
77
82
  }
78
83
  }
@@ -190,6 +195,9 @@ function getBaseRequest(bid, bidderRequest) {
190
195
  if (bid.params.delDomain) {
191
196
  utils.deepSetValue(req, 'ext.delDomain', bid.params.delDomain);
192
197
  }
198
+ if (bid.params.response_template_name) {
199
+ utils.deepSetValue(req, 'ext.response_template_name', bid.params.response_template_name);
200
+ }
193
201
  if (bid.params.test) {
194
202
  req.test = 1;
195
203
  }
@@ -251,7 +259,7 @@ function getFloor(bid, mediaType) {
251
259
  return floor;
252
260
  }
253
261
 
254
- function interpretResponse(resp, req) {
262
+ function interpretOrtbResponse(resp, req) {
255
263
  if (!resp.body) {
256
264
  resp.body = {nbr: 0};
257
265
  }
@@ -316,6 +324,24 @@ function interpretResponse(resp, req) {
316
324
  return bids;
317
325
  }
318
326
 
327
+ function interpretResponse(resp, req) {
328
+ const bids = interpretOrtbResponse(resp, req);
329
+ let fledgeAuctionConfigs = utils.deepAccess(resp, 'body.ext.fledge_auction_configs');
330
+ if (fledgeAuctionConfigs) {
331
+ fledgeAuctionConfigs = Object.entries(fledgeAuctionConfigs).map(([bidId, cfg]) => {
332
+ return Object.assign({
333
+ bidId,
334
+ auctionSignals: {}
335
+ }, cfg);
336
+ });
337
+ return {
338
+ bids,
339
+ fledgeAuctionConfigs,
340
+ }
341
+ }
342
+ return bids;
343
+ }
344
+
319
345
  /**
320
346
  * @param syncOptions
321
347
  * @param responses
@@ -56,13 +56,15 @@ export const spec = {
56
56
  buildRequests: (validBidRequests, bidderRequest) => {
57
57
  // convert Native ORTB definition to old-style prebid native definition
58
58
  validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests);
59
+ const ortb2 = bidderRequest.ortb2 || {};
59
60
  const page = bidderRequest.refererInfo.page;
60
61
  const ua = navigator.userAgent;
61
62
  const test = setOnAny(validBidRequests, 'params.test');
62
63
  const publisher = setOnAny(validBidRequests, 'params.publisher');
63
- const bcat = setOnAny(validBidRequests, 'params.bcat');
64
- const badv = setOnAny(validBidRequests, 'params.badv');
65
- const eids = setOnAny(validBidRequests, 'userIdAsEids')
64
+ const bcat = ortb2.bcat || setOnAny(validBidRequests, 'params.bcat');
65
+ const badv = ortb2.badv || setOnAny(validBidRequests, 'params.badv');
66
+ const eids = setOnAny(validBidRequests, 'userIdAsEids');
67
+ const wlang = ortb2.wlang;
66
68
  const cur = CURRENCY;
67
69
  const endpointUrl = config.getConfig('outbrain.bidderUrl');
68
70
  const timeout = bidderRequest.timeout;
@@ -109,6 +111,7 @@ export const spec = {
109
111
  imp: imps,
110
112
  bcat: bcat,
111
113
  badv: badv,
114
+ wlang: wlang,
112
115
  ext: {
113
116
  prebid: {
114
117
  channel: {
@@ -257,18 +257,17 @@ export const spec = {
257
257
  deepSetValue(requestPayload, 'regs.ext.us_privacy', bidderRequest.uspConsent);
258
258
  }
259
259
 
260
- // ID5 fied
261
- if (deepAccess(bid, 'userId.id5id.uid')) {
262
- userExt.eids = userExt.eids || [];
263
- userExt.eids.push(
264
- {
265
- source: 'id5-sync.com',
266
- uids: [{
267
- id: bid.userId.id5id.uid,
268
- ext: bid.userId.id5id.ext || {}
269
- }]
260
+ if (bid.userIdAsEids) {
261
+ userExt.eids = bid.userIdAsEids;
262
+
263
+ userExt.eids.forEach(eid => {
264
+ if (eid.source === 'uidapi.com') {
265
+ eid.uids.forEach(uid => {
266
+ uid.ext = uid.ext || {};
267
+ uid.ext.rtiPartner = 'UID2'
268
+ });
270
269
  }
271
- );
270
+ });
272
271
  }
273
272
 
274
273
  // Add common id if available
@@ -285,21 +284,6 @@ export const spec = {
285
284
  };
286
285
  }
287
286
 
288
- if (bid && bid.userId && bid.userId.tdid) {
289
- userExt.eids = userExt.eids || [];
290
- userExt.eids.push(
291
- {
292
- source: 'adserver.org',
293
- uids: [{
294
- id: bid.userId.tdid,
295
- ext: {
296
- rtiPartner: 'TDID'
297
- }
298
- }]
299
- }
300
- );
301
- }
302
-
303
287
  // Only add the user object if it's not empty
304
288
  if (!isEmpty(userExt)) {
305
289
  requestPayload.user = { ext: userExt };
@@ -84,7 +84,7 @@ export const spec = {
84
84
  buildRequests: (validBidRequests, bidderRequest) => {
85
85
  const [bidRequest] = validBidRequests;
86
86
  const {refererInfo, gdprConsent = {}, uspConsent} = bidderRequest;
87
- const {publisherId} = bidRequest.params;
87
+ const {publisherId, endpointUrl} = bidRequest.params;
88
88
  const site = getSiteProperties(bidRequest.params, refererInfo);
89
89
  const device = {ua: navigator.userAgent};
90
90
  const imps = getImps(validBidRequests);
@@ -128,7 +128,7 @@ export const spec = {
128
128
  regs
129
129
  };
130
130
 
131
- const url = [END_POINT_URL, publisherId].join('/');
131
+ const url = [endpointUrl || END_POINT_URL, publisherId].join('/');
132
132
 
133
133
  return {
134
134
  url,
@@ -30,7 +30,8 @@ The Taboola Bidding adapter requires setup before beginning. Please contact us o
30
30
  publisherId: 'tester-pub', // your-publisher-id
31
31
  bidfloor: 0.25, // Optional - default is null
32
32
  bcat: ['IAB1-1'], // Optional - default is []
33
- badv: ['example.com'] // Optional - default is []
33
+ badv: ['example.com'], // Optional - default is []
34
+ endpointUrl: ['https://example.com'] // Optional
34
35
  }
35
36
  }]
36
37
  }];
@@ -38,12 +39,13 @@ The Taboola Bidding adapter requires setup before beginning. Please contact us o
38
39
 
39
40
  # Parameters
40
41
 
41
- | Name | Scope | Description | Example | Type |
42
- |----------------|----------|---------------------------------------------------------|----------------------------|--------------|
43
- | `tagId` | required | Tag ID / Placement Name <br> | `'Below The Article'` | `String` |
44
- | `publisherId` | required | Numeric Publisher ID <br>(as provided by Taboola) | `'1234567'` | `String` |
45
- | `bcat` | optional | List of blocked advertiser categories (IAB) | `['IAB1-1']` | `Array` |
46
- | `badv` | optional | Blocked Advertiser Domains | `'example.com'` | `String Url` |
47
- | `bidfloor` | optional | CPM bid floor | `0.25` | `Float` |
42
+ | Name | Scope | Description | Example | Type |
43
+ |---------------|----------|---------------------------------------------------------|----------------------------|--------------|
44
+ | `tagId` | required | Tag ID / Placement Name <br> | `'Below The Article'` | `String` |
45
+ | `publisherId` | required | Numeric Publisher ID <br>(as provided by Taboola) | `'1234567'` | `String` |
46
+ | `bcat` | optional | List of blocked advertiser categories (IAB) | `['IAB1-1']` | `Array` |
47
+ | `badv` | optional | Blocked Advertiser Domains | `'example.com'` | `String Url` |
48
+ | `bidfloor` | optional | CPM bid floor | `0.25` | `Float` |
49
+ | `endpointUrl` | optional | Endpoint Url (only if provided by Taboola) | `https://example.com` | `String` |
48
50
 
49
51
 
@@ -0,0 +1,206 @@
1
+ import { config } from '../src/config.js';
2
+ import { BANNER, VIDEO } from '../src/mediaTypes.js';
3
+ import { registerBidder } from '../src/adapters/bidderFactory.js';
4
+ import { getAdUnitSizes, parseSizesInput, isFn, deepAccess, getBidIdParameter, logError, isArray } from '../src/utils.js';
5
+
6
+ const CUR = 'USD';
7
+ const BIDDER_CODE = 'xe';
8
+ const ENDPOINT = 'https://pbjs.xe.works/bid';
9
+
10
+ /**
11
+ * Determines whether or not the given bid request is valid.
12
+ *
13
+ * @param {BidRequest} bid The bid params to validate.
14
+ * @return boolean True if this is a valid bid, and false otherwise.
15
+ */
16
+ function isBidRequestValid(req) {
17
+ if (req && typeof req.params !== 'object') {
18
+ logError('Params is not defined or is incorrect in the bidder settings');
19
+ return false;
20
+ }
21
+
22
+ if (!getBidIdParameter('env', req.params) || !getBidIdParameter('placement', req.params)) {
23
+ logError('Env or placement is not present in bidder params');
24
+ return false;
25
+ }
26
+
27
+ if (deepAccess(req, 'mediaTypes.video') && !isArray(deepAccess(req, 'mediaTypes.video.playerSize'))) {
28
+ logError('mediaTypes.video.playerSize is required for video');
29
+ return false;
30
+ }
31
+
32
+ return true;
33
+ }
34
+
35
+ /**
36
+ * Make a server request from the list of BidRequests.
37
+ *
38
+ * @param {validBidRequest?pbjs_debug=trues[]} - an array of bids
39
+ * @return ServerRequest Info describing the request to the server.
40
+ */
41
+ function buildRequests(validBidRequests, bidderRequest) {
42
+ const { refererInfo = {}, gdprConsent = {}, uspConsent } = bidderRequest;
43
+ const requests = validBidRequests.map(req => {
44
+ const request = {};
45
+ request.bidId = req.bidId;
46
+ request.banner = deepAccess(req, 'mediaTypes.banner');
47
+ request.auctionId = req.auctionId;
48
+ request.transactionId = req.transactionId;
49
+ request.sizes = parseSizesInput(getAdUnitSizes(req));
50
+ request.schain = req.schain;
51
+ request.location = {
52
+ page: refererInfo.page,
53
+ location: refererInfo.location,
54
+ domain: refererInfo.domain,
55
+ whost: window.location.host,
56
+ ref: refererInfo.ref,
57
+ isAmp: refererInfo.isAmp
58
+ };
59
+ request.device = {
60
+ ua: navigator.userAgent,
61
+ lang: navigator.language
62
+ };
63
+ request.env = {
64
+ env: req.params.env,
65
+ placement: req.params.placement
66
+ };
67
+ request.ortb2 = req.ortb2;
68
+ request.ortb2Imp = req.ortb2Imp;
69
+ request.tz = new Date().getTimezoneOffset();
70
+ request.ext = req.params.ext;
71
+ request.bc = req.bidRequestsCount;
72
+ request.floor = getBidFloor(req);
73
+
74
+ if (req.userIdAsEids && req.userIdAsEids.length !== 0) {
75
+ request.userEids = req.userIdAsEids;
76
+ } else {
77
+ request.userEids = [];
78
+ }
79
+ if (gdprConsent.gdprApplies) {
80
+ request.gdprApplies = Number(gdprConsent.gdprApplies);
81
+ request.consentString = gdprConsent.consentString;
82
+ } else {
83
+ request.gdprApplies = 0;
84
+ request.consentString = '';
85
+ }
86
+ if (uspConsent) {
87
+ request.usPrivacy = uspConsent;
88
+ } else {
89
+ request.usPrivacy = '';
90
+ }
91
+ if (config.getConfig('coppa')) {
92
+ request.coppa = 1;
93
+ } else {
94
+ request.coppa = 0;
95
+ }
96
+
97
+ const video = deepAccess(req, 'mediaTypes.video');
98
+ if (video) {
99
+ request.sizes = parseSizesInput(deepAccess(req, 'mediaTypes.video.playerSize'));
100
+ request.video = video;
101
+ }
102
+
103
+ return request;
104
+ });
105
+
106
+ return {
107
+ method: 'POST',
108
+ url: ENDPOINT,
109
+ data: JSON.stringify(requests),
110
+ withCredentials: true,
111
+ bidderRequest,
112
+ options: {
113
+ contentType: 'application/json'
114
+ }
115
+ };
116
+ }
117
+
118
+ /**
119
+ * Unpack the response from the server into a list of bids.
120
+ *
121
+ * @param {ServerResponse} serverResponse A successful response from the server.
122
+ * @return {Bid[]} An array of bids which were nested inside the server.
123
+ */
124
+ function interpretResponse(serverResponse, { bidderRequest }) {
125
+ const response = [];
126
+ if (!isArray(deepAccess(serverResponse, 'body.data'))) {
127
+ return response;
128
+ }
129
+
130
+ serverResponse.body.data.forEach(serverBid => {
131
+ const bid = {
132
+ requestId: bidderRequest.bidId,
133
+ dealId: bidderRequest.dealId || null,
134
+ ...serverBid
135
+ };
136
+ response.push(bid);
137
+ });
138
+
139
+ return response;
140
+ }
141
+
142
+ /**
143
+ * Register the user sync pixels which should be dropped after the auction.
144
+ *
145
+ * @param {SyncOptions} syncOptions Which user syncs are allowed?
146
+ * @param {ServerResponse[]} serverResponses List of server's responses.
147
+ * @return {UserSync[]} The user syncs which should be dropped.
148
+ */
149
+ function getUserSyncs(syncOptions, serverResponses, gdprConsent = {}, uspConsent = '') {
150
+ const syncs = [];
151
+ const pixels = deepAccess(serverResponses, '0.body.data.0.ext.pixels');
152
+
153
+ if ((syncOptions.iframeEnabled || syncOptions.pixelEnabled) && isArray(pixels) && pixels.length !== 0) {
154
+ const gdprFlag = `&gdpr=${gdprConsent.gdprApplies ? 1 : 0}`;
155
+ const gdprString = `&gdpr_consent=${encodeURIComponent((gdprConsent.consentString || ''))}`;
156
+ const usPrivacy = `us_privacy=${encodeURIComponent(uspConsent)}`;
157
+
158
+ pixels.forEach(pixel => {
159
+ const [ type, url ] = pixel;
160
+ const sync = { type, url: `${url}&${usPrivacy}${gdprFlag}${gdprString}` };
161
+ if (type === 'iframe' && syncOptions.iframeEnabled) {
162
+ syncs.push(sync)
163
+ } else if (type === 'image' && syncOptions.pixelEnabled) {
164
+ syncs.push(sync)
165
+ }
166
+ });
167
+ }
168
+
169
+ return syncs;
170
+ }
171
+
172
+ /**
173
+ * Get valid floor value from getFloor fuction.
174
+ *
175
+ * @param {Object} bid Current bid request.
176
+ * @return {null|Number} Returns floor value when bid.getFloor is function and returns valid floor object with USD currency, otherwise returns null.
177
+ */
178
+ export function getBidFloor(bid) {
179
+ if (!isFn(bid.getFloor)) {
180
+ return null;
181
+ }
182
+
183
+ let floor = bid.getFloor({
184
+ currency: CUR,
185
+ mediaType: '*',
186
+ size: '*'
187
+ });
188
+
189
+ if (typeof floor === 'object' && !isNaN(floor.floor) && floor.currency === CUR) {
190
+ return floor.floor;
191
+ }
192
+
193
+ return null;
194
+ }
195
+
196
+ export const spec = {
197
+ code: BIDDER_CODE,
198
+ aliases: [ 'xeworks', 'lunamediax' ],
199
+ supportedMediaTypes: [ BANNER, VIDEO ],
200
+ isBidRequestValid,
201
+ buildRequests,
202
+ interpretResponse,
203
+ getUserSyncs
204
+ }
205
+
206
+ registerBidder(spec);
@@ -0,0 +1,54 @@
1
+ # Overview
2
+
3
+ ```
4
+ Module Name: xe Bidder Adapter
5
+ Module Type: xe Bidder Adapter
6
+ Maintainer: dima@xe.works
7
+ ```
8
+
9
+ # Description
10
+
11
+ Module that connects to xe.works demand sources
12
+
13
+ # Test Parameters
14
+ ```
15
+ var adUnits = [
16
+ {
17
+ code: 'test-banner',
18
+ mediaTypes: {
19
+ banner: {
20
+ sizes: [[300, 250]],
21
+ }
22
+ },
23
+ bids: [
24
+ {
25
+ bidder: 'xe',
26
+ params: {
27
+ env: 'xe',
28
+ placement: 'test-banner',
29
+ ext: {}
30
+ }
31
+ }
32
+ ]
33
+ },
34
+ {
35
+ code: 'test-video',
36
+ sizes: [ [ 640, 480 ] ],
37
+ mediaTypes: {
38
+ video: {
39
+ playerSize: [640, 480],
40
+ context: 'instream',
41
+ skipppable: true
42
+ }
43
+ },
44
+ bids: [{
45
+ bidder: 'xe',
46
+ params: {
47
+ env: 'xe',
48
+ placement: 'test-video',
49
+ ext: {}
50
+ }
51
+ }]
52
+ }
53
+ ];
54
+ ```
@@ -1,4 +1,4 @@
1
- import { _each, deepAccess, isArray, isPlainObject, timestamp } from '../src/utils.js'
1
+ import { _each, deepAccess, isArray, isFn, isPlainObject, timestamp } from '../src/utils.js'
2
2
  import { registerBidder } from '../src/adapters/bidderFactory.js'
3
3
  import { find } from '../src/polyfill.js'
4
4
  import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'
@@ -75,6 +75,10 @@ export const spec = {
75
75
  if (iabContent) {
76
76
  query.iab_content = createIabContentString(iabContent)
77
77
  }
78
+ const floor = getBidFloor(bid, sizes)
79
+ if (floor) {
80
+ query.floor = floor;
81
+ }
78
82
  })
79
83
 
80
84
  if (bidderRequest) {
@@ -177,7 +181,7 @@ export const spec = {
177
181
  bidResponse.adUrl = url
178
182
  bidResponse.mediaType = NATIVE
179
183
  const nativeImageAssetObj = find(matchedBid.native.assets, e => e.id === 2)
180
- const nativeImageAsset = nativeImageAssetObj ? nativeImageAssetObj.img : {url: '', w: 0, h: 0};
184
+ const nativeImageAsset = nativeImageAssetObj ? nativeImageAssetObj.img : { url: '', w: 0, h: 0 };
181
185
  const nativeTitleAsset = find(matchedBid.native.assets, e => e.id === 1)
182
186
  const nativeBodyAsset = find(matchedBid.native.assets, e => e.id === 3)
183
187
  bidResponse.native = {
@@ -405,6 +409,7 @@ function outstreamRender(bid) {
405
409
  window.document.dispatchEvent(new Event('ma-start-event'))
406
410
  });
407
411
  }
412
+
408
413
  /**
409
414
  * Extract sizes for a given bid from either `mediaTypes` or `sizes` directly.
410
415
  *
@@ -426,7 +431,7 @@ function extractSizes(bid) {
426
431
  sizes.push([bannerType.sizes])
427
432
  }
428
433
  }
429
- // The bid top level field `sizes` is deprecated and should not be used anymore. Keeping it for compatibility.
434
+ // The bid top level field `sizes` is deprecated and should not be used anymore. Keeping it for compatibility.
430
435
  } else if (isArray(bid.sizes)) {
431
436
  if (isArray(bid.sizes[0])) {
432
437
  sizes.push(bid.sizes)
@@ -441,4 +446,30 @@ function extractSizes(bid) {
441
446
  return Array.from(deduplicatedSizeStrings)
442
447
  }
443
448
 
449
+ /**
450
+ * Gets the floor price if the Price Floors Module is enabled for a given auction,
451
+ * which will add the getFloor() function to the bidRequest object.
452
+ *
453
+ * @param {Object} bid
454
+ * @param {string[]} sizes
455
+ * @returns The floor CPM of a matched rule based on the rule selection process (mediaType, size and currency),
456
+ * using the getFloor() inputs. Multi sizes and unsupported media types will default to '*'
457
+ */
458
+ function getBidFloor(bid, sizes) {
459
+ if (!isFn(bid.getFloor)) {
460
+ return undefined;
461
+ }
462
+ const mediaTypes = deepAccess(bid, 'mediaTypes');
463
+ const mediaType = mediaTypes !== undefined ? Object.keys(mediaTypes)[0].toLowerCase() : undefined;
464
+ const floor = bid.getFloor({
465
+ currency: CURRENCY_CODE,
466
+ mediaType: mediaType !== undefined && spec.supportedMediaTypes.includes(mediaType) ? mediaType : '*',
467
+ size: sizes.length !== 1 ? '*' : extractSizes(sizes)
468
+ });
469
+ if (floor.currency === CURRENCY_CODE) {
470
+ return floor.floor;
471
+ }
472
+ return undefined;
473
+ }
474
+
444
475
  registerBidder(spec)
@@ -242,6 +242,17 @@ function addPlacement(request) {
242
242
  if (gpid) {
243
243
  placementInfo.gpid = gpid;
244
244
  }
245
+
246
+ // get the transaction id for the banner bid.
247
+ const transactionId = deepAccess(request, 'ortb2Imp.ext.tid');
248
+
249
+ if (transactionId) {
250
+ placementInfo.tid = transactionId;
251
+ }
252
+
253
+ if (request.auctionId) {
254
+ placementInfo.auctionId = request.auctionId;
255
+ }
245
256
  return JSON.stringify(placementInfo);
246
257
  }
247
258
 
@@ -382,6 +393,9 @@ function openRtbRequest(bidRequests, bidderRequest) {
382
393
  openRtbRequest.schain = schain;
383
394
  }
384
395
 
396
+ if (bidRequests[0].auctionId) {
397
+ openRtbRequest.auctionId = bidRequests[0].auctionId;
398
+ }
385
399
  populateOpenRtbGdpr(openRtbRequest, bidderRequest);
386
400
 
387
401
  return openRtbRequest;
@@ -399,7 +413,8 @@ function openRtbImpression(bidRequest) {
399
413
  tagid: bidRequest.adUnitCode,
400
414
  bidfloor: getBidFloor(bidRequest, VIDEO),
401
415
  ext: {
402
- placement_id: bidRequest.params.placementId
416
+ placement_id: bidRequest.params.placementId,
417
+ tid: deepAccess(bidRequest, 'ortb2Imp.ext.tid')
403
418
  },
404
419
  video: {
405
420
  w: size[0],