prebid.js 5.18.0 → 6.1.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 (150) hide show
  1. package/.babelrc.js +1 -10
  2. package/README.md +3 -1
  3. package/browsers.json +1 -8
  4. package/gulpfile.js +1 -0
  5. package/integrationExamples/gpt/akamaidap_segments_example.html +132 -0
  6. package/modules/.submodules.json +1 -0
  7. package/modules/adfBidAdapter.js +21 -16
  8. package/modules/adheseBidAdapter.js +7 -2
  9. package/modules/adkernelBidAdapter.js +1 -0
  10. package/modules/adlivetechBidAdapter.md +61 -0
  11. package/modules/adomikAnalyticsAdapter.js +10 -4
  12. package/modules/adtelligentBidAdapter.js +2 -1
  13. package/modules/airgridRtdProvider.js +1 -1
  14. package/modules/akamaiDapRtdProvider.js +474 -0
  15. package/modules/akamaiDapRtdProvider.md +47 -0
  16. package/modules/appnexusBidAdapter.js +9 -3
  17. package/modules/atsAnalyticsAdapter.js +67 -46
  18. package/modules/atsAnalyticsAdapter.md +1 -0
  19. package/modules/betweenBidAdapter.js +20 -3
  20. package/modules/browsiRtdProvider.js +106 -18
  21. package/modules/cleanioRtdProvider.js +192 -0
  22. package/modules/cleanioRtdProvider.md +59 -0
  23. package/modules/codefuelBidAdapter.js +181 -0
  24. package/modules/codefuelBidAdapter.md +111 -0
  25. package/modules/connectIdSystem.js +104 -0
  26. package/modules/connectIdSystem.md +33 -0
  27. package/modules/datablocksBidAdapter.js +3 -3
  28. package/modules/deepintentBidAdapter.js +107 -10
  29. package/modules/deepintentBidAdapter.md +36 -1
  30. package/modules/deltaprojectsBidAdapter.js +252 -0
  31. package/modules/deltaprojectsBidAdapter.md +32 -0
  32. package/modules/engageyaBidAdapter.js +171 -0
  33. package/modules/glimpseBidAdapter.js +31 -16
  34. package/modules/gptPreAuction.js +11 -5
  35. package/modules/gridBidAdapter.js +1 -0
  36. package/modules/gumgumBidAdapter.js +8 -0
  37. package/modules/id5IdSystem.md +6 -6
  38. package/modules/imRtdProvider.js +31 -0
  39. package/modules/inskinBidAdapter.js +7 -3
  40. package/modules/ixBidAdapter.js +174 -22
  41. package/modules/jixieBidAdapter.js +8 -2
  42. package/modules/justpremiumBidAdapter.js +6 -1
  43. package/modules/limelightDigitalBidAdapter.js +22 -2
  44. package/modules/livewrappedAnalyticsAdapter.js +49 -1
  45. package/modules/merkleIdSystem.js +5 -0
  46. package/modules/multibid/index.js +3 -3
  47. package/modules/nativoBidAdapter.js +32 -2
  48. package/modules/nextMillenniumBidAdapter.js +12 -3
  49. package/modules/oguryBidAdapter.js +16 -2
  50. package/modules/openxBidAdapter.js +40 -23
  51. package/modules/operaadsBidAdapter.js +21 -1
  52. package/modules/otmBidAdapter.js +146 -0
  53. package/modules/otmBidAdapter.md +27 -26
  54. package/modules/outbrainBidAdapter.js +5 -0
  55. package/modules/playwireBidAdapter.md +61 -0
  56. package/modules/prebidServerBidAdapter/index.js +3 -3
  57. package/modules/publinkIdSystem.js +11 -6
  58. package/modules/pubmaticBidAdapter.js +2 -0
  59. package/modules/rtdModule/index.js +2 -2
  60. package/modules/saambaaBidAdapter.js +420 -0
  61. package/modules/saambaaBidAdapter.md +65 -68
  62. package/modules/seedtagBidAdapter.js +6 -0
  63. package/modules/smaatoBidAdapter.js +6 -1
  64. package/modules/sonobiBidAdapter.js +7 -0
  65. package/modules/sortableBidAdapter.js +1 -0
  66. package/modules/sspBCBidAdapter.js +34 -3
  67. package/modules/teadsBidAdapter.js +3 -0
  68. package/modules/tripleliftBidAdapter.js +22 -5
  69. package/modules/trustxBidAdapter.js +18 -7
  70. package/modules/undertoneBidAdapter.js +9 -5
  71. package/modules/undertoneBidAdapter.md +5 -1
  72. package/modules/userId/eids.js +18 -0
  73. package/modules/userId/eids.md +7 -0
  74. package/modules/userId/userId.md +12 -0
  75. package/modules/ventesBidAdapter.js +370 -0
  76. package/modules/ventesBidAdapter.md +94 -0
  77. package/modules/videobyteBidAdapter.js +13 -6
  78. package/modules/videobyteBidAdapter.md +49 -0
  79. package/modules/vidoomyBidAdapter.js +51 -100
  80. package/modules/visxBidAdapter.js +1 -1
  81. package/modules/yahoosspBidAdapter.js +6 -6
  82. package/modules/yieldlabBidAdapter.js +41 -10
  83. package/modules/yieldlabBidAdapter.md +91 -48
  84. package/modules/yieldmoSyntheticInventoryModule.js +46 -0
  85. package/modules/yieldmoSyntheticInventoryModule.md +68 -0
  86. package/package.json +6 -1
  87. package/src/adapterManager.js +19 -8
  88. package/src/adapters/bidderFactory.js +4 -3
  89. package/src/auction.js +11 -11
  90. package/src/constants.json +1 -0
  91. package/src/secureCreatives.js +6 -7
  92. package/src/targeting.js +11 -9
  93. package/test/spec/modules/adfBidAdapter_spec.js +83 -29
  94. package/test/spec/modules/adheseBidAdapter_spec.js +27 -1
  95. package/test/spec/modules/adomikAnalyticsAdapter_spec.js +3 -1
  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 +16 -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/browsiRtdProvider_spec.js +62 -7
  102. package/test/spec/modules/cleanioRtdProvider_spec.js +188 -0
  103. package/test/spec/modules/codefuelBidAdapter_spec.js +316 -0
  104. package/test/spec/modules/connectIdSystem_spec.js +189 -0
  105. package/test/spec/modules/datablocksBidAdapter_spec.js +3 -3
  106. package/test/spec/modules/deepintentBidAdapter_spec.js +153 -3
  107. package/test/spec/modules/deltaprojectsBidAdapter_spec.js +399 -0
  108. package/test/spec/modules/engageyaBidAdapter_spec.js +422 -0
  109. package/test/spec/modules/eplanningBidAdapter_spec.js +8 -8
  110. package/test/spec/modules/glimpseBidAdapter_spec.js +33 -0
  111. package/test/spec/modules/gptPreAuction_spec.js +58 -4
  112. package/test/spec/modules/gumgumBidAdapter_spec.js +5 -1
  113. package/test/spec/modules/imRtdProvider_spec.js +25 -0
  114. package/test/spec/modules/ixBidAdapter_spec.js +298 -5
  115. package/test/spec/modules/jixieBidAdapter_spec.js +13 -11
  116. package/test/spec/modules/justpremiumBidAdapter_spec.js +9 -2
  117. package/test/spec/modules/konduitWrapper_spec.js +0 -1
  118. package/test/spec/modules/limelightDigitalBidAdapter_spec.js +155 -1
  119. package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +52 -7
  120. package/test/spec/modules/merkleIdSystem_spec.js +18 -0
  121. package/test/spec/modules/multibid_spec.js +31 -31
  122. package/test/spec/modules/nativoBidAdapter_spec.js +35 -18
  123. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +13 -1
  124. package/test/spec/modules/oguryBidAdapter_spec.js +66 -23
  125. package/test/spec/modules/openxBidAdapter_spec.js +90 -13
  126. package/test/spec/modules/operaadsBidAdapter_spec.js +38 -6
  127. package/test/spec/modules/otmBidAdapter_spec.js +67 -0
  128. package/test/spec/modules/outbrainBidAdapter_spec.js +18 -0
  129. package/test/spec/modules/prebidServerBidAdapter_spec.js +19 -2
  130. package/test/spec/modules/publinkIdSystem_spec.js +6 -6
  131. package/test/spec/modules/seedtagBidAdapter_spec.js +3 -0
  132. package/test/spec/modules/smaatoBidAdapter_spec.js +30 -0
  133. package/test/spec/modules/sonobiBidAdapter_spec.js +34 -1
  134. package/test/spec/modules/sortableBidAdapter_spec.js +11 -0
  135. package/test/spec/modules/sspBCBidAdapter_spec.js +33 -3
  136. package/test/spec/modules/teadsBidAdapter_spec.js +132 -0
  137. package/test/spec/modules/tripleliftBidAdapter_spec.js +128 -0
  138. package/test/spec/modules/trustxBidAdapter_spec.js +45 -3
  139. package/test/spec/modules/undertoneBidAdapter_spec.js +52 -0
  140. package/test/spec/modules/ventesBidAdapter_spec.js +845 -0
  141. package/test/spec/modules/videobyteBidAdapter_spec.js +2 -2
  142. package/test/spec/modules/vidoomyBidAdapter_spec.js +32 -13
  143. package/test/spec/modules/visxBidAdapter_spec.js +1 -1
  144. package/test/spec/modules/yieldlabBidAdapter_spec.js +81 -0
  145. package/test/spec/modules/yieldmoSyntheticInventoryModule_spec.js +89 -0
  146. package/test/spec/unit/core/adapterManager_spec.js +56 -6
  147. package/test/spec/unit/core/bidderFactory_spec.js +61 -1
  148. package/test/spec/unit/pbjs_api_spec.js +37 -2
  149. package/test/spec/unit/secureCreatives_spec.js +54 -25
  150. package/wdio.conf.js +1 -1
