prebid.js 5.17.0 → 6.0.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 (145) hide show
  1. package/.babelrc.js +3 -6
  2. package/README.md +3 -1
  3. package/browsers.json +1 -8
  4. package/integrationExamples/gpt/akamaidap_segments_example.html +132 -0
  5. package/modules/.submodules.json +1 -0
  6. package/modules/adfBidAdapter.js +21 -16
  7. package/modules/adgenerationBidAdapter.js +28 -4
  8. package/modules/adkernelBidAdapter.js +2 -1
  9. package/modules/admixerBidAdapter.js +11 -0
  10. package/modules/adtelligentBidAdapter.js +2 -1
  11. package/modules/airgridRtdProvider.js +1 -1
  12. package/modules/akamaiDapRtdProvider.js +474 -0
  13. package/modules/akamaiDapRtdProvider.md +47 -0
  14. package/modules/aolBidAdapter.js +2 -1
  15. package/modules/appnexusBidAdapter.js +5 -3
  16. package/modules/atsAnalyticsAdapter.js +67 -46
  17. package/modules/atsAnalyticsAdapter.md +1 -0
  18. package/modules/betweenBidAdapter.js +20 -3
  19. package/modules/bliinkBidAdapter.js +58 -32
  20. package/modules/bliinkBidAdapter.md +29 -6
  21. package/modules/browsiRtdProvider.js +106 -18
  22. package/modules/cleanioRtdProvider.js +192 -0
  23. package/modules/cleanioRtdProvider.md +59 -0
  24. package/modules/codefuelBidAdapter.js +183 -0
  25. package/modules/codefuelBidAdapter.md +111 -0
  26. package/modules/connectIdSystem.js +104 -0
  27. package/modules/connectIdSystem.md +33 -0
  28. package/modules/cwireBidAdapter.js +272 -0
  29. package/modules/cwireBidAdapter.md +43 -0
  30. package/modules/deepintentBidAdapter.js +106 -9
  31. package/modules/deepintentBidAdapter.md +36 -1
  32. package/modules/deltaprojectsBidAdapter.js +252 -0
  33. package/modules/deltaprojectsBidAdapter.md +32 -0
  34. package/modules/dgkeywordRtdProvider.js +0 -1
  35. package/modules/engageyaBidAdapter.js +157 -0
  36. package/modules/gridBidAdapter.js +1 -0
  37. package/modules/gumgumBidAdapter.js +8 -0
  38. package/modules/inskinBidAdapter.js +7 -3
  39. package/modules/ixBidAdapter.js +8 -1
  40. package/modules/jixieBidAdapter.js +8 -2
  41. package/modules/justpremiumBidAdapter.js +6 -1
  42. package/modules/limelightDigitalBidAdapter.js +22 -2
  43. package/modules/livewrappedAnalyticsAdapter.js +53 -3
  44. package/modules/mediakeysBidAdapter.js +2 -1
  45. package/modules/multibid/index.js +3 -3
  46. package/modules/nativoBidAdapter.js +6 -2
  47. package/modules/nextMillenniumBidAdapter.js +12 -3
  48. package/modules/oguryBidAdapter.js +36 -7
  49. package/modules/openxBidAdapter.js +34 -22
  50. package/modules/operaadsBidAdapter.js +21 -1
  51. package/modules/otmBidAdapter.js +146 -0
  52. package/modules/otmBidAdapter.md +27 -26
  53. package/modules/outbrainBidAdapter.js +5 -0
  54. package/modules/pixfutureBidAdapter.js +24 -4
  55. package/modules/pixfutureBidAdapter.md +127 -0
  56. package/modules/playwireBidAdapter.md +61 -0
  57. package/modules/prebidServerBidAdapter/index.js +1 -1
  58. package/modules/proxistoreBidAdapter.js +4 -6
  59. package/modules/publinkIdSystem.js +11 -6
  60. package/modules/pubmaticBidAdapter.js +9 -0
  61. package/modules/pubmaticBidAdapter.md +1 -1
  62. package/modules/rtdModule/index.js +2 -2
  63. package/modules/sonobiBidAdapter.js +7 -0
  64. package/modules/sortableBidAdapter.js +1 -0
  65. package/modules/talkadsBidAdapter.js +129 -0
  66. package/modules/talkadsBidAdapter.md +60 -0
  67. package/modules/teadsBidAdapter.js +3 -0
  68. package/modules/tripleliftBidAdapter.js +22 -5
  69. package/modules/trustxBidAdapter.js +8 -6
  70. package/modules/undertoneBidAdapter.js +9 -5
  71. package/modules/undertoneBidAdapter.md +5 -1
  72. package/modules/unicornBidAdapter.js +3 -3
  73. package/modules/userId/eids.js +18 -0
  74. package/modules/userId/eids.md +7 -0
  75. package/modules/userId/userId.md +12 -0
  76. package/modules/ventesBidAdapter.js +370 -0
  77. package/modules/ventesBidAdapter.md +94 -0
  78. package/modules/videobyteBidAdapter.js +13 -6
  79. package/modules/videobyteBidAdapter.md +49 -0
  80. package/modules/visxBidAdapter.js +15 -22
  81. package/modules/yahoosspBidAdapter.js +637 -0
  82. package/modules/yahoosspBidAdapter.md +795 -0
  83. package/modules/yieldlabBidAdapter.js +48 -3
  84. package/modules/yieldlabBidAdapter.md +16 -1
  85. package/modules/yieldmoSyntheticInventoryModule.js +46 -0
  86. package/modules/yieldmoSyntheticInventoryModule.md +68 -0
  87. package/package.json +1 -1
  88. package/src/adapterManager.js +5 -0
  89. package/src/adapters/bidderFactory.js +4 -3
  90. package/src/auction.js +11 -11
  91. package/src/constants.json +1 -0
  92. package/src/secureCreatives.js +6 -7
  93. package/src/targeting.js +11 -9
  94. package/test/spec/modules/adfBidAdapter_spec.js +83 -29
  95. package/test/spec/modules/adgenerationBidAdapter_spec.js +121 -50
  96. package/test/spec/modules/adtelligentBidAdapter_spec.js +1 -0
  97. package/test/spec/modules/akamaiDapRtdProvider_spec.js +246 -0
  98. package/test/spec/modules/appnexusBidAdapter_spec.js +2 -1
  99. package/test/spec/modules/atsAnalyticsAdapter_spec.js +42 -9
  100. package/test/spec/modules/betweenBidAdapter_spec.js +41 -0
  101. package/test/spec/modules/bliinkBidAdapter_spec.js +87 -36
  102. package/test/spec/modules/browsiRtdProvider_spec.js +62 -7
  103. package/test/spec/modules/cleanioRtdProvider_spec.js +188 -0
  104. package/test/spec/modules/codefuelBidAdapter_spec.js +316 -0
  105. package/test/spec/modules/connectIdSystem_spec.js +189 -0
  106. package/test/spec/modules/cwireBidAdapter_spec.js +246 -0
  107. package/test/spec/modules/deepintentBidAdapter_spec.js +153 -3
  108. package/test/spec/modules/deltaprojectsBidAdapter_spec.js +399 -0
  109. package/test/spec/modules/engageyaBidAdapter_spec.js +286 -0
  110. package/test/spec/modules/gumgumBidAdapter_spec.js +5 -1
  111. package/test/spec/modules/ixBidAdapter_spec.js +13 -3
  112. package/test/spec/modules/jixieBidAdapter_spec.js +13 -11
  113. package/test/spec/modules/justpremiumBidAdapter_spec.js +9 -2
  114. package/test/spec/modules/limelightDigitalBidAdapter_spec.js +155 -1
  115. package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +67 -12
  116. package/test/spec/modules/multibid_spec.js +31 -31
  117. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +13 -1
  118. package/test/spec/modules/oguryBidAdapter_spec.js +125 -37
  119. package/test/spec/modules/openxBidAdapter_spec.js +85 -13
  120. package/test/spec/modules/operaadsBidAdapter_spec.js +38 -6
  121. package/test/spec/modules/otmBidAdapter_spec.js +67 -0
  122. package/test/spec/modules/outbrainBidAdapter_spec.js +18 -0
  123. package/test/spec/modules/publinkIdSystem_spec.js +6 -6
  124. package/test/spec/modules/pubmaticBidAdapter_spec.js +39 -1
  125. package/test/spec/modules/sonobiBidAdapter_spec.js +34 -1
  126. package/test/spec/modules/sortableBidAdapter_spec.js +11 -0
  127. package/test/spec/modules/talkadsBidAdapter_spec.js +231 -0
  128. package/test/spec/modules/teadsBidAdapter_spec.js +132 -0
  129. package/test/spec/modules/tripleliftBidAdapter_spec.js +128 -0
  130. package/test/spec/modules/trustxBidAdapter_spec.js +3 -3
  131. package/test/spec/modules/undertoneBidAdapter_spec.js +52 -0
  132. package/test/spec/modules/unicornBidAdapter_spec.js +4 -4
  133. package/test/spec/modules/ventesBidAdapter_spec.js +845 -0
  134. package/test/spec/modules/videobyteBidAdapter_spec.js +2 -2
  135. package/test/spec/modules/visxBidAdapter_spec.js +48 -4
  136. package/test/spec/modules/yahoosspBidAdapter_spec.js +1332 -0
  137. package/test/spec/modules/yieldlabBidAdapter_spec.js +65 -1
  138. package/test/spec/modules/yieldmoSyntheticInventoryModule_spec.js +89 -0
  139. package/test/spec/unit/core/adapterManager_spec.js +32 -0
  140. package/test/spec/unit/core/bidderFactory_spec.js +61 -1
  141. package/test/spec/unit/pbjs_api_spec.js +37 -2
  142. package/test/spec/unit/secureCreatives_spec.js +54 -25
  143. package/wdio.conf.js +1 -1
  144. package/modules/turktelekomBidAdapter.md +0 -49
  145. package/yarn.lock +0 -13122
@@ -3,6 +3,7 @@ import {ajax} from '../src/ajax.js';
3
3
  import adapter from '../src/AnalyticsAdapter.js';
4
4
  import CONSTANTS from '../src/constants.json';
5
5
  import adapterManager from '../src/adapterManager.js';
6
+ import { getGlobal } from '../src/prebidGlobal.js';
6
7
 
7
8
  const ANALYTICSTYPE = 'endpoint';
8
9
  const URL = 'https://lwadm.com/analytics/10';
@@ -11,8 +12,10 @@ const REQUESTSENT = 1;
11
12
  const RESPONSESENT = 2;
12
13
  const WINSENT = 4;
13
14
  const TIMEOUTSENT = 8;
15
+ const ADRENDERFAILEDSENT = 16;
14
16
 
15
17
  let initOptions;
18
+ let prebidGlobal = getGlobal();
16
19
  export const BID_WON_TIMEOUT = 500;
17
20
 
18
21
  const cache = {
@@ -78,9 +81,11 @@ let livewrappedAnalyticsAdapter = Object.assign(adapter({EMPTYURL, ANALYTICSTYPE
78
81
  bidResponse.width = args.width;
79
82
  bidResponse.height = args.height;
80
83
  bidResponse.cpm = args.cpm;
84
+ bidResponse.originalCpm = prebidGlobal.convertCurrency(args.originalCpm, args.originalCurrency, args.currency);
81
85
  bidResponse.ttr = args.timeToRespond;
82
86
  bidResponse.readyToSend = 1;
83
87
  bidResponse.mediaType = args.mediaType == 'native' ? 2 : (args.mediaType == 'video' ? 4 : 1);
88
+ bidResponse.floorData = args.floorData;
84
89
  if (!bidResponse.ttr) {
85
90
  bidResponse.ttr = time - bidResponse.start;
86
91
  }
@@ -108,10 +113,21 @@ let livewrappedAnalyticsAdapter = Object.assign(adapter({EMPTYURL, ANALYTICSTYPE
108
113
  logInfo('LIVEWRAPPED_BID_WON:', args);
109
114
  let wonBid = cache.auctions[args.auctionId].bids[args.requestId];
110
115
  wonBid.won = true;
116
+ wonBid.floorData = args.floorData;
111
117
  if (wonBid.sendStatus != 0) {
112
118
  livewrappedAnalyticsAdapter.sendEvents();
113
119
  }
114
120
  break;
121
+ case CONSTANTS.EVENTS.AD_RENDER_FAILED:
122
+ logInfo('LIVEWRAPPED_AD_RENDER_FAILED:', args);
123
+ let adRenderFailedBid = cache.auctions[args.bid.auctionId].bids[args.bid.requestId];
124
+ adRenderFailedBid.adRenderFailed = true;
125
+ adRenderFailedBid.reason = args.reason;
126
+ adRenderFailedBid.message = args.message;
127
+ if (adRenderFailedBid.sendStatus != 0) {
128
+ livewrappedAnalyticsAdapter.sendEvents();
129
+ }
130
+ break;
115
131
  case CONSTANTS.EVENTS.BID_TIMEOUT:
116
132
  logInfo('LIVEWRAPPED_BID_TIMEOUT:', args);
117
133
  args.forEach(timeout => {
@@ -149,13 +165,15 @@ livewrappedAnalyticsAdapter.sendEvents = function() {
149
165
  wins: getWins(sentRequests.gdpr, sentRequests.auctionIds),
150
166
  timeouts: getTimeouts(sentRequests.auctionIds),
151
167
  bidAdUnits: getbidAdUnits(),
168
+ rf: getAdRenderFailed(sentRequests.auctionIds),
152
169
  rcv: getAdblockerRecovered()
153
170
  };
154
171
 
155
172
  if (events.requests.length == 0 &&
156
173
  events.responses.length == 0 &&
157
174
  events.wins.length == 0 &&
158
- events.timeouts.length == 0) {
175
+ events.timeouts.length == 0 &&
176
+ events.rf.length == 0) {
159
177
  return;
160
178
  }
161
179
 
@@ -222,11 +240,12 @@ function getResponses(gdpr, auctionIds) {
222
240
  width: bid.width,
223
241
  height: bid.height,
224
242
  cpm: bid.cpm,
243
+ orgCpm: bid.originalCpm,
225
244
  ttr: bid.ttr,
226
245
  IsBid: bid.isBid,
227
246
  mediaType: bid.mediaType,
228
247
  gdpr: gdprPos,
229
- floor: bid.floorData ? bid.floorData.floorValue : bid.lwFloor,
248
+ floor: bid.lwFloor ? bid.lwFloor : (bid.floorData ? bid.floorData.floorValue : undefined),
230
249
  floorCur: bid.floorData ? bid.floorData.floorCurrency : undefined,
231
250
  auctionId: auctionIdPos,
232
251
  auc: bid.auc,
@@ -261,9 +280,10 @@ function getWins(gdpr, auctionIds) {
261
280
  width: bid.width,
262
281
  height: bid.height,
263
282
  cpm: bid.cpm,
283
+ orgCpm: bid.originalCpm,
264
284
  mediaType: bid.mediaType,
265
285
  gdpr: gdprPos,
266
- floor: bid.floorData ? bid.floorData.floorValue : bid.lwFloor,
286
+ floor: bid.lwFloor ? bid.lwFloor : (bid.floorData ? bid.floorData.floorValue : undefined),
267
287
  floorCur: bid.floorData ? bid.floorData.floorCurrency : undefined,
268
288
  auctionId: auctionIdPos,
269
289
  auc: bid.auc,
@@ -336,6 +356,36 @@ function getTimeouts(auctionIds) {
336
356
  return timeouts;
337
357
  }
338
358
 
359
+ function getAdRenderFailed(auctionIds) {
360
+ var adRenderFails = [];
361
+
362
+ Object.keys(cache.auctions).forEach(auctionId => {
363
+ let auctionIdPos = getAuctionIdPos(auctionIds, auctionId);
364
+ Object.keys(cache.auctions[auctionId].bids).forEach(bidId => {
365
+ let auction = cache.auctions[auctionId];
366
+ let bid = auction.bids[bidId];
367
+ if (!(bid.sendStatus & ADRENDERFAILEDSENT) && bid.adRenderFailed) {
368
+ bid.sendStatus |= ADRENDERFAILEDSENT;
369
+
370
+ adRenderFails.push({
371
+ bidder: bid.bidder,
372
+ adUnit: bid.adUnit,
373
+ adUnitId: bid.adUnitId,
374
+ timeStamp: auction.timeStamp,
375
+ auctionId: auctionIdPos,
376
+ auc: bid.auc,
377
+ buc: bid.buc,
378
+ lw: bid.lw,
379
+ rsn: bid.reason,
380
+ msg: bid.message
381
+ });
382
+ }
383
+ });
384
+ });
385
+
386
+ return adRenderFails;
387
+ }
388
+
339
389
  function getbidAdUnits() {
340
390
  var bidAdUnits = [];
341
391
 
@@ -1,4 +1,5 @@
1
1
  import find from 'core-js-pure/features/array/find.js';
2
+ import arrayFrom from 'core-js-pure/features/array/from';
2
3
  import { getWindowTop, isFn, logWarn, getDNT, deepAccess, isArray, inIframe, mergeDeep, isStr, isEmpty, deepSetValue, deepClone, parseUrl, cleanObj, logError, triggerPixel, isInteger, isNumber } from '../src/utils.js';
3
4
  import { registerBidder } from '../src/adapters/bidderFactory.js';
4
5
  import { config } from '../src/config.js';
@@ -54,7 +55,7 @@ const ORTB_VIDEO_PARAMS = {
54
55
  skipmin: value => isInteger(value),
55
56
  skipafter: value => isInteger(value),
56
57
  sequence: value => isInteger(value),
57
- battr: value => Array.isArray(value) && value.every(v => Array.from({length: 17}, (_, i) => i + 1).indexOf(v) !== -1),
58
+ battr: value => Array.isArray(value) && value.every(v => arrayFrom({length: 17}, (_, i) => i + 1).indexOf(v) !== -1),
58
59
  maxextended: value => isInteger(value),
59
60
  minbitrate: value => isInteger(value),
60
61
  maxbitrate: value => isInteger(value),
@@ -112,7 +112,7 @@ export function addBidResponseHook(fn, adUnitCode, bid) {
112
112
  if (multiConfig[bid.bidderCode].prefix) bid.multibidPrefix = multiConfig[bid.bidderCode].prefix;
113
113
  bid.originalBidder = bid.bidderCode;
114
114
  // Check if stored bids for auction include adUnitCode.bidder and max limit not reach for ad unit
115
- if (deepAccess(multibidUnits, `${adUnitCode}.${bid.bidderCode}`)) {
115
+ if (deepAccess(multibidUnits, [adUnitCode, bid.bidderCode])) {
116
116
  // Store request id under new property originalRequestId, create new unique bidId,
117
117
  // and push bid into multibid stored bids for auction if max not reached and bid cpm above floor
118
118
  if (!multibidUnits[adUnitCode][bid.bidderCode].maxReached && (!floor || floor <= bid.cpm)) {
@@ -131,9 +131,9 @@ export function addBidResponseHook(fn, adUnitCode, bid) {
131
131
  logWarn(`Filtering multibid received from bidder ${bid.bidderCode}: ` + ((multibidUnits[adUnitCode][bid.bidderCode].maxReached) ? `Maximum bid limit reached for ad unit code ${adUnitCode}` : 'Bid cpm under floors value.'));
132
132
  }
133
133
  } else {
134
- if (deepAccess(bid, 'floorData.floorValue')) deepSetValue(multibidUnits, `${adUnitCode}.${bid.bidderCode}`, {floor: deepAccess(bid, 'floorData.floorValue')});
134
+ if (deepAccess(bid, 'floorData.floorValue')) deepSetValue(multibidUnits, [adUnitCode, bid.bidderCode], {floor: deepAccess(bid, 'floorData.floorValue')});
135
135
 
136
- deepSetValue(multibidUnits, `${adUnitCode}.${bid.bidderCode}`, {ads: [bid]});
136
+ deepSetValue(multibidUnits, [adUnitCode, bid.bidderCode], {ads: [bid]});
137
137
  if (multibidUnits[adUnitCode][bid.bidderCode].ads.length === multiConfig[bid.bidderCode].maxbids) multibidUnits[adUnitCode][bid.bidderCode].maxReached = true;
138
138
 
139
139
  fn.call(this, adUnitCode, bid);
@@ -71,7 +71,7 @@ export const spec = {
71
71
  // Track if we've already requested for this ad unit code
72
72
  adUnitsRequested[adUnit.adUnitCode] =
73
73
  adUnitsRequested[adUnit.adUnitCode] !== undefined
74
- ? adUnitsRequested[adUnit.adUnitCode]++
74
+ ? adUnitsRequested[adUnit.adUnitCode] + 1
75
75
  : 0
76
76
  return {
77
77
  adUnitCode: adUnit.adUnitCode,
@@ -98,7 +98,11 @@ export const spec = {
98
98
  ]
99
99
 
100
100
  if (placementIds.size > 0) {
101
- params.unshift({ key: 'ntv_ptd', value: [...placementIds].join(',') })
101
+ // Convert Set to Array (IE 11 Safe)
102
+ const placements = []
103
+ placementIds.forEach((value) => placements.push(value))
104
+ // Append to query string paramters
105
+ params.unshift({ key: 'ntv_ptd', value: placements.join(',') })
102
106
  }
103
107
 
104
108
  if (bidderRequest.gdprConsent) {
@@ -30,14 +30,23 @@ export const spec = {
30
30
  }
31
31
  }
32
32
  }
33
+
33
34
  const gdprConsent = bidderRequest && bidderRequest.gdprConsent;
35
+ const uspConsent = bidderRequest && bidderRequest.uspConsent
36
+
37
+ if (gdprConsent || uspConsent) {
38
+ postBody.regs = { ext: {} }
34
39
 
35
- if (gdprConsent) {
40
+ if (uspConsent) {
41
+ postBody.regs.ext.us_privacy = uspConsent;
42
+ }
36
43
  if (typeof gdprConsent.gdprApplies !== 'undefined') {
37
- postBody.gdprApplies = !!gdprConsent.gdprApplies;
44
+ postBody.regs.ext.gdpr = gdprConsent.gdprApplies ? 1 : 0;
38
45
  }
39
46
  if (typeof gdprConsent.consentString !== 'undefined') {
40
- postBody.consentString = gdprConsent.consentString;
47
+ postBody.user = {
48
+ ext: { consent: gdprConsent.consentString }
49
+ }
41
50
  }
42
51
  }
43
52
 
@@ -1,13 +1,14 @@
1
1
  'use strict';
2
2
 
3
3
  import { BANNER } from '../src/mediaTypes.js';
4
- import { getAdUnitSizes, logWarn, isFn } from '../src/utils.js';
4
+ import { getAdUnitSizes, logWarn, isFn, getWindowTop, getWindowSelf } from '../src/utils.js';
5
5
  import { registerBidder } from '../src/adapters/bidderFactory.js';
6
6
  import { ajax } from '../src/ajax.js'
7
7
 
8
8
  const BIDDER_CODE = 'ogury';
9
9
  const DEFAULT_TIMEOUT = 1000;
10
10
  const BID_HOST = 'https://mweb-hb.presage.io/api/header-bidding-request';
11
+ const TIMEOUT_MONITORING_HOST = 'https://ms-ads-monitoring-events.presage.io';
11
12
  const MS_COOKIE_SYNC_DOMAIN = 'https://ms-cookie-sync.presage.io';
12
13
 
13
14
  function isBidRequestValid(bid) {
@@ -23,10 +24,16 @@ function isBidRequestValid(bid) {
23
24
  function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) {
24
25
  if (!syncOptions.pixelEnabled) return [];
25
26
 
26
- return [{
27
- type: 'image',
28
- url: `${MS_COOKIE_SYNC_DOMAIN}/v1/init-sync/bid-switch?iab_string=${(gdprConsent && gdprConsent.consentString) || ''}&source=prebid`
29
- }]
27
+ return [
28
+ {
29
+ type: 'image',
30
+ url: `${MS_COOKIE_SYNC_DOMAIN}/v1/init-sync/bid-switch?iab_string=${(gdprConsent && gdprConsent.consentString) || ''}&source=prebid`
31
+ },
32
+ {
33
+ type: 'image',
34
+ url: `${MS_COOKIE_SYNC_DOMAIN}/ttd/init-sync?iab_string=${(gdprConsent && gdprConsent.consentString) || ''}&source=prebid`
35
+ }
36
+ ]
30
37
  }
31
38
 
32
39
  function buildRequests(validBidRequests, bidderRequest) {
@@ -40,7 +47,8 @@ function buildRequests(validBidRequests, bidderRequest) {
40
47
  },
41
48
  },
42
49
  site: {
43
- domain: location.hostname
50
+ domain: location.hostname,
51
+ page: location.href
44
52
  },
45
53
  user: {
46
54
  ext: {
@@ -137,10 +145,29 @@ function getFloor(bid) {
137
145
  return floorResult.currency === 'USD' ? floorResult.floor : 0;
138
146
  }
139
147
 
148
+ function getWindowContext() {
149
+ try {
150
+ return getWindowTop()
151
+ } catch (e) {
152
+ return getWindowSelf()
153
+ }
154
+ }
155
+
140
156
  function onBidWon(bid) {
157
+ const w = getWindowContext()
158
+ w.OG_PREBID_BID_OBJECT = {
159
+ ...(bid && { ...bid }),
160
+ }
141
161
  if (bid && bid.hasOwnProperty('nurl') && bid.nurl.length > 0) ajax(bid['nurl'], null);
142
162
  }
143
163
 
164
+ function onTimeout(timeoutData) {
165
+ ajax(`${TIMEOUT_MONITORING_HOST}/bid_timeout`, null, JSON.stringify(timeoutData[0]), {
166
+ method: 'POST',
167
+ contentType: 'application/json'
168
+ });
169
+ }
170
+
144
171
  export const spec = {
145
172
  code: BIDDER_CODE,
146
173
  supportedMediaTypes: [BANNER],
@@ -149,7 +176,9 @@ export const spec = {
149
176
  buildRequests,
150
177
  interpretResponse,
151
178
  getFloor,
152
- onBidWon
179
+ onBidWon,
180
+ getWindowContext,
181
+ onTimeout
153
182
  }
154
183
 
155
184
  registerBidder(spec);
@@ -256,27 +256,14 @@ function buildCommonQueryParamsFromBids(bids, bidderRequest) {
256
256
  nocache: new Date().getTime()
257
257
  };
258
258
 
259
- const firstPartyData = config.getConfig('ortb2.user.data')
260
- if (Array.isArray(firstPartyData) && firstPartyData.length > 0) {
261
- // extract and merge valid segments by provider/taxonomy
262
- const fpd = firstPartyData
263
- .filter(
264
- data => (Array.isArray(data.segment) &&
265
- data.segment.length > 0 &&
266
- data.name !== undefined &&
267
- data.name.length > 0)
268
- )
269
- .reduce((acc, data) => {
270
- const name = typeof data.ext === 'object' && data.ext.segtax ? `${data.name}/${data.ext.segtax}` : data.name;
271
- acc[name] = (acc[name] || []).concat(data.segment.map(seg => seg.id));
272
- return acc;
273
- }, {})
274
- const sm = Object.keys(fpd)
275
- .map((name, _) => name + ':' + fpd[name].join('|'))
276
- .join(',')
277
- if (sm.length > 0) {
278
- defaultParams.sm = encodeURIComponent(sm);
279
- }
259
+ const userDataSegments = buildFpdQueryParams('ortb2.user.data');
260
+ if (userDataSegments.length > 0) {
261
+ defaultParams.sm = userDataSegments;
262
+ }
263
+
264
+ const siteContentDataSegments = buildFpdQueryParams('ortb2.site.content.data');
265
+ if (siteContentDataSegments.length > 0) {
266
+ defaultParams.scsm = siteContentDataSegments;
280
267
  }
281
268
 
282
269
  if (bids[0].params.platform) {
@@ -317,12 +304,37 @@ function buildCommonQueryParamsFromBids(bids, bidderRequest) {
317
304
  return defaultParams;
318
305
  }
319
306
 
307
+ function buildFpdQueryParams(fpdPath) {
308
+ const firstPartyData = config.getConfig(fpdPath);
309
+ if (!Array.isArray(firstPartyData) || !firstPartyData.length) {
310
+ return '';
311
+ }
312
+ const fpd = firstPartyData
313
+ .filter(
314
+ data => (Array.isArray(data.segment) &&
315
+ data.segment.length > 0 &&
316
+ data.name !== undefined &&
317
+ data.name.length > 0)
318
+ )
319
+ .reduce((acc, data) => {
320
+ const name = typeof data.ext === 'object' && data.ext.segtax ? `${data.name}/${data.ext.segtax}` : data.name;
321
+ acc[name] = (acc[name] || []).concat(data.segment.map(seg => seg.id));
322
+ return acc;
323
+ }, {})
324
+ return Object.keys(fpd)
325
+ .map((name, _) => name + ':' + fpd[name].join('|'))
326
+ .join(',')
327
+ }
328
+
320
329
  function appendUserIdsToQueryParams(queryParams, userIds) {
321
330
  _each(userIds, (userIdObjectOrValue, userIdProviderKey) => {
322
331
  const key = USER_ID_CODE_TO_QUERY_ARG[userIdProviderKey];
323
332
 
324
333
  if (USER_ID_CODE_TO_QUERY_ARG.hasOwnProperty(userIdProviderKey)) {
325
334
  switch (userIdProviderKey) {
335
+ case 'merkleId':
336
+ queryParams[key] = userIdObjectOrValue.id;
337
+ break;
326
338
  case 'flocId':
327
339
  queryParams[key] = userIdObjectOrValue.id;
328
340
  break;
@@ -333,7 +345,7 @@ function appendUserIdsToQueryParams(queryParams, userIds) {
333
345
  queryParams[key] = userIdObjectOrValue.lipbid;
334
346
  if (Array.isArray(userIdObjectOrValue.segments) && userIdObjectOrValue.segments.length > 0) {
335
347
  const liveIntentSegments = 'liveintent:' + userIdObjectOrValue.segments.join('|')
336
- queryParams.sm = `${queryParams.sm ? queryParams.sm + encodeURIComponent(',') : ''}${encodeURIComponent(liveIntentSegments)}`;
348
+ queryParams.sm = `${queryParams.sm ? queryParams.sm + ',' : ''}${liveIntentSegments}`;
337
349
  }
338
350
  break;
339
351
  case 'parrableId':
@@ -8,6 +8,7 @@ import { OUTSTREAM } from '../src/video.js';
8
8
  const BIDDER_CODE = 'operaads';
9
9
 
10
10
  const ENDPOINT = 'https://s.adx.opera.com/ortb/v2/';
11
+ const USER_SYNC_ENDPOINT = 'https://s.adx.opera.com/usersync/page';
11
12
 
12
13
  const OUTSTREAM_RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js';
13
14
 
@@ -137,6 +138,25 @@ export const spec = {
137
138
  * @return {UserSync[]} The user syncs which should be dropped.
138
139
  */
139
140
  getUserSyncs: function (syncOptions, serverResponses, gdprConsent, uspConsent) {
141
+ if ('iframeEnabled' in syncOptions && syncOptions.iframeEnabled) {
142
+ return [{
143
+ type: 'iframe',
144
+ url: USER_SYNC_ENDPOINT
145
+ }];
146
+ }
147
+ if ('pixelEnabled' in syncOptions && syncOptions.pixelEnabled) {
148
+ const pixels = deepAccess(serverResponses, '0.body.pixels')
149
+ if (Array.isArray(pixels)) {
150
+ const userSyncPixels = []
151
+ for (const pixel of pixels) {
152
+ userSyncPixels.push({
153
+ type: 'image',
154
+ url: pixel
155
+ })
156
+ }
157
+ return userSyncPixels;
158
+ }
159
+ }
140
160
  return [];
141
161
  },
142
162
 
@@ -212,7 +232,7 @@ function buildOpenRtbBidRequest(bidRequest, bidderRequest) {
212
232
  ext: {}
213
233
  },
214
234
  user: {
215
- id: getUserId(bidRequest)
235
+ buyeruid: getUserId(bidRequest)
216
236
  }
217
237
  }
218
238
 
@@ -0,0 +1,146 @@
1
+ import { registerBidder } from '../src/adapters/bidderFactory.js';
2
+ import {logInfo, logError, getBidIdParameter, _each, getValue, isFn, isPlainObject} from '../src/utils.js';
3
+ import { BANNER } from '../src/mediaTypes.js';
4
+
5
+ const BIDDER_CODE = 'otm';
6
+ const OTM_BID_URL = 'https://ssp.otm-r.com/adjson';
7
+ const DEF_CUR = 'RUB'
8
+
9
+ export const spec = {
10
+
11
+ code: BIDDER_CODE,
12
+ url: OTM_BID_URL,
13
+ supportedMediaTypes: [ BANNER ],
14
+
15
+ /**
16
+ * Determines whether or not the given bid request is valid.
17
+ *
18
+ * @param {object} bid The bid to validate.
19
+ * @return boolean True if this is a valid bid, and false otherwise.
20
+ */
21
+ isBidRequestValid: function (bid) {
22
+ return !!bid.params.tid;
23
+ },
24
+
25
+ /**
26
+ * Build bidder requests.
27
+ *
28
+ * @param validBidRequests
29
+ * @param bidderRequest
30
+ * @returns {[]}
31
+ */
32
+ buildRequests: function (validBidRequests, bidderRequest) {
33
+ logInfo('validBidRequests', validBidRequests);
34
+
35
+ const bidRequests = [];
36
+ let tz = new Date().getTimezoneOffset()
37
+ let referrer = '';
38
+ if (bidderRequest && bidderRequest.refererInfo) {
39
+ referrer = bidderRequest.refererInfo.referer;
40
+ }
41
+
42
+ _each(validBidRequests, (bid) => {
43
+ let domain = getValue(bid.params, 'domain') || ''
44
+ let tid = getValue(bid.params, 'tid')
45
+ let cur = getValue(bid.params, 'currency') || DEF_CUR
46
+ let bidid = getBidIdParameter('bidId', bid)
47
+ let transactionid = getBidIdParameter('transactionId', bid)
48
+ let auctionid = getBidIdParameter('auctionId', bid)
49
+ let bidfloor = _getBidFloor(bid)
50
+
51
+ _each(bid.sizes, size => {
52
+ let width = 0;
53
+ let height = 0;
54
+ if (size.length && typeof size[0] === 'number' && typeof size[1] === 'number') {
55
+ width = size[0];
56
+ height = size[1];
57
+ }
58
+ bidRequests.push({
59
+ method: 'GET',
60
+ url: OTM_BID_URL,
61
+ data: {
62
+ tz: tz,
63
+ w: width,
64
+ h: height,
65
+ domain: domain,
66
+ l: referrer,
67
+ s: tid,
68
+ cur: cur,
69
+ bidid: bidid,
70
+ transactionid: transactionid,
71
+ auctionid: auctionid,
72
+ bidfloor: bidfloor,
73
+ },
74
+ })
75
+ })
76
+ })
77
+ return bidRequests;
78
+ },
79
+
80
+ /**
81
+ * Generate response.
82
+ *
83
+ * @param serverResponse
84
+ * @param request
85
+ * @returns {[]|*[]}
86
+ */
87
+ interpretResponse: function (serverResponse, request) {
88
+ logInfo('serverResponse', serverResponse.body);
89
+
90
+ const responsesBody = serverResponse ? serverResponse.body : {};
91
+ const bidResponses = [];
92
+ try {
93
+ if (responsesBody.length === 0) {
94
+ return [];
95
+ }
96
+
97
+ _each(responsesBody, (bid) => {
98
+ if (bid.ad) {
99
+ bidResponses.push({
100
+ requestId: bid.bidid,
101
+ cpm: bid.cpm,
102
+ width: bid.w,
103
+ height: bid.h,
104
+ creativeId: bid.creativeid,
105
+ currency: bid.currency || 'RUB',
106
+ netRevenue: true,
107
+ ad: bid.ad,
108
+ ttl: bid.ttl,
109
+ transactionId: bid.transactionid,
110
+ meta: {
111
+ advertiserDomains: bid.adDomain ? [bid.adDomain] : []
112
+ }
113
+ });
114
+ }
115
+ });
116
+ } catch (error) {
117
+ logError(error);
118
+ }
119
+
120
+ return bidResponses;
121
+ }
122
+ };
123
+
124
+ /**
125
+ * Get floor value
126
+ * @param bid
127
+ * @returns {null|*}
128
+ * @private
129
+ */
130
+ function _getBidFloor(bid) {
131
+ if (!isFn(bid.getFloor)) {
132
+ return bid.params.bidfloor ? bid.params.bidfloor : 0;
133
+ }
134
+
135
+ let floor = bid.getFloor({
136
+ currency: DEF_CUR,
137
+ mediaType: '*',
138
+ size: '*'
139
+ });
140
+ if (isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === DEF_CUR) {
141
+ return floor.floor;
142
+ }
143
+ return 0;
144
+ }
145
+
146
+ registerBidder(spec);
@@ -1,36 +1,37 @@
1
1
  # Overview
2
2
 
3
- Module Name: OTM Bidder Adapter
4
- Module Type: Bidder Adapter
5
- Maintainer: ?
3
+ **Module Name**: OTM Bidder Adapter
4
+ **Module Type**: Bidder Adapter
5
+ **Maintainer**: e.kretsu@otm-r.com
6
6
 
7
7
  # Description
8
8
 
9
- You can use this adapter to get a bid from otm-r.com.
9
+ OTM Bidder Adapter for Prebid.js. About: https://otm-r.com
10
10
 
11
- About us : http://otm-r.com
11
+ Use `otm` as bidder:
12
12
 
13
+ # Params
14
+ - `tid` required, specific id AdUnit slot.
15
+ - `domain` optional, specific custom domain.
16
+ - `bidfloor` optional.
13
17
 
14
- # Test Parameters
15
- ```javascript
16
- var adUnits = [
17
- {
18
- code: 'div-otm-example',
19
- sizes: [[320, 480]],
20
- bids: [
21
- {
22
- bidder: "otm",
23
- params: {
24
- tid: "99",
25
- bidfloor: 20
26
- }
27
- }
28
- ]
29
- }
30
- ];
18
+ ## AdUnits configuration example
31
19
  ```
20
+ var adUnits = [{
21
+ code: 'your-slot', //use exactly the same code as your slot div id.
22
+ mediaTypes: {
23
+ banner: {
24
+ sizes: [[320, 480]]
25
+ }
26
+ },
27
+ bids: [{
28
+ bidder: 'otm',
29
+ params: {
30
+ tid: 'XXXXX',
31
+ domain: 'specific custom domain, if needed',
32
+ bidfloor: 20
33
+ }
34
+ }]
35
+ }];
32
36
 
33
- Where:
34
-
35
- * tid - A tag id (should have low cardinality)
36
- * bidfloor - Floor price
37
+ ```
@@ -40,6 +40,7 @@ export const spec = {
40
40
  const publisher = setOnAny(validBidRequests, 'params.publisher');
41
41
  const bcat = setOnAny(validBidRequests, 'params.bcat');
42
42
  const badv = setOnAny(validBidRequests, 'params.badv');
43
+ const eids = setOnAny(validBidRequests, 'userIdAsEids')
43
44
  const cur = CURRENCY;
44
45
  const endpointUrl = config.getConfig('outbrain.bidderUrl');
45
46
  const timeout = bidderRequest.timeout;
@@ -105,6 +106,10 @@ export const spec = {
105
106
  deepSetValue(request, 'regs.coppa', config.getConfig('coppa') & 1)
106
107
  }
107
108
 
109
+ if (eids) {
110
+ deepSetValue(request, 'user.ext.eids', eids);
111
+ }
112
+
108
113
  return {
109
114
  method: 'POST',
110
115
  url: endpointUrl,