@@ -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,6 +81,7 @@ 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);
@@ -114,6 +118,16 @@ let livewrappedAnalyticsAdapter = Object.assign(adapter({EMPTYURL, ANALYTICSTYPE
114
118
  livewrappedAnalyticsAdapter.sendEvents();
115
119
  }
116
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;
117
131
  case CONSTANTS.EVENTS.BID_TIMEOUT:
118
132
  logInfo('LIVEWRAPPED_BID_TIMEOUT:', args);
119
133
  args.forEach(timeout => {
@@ -151,13 +165,15 @@ livewrappedAnalyticsAdapter.sendEvents = function() {
151
165
  wins: getWins(sentRequests.gdpr, sentRequests.auctionIds),
152
166
  timeouts: getTimeouts(sentRequests.auctionIds),
153
167
  bidAdUnits: getbidAdUnits(),
168
+ rf: getAdRenderFailed(sentRequests.auctionIds),
154
169
  rcv: getAdblockerRecovered()
155
170
  };
156
171
 
157
172
  if (events.requests.length == 0 &&
158
173
  events.responses.length == 0 &&
159
174
  events.wins.length == 0 &&
160
- events.timeouts.length == 0) {
175
+ events.timeouts.length == 0 &&
176
+ events.rf.length == 0) {
161
177
  return;
162
178
  }
163
179
 
@@ -224,6 +240,7 @@ function getResponses(gdpr, auctionIds) {
224
240
  width: bid.width,
225
241
  height: bid.height,
226
242
  cpm: bid.cpm,
243
+ orgCpm: bid.originalCpm,
227
244
  ttr: bid.ttr,
228
245
  IsBid: bid.isBid,
229
246
  mediaType: bid.mediaType,
@@ -263,6 +280,7 @@ function getWins(gdpr, auctionIds) {
263
280
  width: bid.width,
264
281
  height: bid.height,
265
282
  cpm: bid.cpm,
283
+ orgCpm: bid.originalCpm,
266
284
  mediaType: bid.mediaType,
267
285
  gdpr: gdprPos,
268
286
  floor: bid.lwFloor ? bid.lwFloor : (bid.floorData ? bid.floorData.floorValue : undefined),
@@ -338,6 +356,36 @@ function getTimeouts(auctionIds) {
338
356
  return timeouts;
339
357
  }
340
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
+
341
389
  function getbidAdUnits() {
342
390
  var bidAdUnits = [];
343
391
 
@@ -149,6 +149,11 @@ export const merkleIdSubmodule = {
149
149
  logInfo('User ID - merkleId stored id ' + storedId);
150
150
  const configParams = (config && config.params) || {};
151
151
 
152
+ if (typeof configParams.endpoint !== 'string') {
153
+ logWarn('User ID - merkleId submodule endpoint string is not defined');
154
+ configParams.endpoint = ID_URL
155
+ }
156
+
152
157
  if (consentData && typeof consentData.gdprApplies === 'boolean' && consentData.gdprApplies) {
153
158
  logError('User ID - merkleId submodule does not currently handle consent strings');
154
159
  return;
@@ -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);
@@ -17,6 +17,16 @@ const adUnitsRequested = {}
17
17
 
18
18
  // Prebid adapter referrence doc: https://docs.prebid.org/dev-docs/bidder-adaptor.html
19
19
 
20
+ // Validity checks for optionsl paramters
21
+ const validParameter = {
22
+ url: (value) => typeof value === 'string',
23
+ placementId: (value) => {
24
+ const isString = typeof value === 'string'
25
+ const isNumber = typeof value === 'number'
26
+ return isString || isNumber
27
+ },
28
+ }
29
+
20
30
  export const spec = {
21
31
  code: BIDDER_CODE,
22
32
  gvlid: GVLID,
@@ -30,7 +40,23 @@ export const spec = {
30
40
  * @return boolean True if this is a valid bid, and false otherwise.
31
41
  */
32
42
  isBidRequestValid: function (bid) {
33
- return true
43
+ // We don't need any specific parameters to make a bid request
44
+ // If not parameters are supplied just verify it's the correct bidder code
45
+ if (!bid.params) return bid.bidder === BIDDER_CODE
46
+
47
+ // Check if any supplied parameters are invalid
48
+ const hasInvalidParameters = Object.keys(bid.params).some(key => {
49
+ const value = bid.params[key]
50
+ const validityCheck = validParameter[key]
51
+
52
+ // We don't have a test for this so it's not a paramter we care about
53
+ if (!validityCheck) return false
54
+
55
+ // Return if the check is not passed
56
+ return !validityCheck(value)
57
+ })
58
+
59
+ return !hasInvalidParameters
34
60
  },
35
61
 
36
62
  /**
@@ -98,7 +124,11 @@ export const spec = {
98
124
  ]
99
125
 
100
126
  if (placementIds.size > 0) {
101
- params.unshift({ key: 'ntv_ptd', value: [...placementIds].join(',') })
127
+ // Convert Set to Array (IE 11 Safe)
128
+ const placements = []
129
+ placementIds.forEach((value) => placements.push(value))
130
+ // Append to query string paramters
131
+ params.unshift({ key: 'ntv_ptd', value: placements.join(',') })
102
132
  }
103
133
 
104
134
  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,7 +1,7 @@
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
 
@@ -83,7 +83,8 @@ function buildRequests(validBidRequests, bidderRequest) {
83
83
  bidfloor: getFloor(bidRequest),
84
84
  banner: {
85
85
  format: sizes
86
- }
86
+ },
87
+ ext: bidRequest.params
87
88
  });
88
89
  }
89
90
  });
@@ -145,7 +146,19 @@ function getFloor(bid) {
145
146
  return floorResult.currency === 'USD' ? floorResult.floor : 0;
146
147
  }
147
148
 
149
+ function getWindowContext() {
150
+ try {
151
+ return getWindowTop()
152
+ } catch (e) {
153
+ return getWindowSelf()
154
+ }
155
+ }
156
+
148
157
  function onBidWon(bid) {
158
+ const w = getWindowContext()
159
+ w.OG_PREBID_BID_OBJECT = {
160
+ ...(bid && { ...bid }),
161
+ }
149
162
  if (bid && bid.hasOwnProperty('nurl') && bid.nurl.length > 0) ajax(bid['nurl'], null);
150
163
  }
151
164
 
@@ -165,6 +178,7 @@ export const spec = {
165
178
  interpretResponse,
166
179
  getFloor,
167
180
  onBidWon,
181
+ getWindowContext,
168
182
  onTimeout
169
183
  }
170
184
 
@@ -42,7 +42,12 @@ export const USER_ID_CODE_TO_QUERY_ARG = {
42
42
  novatiq: 'novatiqid', // Novatiq ID
43
43
  mwOpenLinkId: 'mwopenlinkid', // MediaWallah OpenLink ID
44
44
  dapId: 'dapid', // Akamai DAP ID
45
- amxId: 'amxid' // AMX RTB ID
45
+ amxId: 'amxid', // AMX RTB ID
46
+ kpuid: 'kpuid', // Kinesso ID
47
+ publinkId: 'publinkid', // Publisher Link
48
+ naveggId: 'naveggid', // Navegg ID
49
+ imuid: 'imuid', // IM-UID by Intimate Merger
50
+ adtelligentId: 'adtelligentid' // Adtelligent ID
46
51
  };
47
52
 
48
53
  export const spec = {
@@ -256,27 +261,14 @@ function buildCommonQueryParamsFromBids(bids, bidderRequest) {
256
261
  nocache: new Date().getTime()
257
262
  };
258
263
 
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
- }
264
+ const userDataSegments = buildFpdQueryParams('ortb2.user.data');
265
+ if (userDataSegments.length > 0) {
266
+ defaultParams.sm = userDataSegments;
267
+ }
268
+
269
+ const siteContentDataSegments = buildFpdQueryParams('ortb2.site.content.data');
270
+ if (siteContentDataSegments.length > 0) {
271
+ defaultParams.scsm = siteContentDataSegments;
280
272
  }
281
273
 
282
274
  if (bids[0].params.platform) {
@@ -317,12 +309,37 @@ function buildCommonQueryParamsFromBids(bids, bidderRequest) {
317
309
  return defaultParams;
318
310
  }
319
311
 
312
+ function buildFpdQueryParams(fpdPath) {
313
+ const firstPartyData = config.getConfig(fpdPath);
314
+ if (!Array.isArray(firstPartyData) || !firstPartyData.length) {
315
+ return '';
316
+ }
317
+ const fpd = firstPartyData
318
+ .filter(
319
+ data => (Array.isArray(data.segment) &&
320
+ data.segment.length > 0 &&
321
+ data.name !== undefined &&
322
+ data.name.length > 0)
323
+ )
324
+ .reduce((acc, data) => {
325
+ const name = typeof data.ext === 'object' && data.ext.segtax ? `${data.name}/${data.ext.segtax}` : data.name;
326
+ acc[name] = (acc[name] || []).concat(data.segment.map(seg => seg.id));
327
+ return acc;
328
+ }, {})
329
+ return Object.keys(fpd)
330
+ .map((name, _) => name + ':' + fpd[name].join('|'))
331
+ .join(',')
332
+ }
333
+
320
334
  function appendUserIdsToQueryParams(queryParams, userIds) {
321
335
  _each(userIds, (userIdObjectOrValue, userIdProviderKey) => {
322
336
  const key = USER_ID_CODE_TO_QUERY_ARG[userIdProviderKey];
323
337
 
324
338
  if (USER_ID_CODE_TO_QUERY_ARG.hasOwnProperty(userIdProviderKey)) {
325
339
  switch (userIdProviderKey) {
340
+ case 'merkleId':
341
+ queryParams[key] = userIdObjectOrValue.id;
342
+ break;
326
343
  case 'flocId':
327
344
  queryParams[key] = userIdObjectOrValue.id;
328
345
  break;
@@ -333,7 +350,7 @@ function appendUserIdsToQueryParams(queryParams, userIds) {
333
350
  queryParams[key] = userIdObjectOrValue.lipbid;
334
351
  if (Array.isArray(userIdObjectOrValue.segments) && userIdObjectOrValue.segments.length > 0) {
335
352
  const liveIntentSegments = 'liveintent:' + userIdObjectOrValue.segments.join('|')
336
- queryParams.sm = `${queryParams.sm ? queryParams.sm + encodeURIComponent(',') : ''}${encodeURIComponent(liveIntentSegments)}`;
353
+ queryParams.sm = `${queryParams.sm ? queryParams.sm + ',' : ''}${liveIntentSegments}`;
337
354
  }
338
355
  break;
339
356
  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,