prebid.js 6.4.0 → 6.8.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 (147) hide show
  1. package/integrationExamples/gpt/amp/creative.html +11 -33
  2. package/integrationExamples/gpt/x-domain/creative.html +53 -26
  3. package/modules/.submodules.json +2 -1
  4. package/modules/adagioBidAdapter.js +0 -8
  5. package/modules/adagioBidAdapter.md +1 -1
  6. package/modules/adbookpspBidAdapter.js +27 -10
  7. package/modules/adhashBidAdapter.js +3 -3
  8. package/modules/adkernelBidAdapter.js +2 -1
  9. package/modules/admanBidAdapter.js +10 -4
  10. package/modules/adomikAnalyticsAdapter.js +23 -11
  11. package/modules/adqueryIdSystem.js +103 -0
  12. package/modules/adqueryIdSystem.md +35 -0
  13. package/modules/adyoulikeBidAdapter.js +13 -9
  14. package/modules/appnexusBidAdapter.js +11 -0
  15. package/modules/bliinkBidAdapter.js +3 -2
  16. package/modules/brandmetricsRtdProvider.js +168 -0
  17. package/modules/brandmetricsRtdProvider.md +40 -0
  18. package/modules/colossussspBidAdapter.js +12 -8
  19. package/modules/colossussspBidAdapter.md +15 -1
  20. package/modules/compassBidAdapter.js +10 -3
  21. package/modules/consentManagement.js +7 -1
  22. package/modules/consumableBidAdapter.md +1 -1
  23. package/modules/criteoBidAdapter.js +10 -1
  24. package/modules/criteoIdSystem.js +29 -7
  25. package/modules/currency.js +26 -1
  26. package/modules/displayioBidAdapter.js +157 -0
  27. package/modules/displayioBidAdapter.md +148 -0
  28. package/modules/docereeBidAdapter.js +10 -1
  29. package/modules/docereeBidAdapter.md +2 -0
  30. package/modules/e_volutionBidAdapter.js +158 -0
  31. package/modules/glimpseBidAdapter.js +66 -44
  32. package/modules/gnetBidAdapter.js +3 -3
  33. package/modules/gnetBidAdapter.md +4 -4
  34. package/modules/gptPreAuction.js +55 -7
  35. package/modules/gumgumBidAdapter.js +56 -42
  36. package/modules/idImportLibrary.js +45 -8
  37. package/modules/idImportLibrary.md +4 -0
  38. package/modules/improvedigitalBidAdapter.js +24 -2
  39. package/modules/interactiveOffersBidAdapter.js +9 -6
  40. package/modules/ixBidAdapter.js +29 -12
  41. package/modules/jwplayerRtdProvider.js +71 -6
  42. package/modules/jwplayerRtdProvider.md +27 -11
  43. package/modules/kargoBidAdapter.js +2 -2
  44. package/modules/limelightDigitalBidAdapter.js +2 -1
  45. package/modules/livewrappedAnalyticsAdapter.js +3 -1
  46. package/modules/loglyliftBidAdapter.js +79 -0
  47. package/modules/loglyliftBidAdapter.md +55 -0
  48. package/modules/nextMillenniumBidAdapter.js +3 -1
  49. package/modules/oguryBidAdapter.js +9 -2
  50. package/modules/onetagBidAdapter.js +4 -2
  51. package/modules/optimeraRtdProvider.js +8 -1
  52. package/modules/ozoneBidAdapter.js +21 -64
  53. package/modules/pilotxBidAdapter.js +147 -0
  54. package/modules/pilotxBidAdapter.md +50 -0
  55. package/modules/proxistoreBidAdapter.js +0 -2
  56. package/modules/pubmaticAnalyticsAdapter.js +16 -0
  57. package/modules/richaudienceBidAdapter.js +3 -2
  58. package/modules/riseBidAdapter.js +1 -1
  59. package/modules/rtbhouseBidAdapter.js +14 -4
  60. package/modules/rtdModule/index.js +14 -15
  61. package/modules/rubiconAnalyticsAdapter.js +3 -2
  62. package/modules/seedingAllianceBidAdapter.js +3 -3
  63. package/modules/sharethroughBidAdapter.js +12 -17
  64. package/modules/showheroes-bsBidAdapter.js +13 -2
  65. package/modules/sovrnBidAdapter.js +93 -18
  66. package/modules/sovrnBidAdapter.md +80 -2
  67. package/modules/synacormediaBidAdapter.js +31 -10
  68. package/modules/tappxBidAdapter.js +8 -5
  69. package/modules/teadsBidAdapter.js +1 -2
  70. package/modules/undertoneBidAdapter.js +17 -1
  71. package/modules/userId/eids.js +7 -1
  72. package/modules/userId/userId.md +8 -0
  73. package/modules/viewability.js +177 -0
  74. package/modules/viewability.md +87 -0
  75. package/modules/welectBidAdapter.js +106 -0
  76. package/modules/yahoosspBidAdapter.js +2 -0
  77. package/modules/yieldmoBidAdapter.js +23 -5
  78. package/modules/zeta_global_sspAnalyticsAdapter.js +97 -0
  79. package/modules/zeta_global_sspAnalyticsAdapter.md +24 -0
  80. package/package.json +1 -1
  81. package/src/adRendering.js +38 -0
  82. package/src/auction.js +44 -9
  83. package/src/config.js +27 -3
  84. package/src/hook.js +5 -1
  85. package/src/prebid.js +21 -21
  86. package/src/secureCreatives.js +114 -44
  87. package/src/utils.js +25 -4
  88. package/test/helpers/syncPromise.js +71 -0
  89. package/test/spec/auctionmanager_spec.js +148 -16
  90. package/test/spec/config_spec.js +279 -0
  91. package/test/spec/modules/adagioBidAdapter_spec.js +0 -10
  92. package/test/spec/modules/adbookpspBidAdapter_spec.js +17 -3
  93. package/test/spec/modules/adhashBidAdapter_spec.js +2 -2
  94. package/test/spec/modules/admanBidAdapter_spec.js +2 -2
  95. package/test/spec/modules/adomikAnalyticsAdapter_spec.js +3 -1
  96. package/test/spec/modules/adqueryIdSystem_spec.js +74 -0
  97. package/test/spec/modules/adyoulikeBidAdapter_spec.js +49 -0
  98. package/test/spec/modules/appnexusBidAdapter_spec.js +27 -0
  99. package/test/spec/modules/bliinkBidAdapter_spec.js +2 -0
  100. package/test/spec/modules/brandmetricsRtdProvider_spec.js +191 -0
  101. package/test/spec/modules/colossussspBidAdapter_spec.js +5 -2
  102. package/test/spec/modules/compassBidAdapter_spec.js +1 -0
  103. package/test/spec/modules/consentManagement_spec.js +20 -0
  104. package/test/spec/modules/criteoBidAdapter_spec.js +21 -0
  105. package/test/spec/modules/criteoIdSystem_spec.js +6 -3
  106. package/test/spec/modules/currency_spec.js +21 -6
  107. package/test/spec/modules/displayioBidAdapter_spec.js +239 -0
  108. package/test/spec/modules/docereeBidAdapter_spec.js +9 -1
  109. package/test/spec/modules/e_volutionBidAdapter_spec.js +242 -0
  110. package/test/spec/modules/eids_spec.js +15 -0
  111. package/test/spec/modules/glimpseBidAdapter_spec.js +0 -18
  112. package/test/spec/modules/gnetBidAdapter_spec.js +6 -6
  113. package/test/spec/modules/gptPreAuction_spec.js +177 -2
  114. package/test/spec/modules/gumgumBidAdapter_spec.js +46 -0
  115. package/test/spec/modules/idImportLibrary_spec.js +197 -10
  116. package/test/spec/modules/improvedigitalBidAdapter_spec.js +42 -0
  117. package/test/spec/modules/ixBidAdapter_spec.js +104 -62
  118. package/test/spec/modules/jwplayerRtdProvider_spec.js +195 -2
  119. package/test/spec/modules/kargoBidAdapter_spec.js +1 -1
  120. package/test/spec/modules/limelightDigitalBidAdapter_spec.js +75 -17
  121. package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +22 -0
  122. package/test/spec/modules/loglyliftBidAdapter_spec.js +172 -0
  123. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +1 -1
  124. package/test/spec/modules/oguryBidAdapter_spec.js +10 -2
  125. package/test/spec/modules/optimeraRtdProvider_spec.js +14 -1
  126. package/test/spec/modules/ozoneBidAdapter_spec.js +43 -31
  127. package/test/spec/modules/pilotxBidAdapter_spec.js +244 -0
  128. package/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +13 -1
  129. package/test/spec/modules/realTimeDataModule_spec.js +67 -5
  130. package/test/spec/modules/richaudienceBidAdapter_spec.js +40 -0
  131. package/test/spec/modules/riseBidAdapter_spec.js +1 -1
  132. package/test/spec/modules/rtbhouseBidAdapter_spec.js +20 -0
  133. package/test/spec/modules/rubiconAnalyticsAdapter_spec.js +30 -0
  134. package/test/spec/modules/sharethroughBidAdapter_spec.js +91 -6
  135. package/test/spec/modules/showheroes-bsBidAdapter_spec.js +2 -0
  136. package/test/spec/modules/sovrnBidAdapter_spec.js +413 -333
  137. package/test/spec/modules/synacormediaBidAdapter_spec.js +70 -0
  138. package/test/spec/modules/tappxBidAdapter_spec.js +0 -19
  139. package/test/spec/modules/teadsBidAdapter_spec.js +14 -59
  140. package/test/spec/modules/undertoneBidAdapter_spec.js +55 -2
  141. package/test/spec/modules/userId_spec.js +68 -19
  142. package/test/spec/modules/viewability_spec.js +280 -0
  143. package/test/spec/modules/welectBidAdapter_spec.js +211 -0
  144. package/test/spec/modules/yahoosspBidAdapter_spec.js +10 -0
  145. package/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js +427 -0
  146. package/test/spec/unit/pbjs_api_spec.js +20 -2
  147. package/test/spec/unit/secureCreatives_spec.js +85 -0
@@ -17,32 +17,48 @@ const TIME_TO_LIVE = 60
17
17
  const DELAY_REQUEST_TIME = 1800000; // setting to 30 mins
18
18
 
19
19
  let invalidRequestIds = {};
20
- let browserParams = {};
21
20
  let pageViewId = null;
22
21
 
23
22
  // TODO: potential 0 values for browserParams sent to ad server
24
23
  function _getBrowserParams(topWindowUrl) {
25
- let topWindow
26
- let topScreen
27
- let topUrl
28
- let ggad
29
- let ns
30
- function getNetworkSpeed() {
31
- const connection = window.navigator && (window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection)
32
- const Mbps = connection && (connection.downlink || connection.bandwidth)
33
- return Mbps ? Math.round(Mbps * 1024) : null
24
+ const paramRegex = paramName => new RegExp(`[?#&](${paramName}=(.*?))($|&)`, 'i');
25
+
26
+ let browserParams = {};
27
+ let topWindow;
28
+ let topScreen;
29
+ let topUrl;
30
+ let ggad;
31
+ let ggdeal;
32
+ let ns;
33
+
34
+ function getNetworkSpeed () {
35
+ const connection = window.navigator && (window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection);
36
+ const Mbps = connection && (connection.downlink || connection.bandwidth);
37
+ return Mbps ? Math.round(Mbps * 1024) : null;
34
38
  }
35
- function getOgURL() {
36
- let ogURL = ''
37
- const ogURLSelector = "meta[property='og:url']"
38
- const head = document && document.getElementsByTagName('head')[0]
39
- const ogURLElement = head.querySelector(ogURLSelector)
40
- ogURL = ogURLElement ? ogURLElement.content : null
41
- return ogURL
39
+
40
+ function getOgURL () {
41
+ let ogURL = '';
42
+ const ogURLSelector = "meta[property='og:url']";
43
+ const head = document && document.getElementsByTagName('head')[0];
44
+ const ogURLElement = head.querySelector(ogURLSelector);
45
+ ogURL = ogURLElement ? ogURLElement.content : null;
46
+ return ogURL;
42
47
  }
43
- if (browserParams.vw) {
44
- // we've already initialized browserParams, just return it.
45
- return browserParams
48
+
49
+ function stripGGParams (url) {
50
+ const params = [
51
+ 'ggad',
52
+ 'ggdeal'
53
+ ];
54
+
55
+ return params.reduce((result, param) => {
56
+ const matches = url.match(paramRegex(param));
57
+ if (!matches) return result;
58
+ matches[1] && (result = result.replace(matches[1], ''));
59
+ matches[3] && (result = result.replace(matches[3], ''));
60
+ return result;
61
+ }, url);
46
62
  }
47
63
 
48
64
  try {
@@ -51,7 +67,7 @@ function _getBrowserParams(topWindowUrl) {
51
67
  topUrl = topWindowUrl || '';
52
68
  } catch (error) {
53
69
  logError(error);
54
- return browserParams
70
+ return browserParams;
55
71
  }
56
72
 
57
73
  browserParams = {
@@ -59,23 +75,25 @@ function _getBrowserParams(topWindowUrl) {
59
75
  vh: topWindow.innerHeight,
60
76
  sw: topScreen.width,
61
77
  sh: topScreen.height,
62
- pu: topUrl,
78
+ pu: stripGGParams(topUrl),
63
79
  ce: storage.cookiesAreEnabled(),
64
80
  dpr: topWindow.devicePixelRatio || 1,
65
81
  jcsi: JSON.stringify(JCSI),
66
82
  ogu: getOgURL()
67
- }
83
+ };
68
84
 
69
- ns = getNetworkSpeed()
85
+ ns = getNetworkSpeed();
70
86
  if (ns) {
71
- browserParams.ns = ns
87
+ browserParams.ns = ns;
72
88
  }
73
89
 
74
- ggad = (topUrl.match(/#ggad=(\w+)$/) || [0, 0])[1]
75
- if (ggad) {
76
- browserParams[isNaN(ggad) ? 'eAdBuyId' : 'adBuyId'] = ggad
77
- }
78
- return browserParams
90
+ ggad = (topUrl.match(paramRegex('ggad')) || [0, 0, 0])[2];
91
+ if (ggad) browserParams[isNaN(ggad) ? 'eAdBuyId' : 'adBuyId'] = ggad;
92
+
93
+ ggdeal = (topUrl.match(paramRegex('ggdeal')) || [0, 0, 0])[2];
94
+ if (ggdeal) browserParams.ggdeal = ggdeal;
95
+
96
+ return browserParams;
79
97
  }
80
98
 
81
99
  function getWrapperCode(wrapper, data) {
@@ -291,17 +309,17 @@ function buildRequests(validBidRequests, bidderRequest) {
291
309
  } = bidRequest;
292
310
  const { currency, floor } = _getFloor(mediaTypes, params.bidfloor, bidRequest);
293
311
  const eids = getEids(userId);
312
+ const gpid = deepAccess(ortb2Imp, 'ext.data.pbadslot') || deepAccess(ortb2Imp, 'ext.data.adserver.adslot');
294
313
  let sizes = [1, 1];
295
314
  let data = {};
296
- let gpid = '';
297
315
 
298
316
  const date = new Date();
299
317
  const lt = date.getTime();
300
318
  const to = date.getTimezoneOffset();
301
- if (to) {
302
- lt && (data.lt = lt);
303
- data.to = to;
304
- }
319
+
320
+ // ADTS-174 Removed unnecessary checks to fix failing test
321
+ data.lt = lt;
322
+ data.to = to;
305
323
 
306
324
  // ADTS-169 add adUnitCode to requests
307
325
  if (adUnitCode) data.aun = adUnitCode
@@ -309,12 +327,8 @@ function buildRequests(validBidRequests, bidderRequest) {
309
327
  // ADTS-134 Retrieve ID envelopes
310
328
  for (const eid in eids) data[eid] = eids[eid];
311
329
 
312
- // ADJS-1024 & ADSS-1297
313
- if (deepAccess(ortb2Imp, 'ext.data.pbadslot')) {
314
- gpid = deepAccess(ortb2Imp, 'ext.data.pbadslot')
315
- } else if (deepAccess(ortb2Imp, 'ext.data.adserver.name')) {
316
- gpid = ortb2Imp.ext.data.adserver.adslot
317
- }
330
+ // ADJS-1024 & ADSS-1297 & ADTS-175
331
+ gpid && (data.gpid = gpid);
318
332
 
319
333
  if (mediaTypes.banner) {
320
334
  sizes = mediaTypes.banner.sizes;
@@ -384,7 +398,7 @@ function buildRequests(validBidRequests, bidderRequest) {
384
398
  sizes,
385
399
  url: BID_ENDPOINT,
386
400
  method: 'GET',
387
- data: Object.assign(data, _getBrowserParams(topWindowUrl), _getDigiTrustQueryParams(userId), { gpid })
401
+ data: Object.assign(data, _getBrowserParams(topWindowUrl), _getDigiTrustQueryParams(userId))
388
402
  })
389
403
  });
390
404
  return bids;
@@ -9,6 +9,7 @@ let conf;
9
9
  const LOG_PRE_FIX = 'ID-Library: ';
10
10
  const CONF_DEFAULT_OBSERVER_DEBOUNCE_MS = 250;
11
11
  const CONF_DEFAULT_FULL_BODY_SCAN = false;
12
+ const CONF_DEFAULT_INPUT_SCAN = false;
12
13
  const OBSERVER_CONFIG = {
13
14
  subtree: true,
14
15
  attributes: true,
@@ -78,7 +79,13 @@ function targetAction(mutations, observer) {
78
79
  }
79
80
  }
80
81
 
81
- function addInputElementsElementListner(conf) {
82
+ function addInputElementsElementListner() {
83
+ if (doesInputElementsHaveEmail()) {
84
+ _logInfo('Email found in input elements ' + email);
85
+ _logInfo('Post data on email found in target without');
86
+ postData();
87
+ return;
88
+ }
82
89
  _logInfo('Adding input element listeners');
83
90
  const inputs = document.querySelectorAll('input[type=text], input[type=email]');
84
91
 
@@ -89,6 +96,19 @@ function addInputElementsElementListner(conf) {
89
96
  }
90
97
  }
91
98
 
99
+ function addFormInputElementsElementListner(id) {
100
+ _logInfo('Adding input element listeners');
101
+ if (doesFormInputElementsHaveEmail(id)) {
102
+ _logInfo('Email found in input elements ' + email);
103
+ postData();
104
+ return;
105
+ }
106
+ _logInfo('Adding input element listeners');
107
+ const input = document.getElementById(id);
108
+ input.addEventListener('change', event => processInputChange(event));
109
+ input.addEventListener('blur', event => processInputChange(event));
110
+ }
111
+
92
112
  function removeInputElementsElementListner() {
93
113
  _logInfo('Removing input element listeners');
94
114
  const inputs = document.querySelectorAll('input[type=text], input[type=email]');
@@ -149,12 +169,6 @@ function handleTargetElement() {
149
169
  }
150
170
 
151
171
  function handleBodyElements() {
152
- if (doesInputElementsHaveEmail()) {
153
- _logInfo('Email found in input elements ' + email);
154
- _logInfo('Post data on email found in target without');
155
- postData();
156
- return;
157
- }
158
172
  email = getEmail(document.body.innerHTML);
159
173
  if (email !== null) {
160
174
  _logInfo('Email found in body ' + email);
@@ -162,7 +176,7 @@ function handleBodyElements() {
162
176
  postData();
163
177
  return;
164
178
  }
165
- addInputElementsElementListner();
179
+
166
180
  if (conf.fullscan === true) {
167
181
  const bodyObserver = new MutationObserver(debounce(bodyAction, conf.debounce, false));
168
182
  bodyObserver.observe(document.body, OBSERVER_CONFIG);
@@ -182,6 +196,17 @@ function doesInputElementsHaveEmail() {
182
196
  return false;
183
197
  }
184
198
 
199
+ function doesFormInputElementsHaveEmail(formElementId) {
200
+ const input = document.getElementById(formElementId);
201
+ if (input) {
202
+ email = getEmail(input.value);
203
+ if (email !== null) {
204
+ return true;
205
+ }
206
+ }
207
+ return false;
208
+ }
209
+
185
210
  function syncCallback() {
186
211
  return {
187
212
  success: function () {
@@ -213,6 +238,10 @@ function associateIds() {
213
238
  if (window.MutationObserver || window.WebKitMutationObserver) {
214
239
  if (conf.target) {
215
240
  handleTargetElement();
241
+ } else if (conf.formElementId) {
242
+ addFormInputElementsElementListner(conf.formElementId);
243
+ } else if (conf.inputscan) {
244
+ addInputElementsElementListner();
216
245
  } else {
217
246
  handleBodyElements();
218
247
  }
@@ -236,6 +265,14 @@ export function setConfig(config) {
236
265
  config.fullscan = CONF_DEFAULT_FULL_BODY_SCAN;
237
266
  _logInfo('Set default fullscan ' + CONF_DEFAULT_FULL_BODY_SCAN);
238
267
  }
268
+ if (typeof config.inputscan !== 'boolean') {
269
+ config.inputscan = CONF_DEFAULT_INPUT_SCAN;
270
+ _logInfo('Set default input scan ' + CONF_DEFAULT_INPUT_SCAN);
271
+ }
272
+
273
+ if (typeof config.formElementId == 'string') {
274
+ _logInfo('Looking for formElementId ' + config.formElementId);
275
+ }
239
276
  conf = config;
240
277
  associateIds();
241
278
  }
@@ -8,6 +8,8 @@
8
8
  | `url` | Yes | String | N/A | URL endpoint used to post the hashed email and user IDs. |
9
9
  | `debounce` | No | Number | 250 | Time in milliseconds before the email and IDs are fetched. |
10
10
  | `fullscan` | No | Boolean | false | Enable/disable a full page body scan to get email. |
11
+ | `formElementId` | No | String | N/A | ID attribute of the input (type=text/email) from which the email can be read. |
12
+ | `inputscan` | No | Boolean | N/A | Enable/disable a input element (type=text/email) scan to get email. |
11
13
 
12
14
  ## Example
13
15
 
@@ -18,5 +20,7 @@ pbjs.setConfig({
18
20
  url: 'https://example.com',
19
21
  debounce: 250,
20
22
  fullscan: false,
23
+ inputscan: false,
24
+ formElementId: "userid"
21
25
  },
22
26
  });
@@ -1,4 +1,4 @@
1
- import { deepSetValue, logError, _each, getBidRequest, isNumber, isArray, deepAccess, isFn, isPlainObject, logWarn, getBidIdParameter, getUniqueIdentifierStr, isEmpty, isInteger } from '../src/utils.js';
1
+ import { deepSetValue, logError, _each, getBidRequest, isNumber, isArray, deepAccess, isFn, isPlainObject, logWarn, getBidIdParameter, getUniqueIdentifierStr, isEmpty, isInteger, isStr } from '../src/utils.js';
2
2
  import { registerBidder } from '../src/adapters/bidderFactory.js';
3
3
  import { config } from '../src/config.js';
4
4
  import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
@@ -11,7 +11,7 @@ const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js
11
11
  const VIDEO_TARGETING = ['skip', 'skipmin', 'skipafter'];
12
12
 
13
13
  export const spec = {
14
- version: '7.5.0',
14
+ version: '7.6.0',
15
15
  code: BIDDER_CODE,
16
16
  gvlid: 253,
17
17
  aliases: ['id'],
@@ -73,6 +73,22 @@ export const spec = {
73
73
  requestParameters.referrer = bidderRequest.refererInfo.referer;
74
74
  }
75
75
 
76
+ // Adding first party data
77
+ const site = config.getConfig('ortb2.site');
78
+ if (site) {
79
+ const pageCategory = site.pagecat || site.cat;
80
+ if (pageCategory && isArray(pageCategory)) {
81
+ requestParameters.pagecat = pageCategory.filter((category) => {
82
+ return category && isStr(category)
83
+ });
84
+ }
85
+ const genre = deepAccess(site, 'content.genre');
86
+ if (genre && isStr(genre)) {
87
+ requestParameters.genre = genre;
88
+ }
89
+ }
90
+ // End of adding first party data
91
+
76
92
  requestParameters.schain = bidRequests[0].schain;
77
93
 
78
94
  if (bidRequests[0].userId) {
@@ -621,6 +637,12 @@ export function ImproveDigitalAdServerJSClient(endPoint) {
621
637
  if (requestParameters.schain) {
622
638
  impressionBidRequestObject.schain = requestParameters.schain;
623
639
  }
640
+ if (requestParameters.pagecat) {
641
+ impressionBidRequestObject.pagecat = requestParameters.pagecat;
642
+ }
643
+ if (requestParameters.genre) {
644
+ impressionBidRequestObject.genre = requestParameters.genre;
645
+ }
624
646
  if (requestParameters.user) {
625
647
  impressionBidRequestObject.user = requestParameters.user;
626
648
  }
@@ -83,7 +83,8 @@ function parseRequestPrebidjsToOpenRTB(prebidRequest) {
83
83
  let openRTBRequest = JSON.parse(JSON.stringify(DEFAULT['OpenRTBBidRequest']));
84
84
  openRTBRequest.id = prebidRequest.auctionId;
85
85
  openRTBRequest.ext = {
86
- auctionstart: Date.now()
86
+ refererInfo: prebidRequest.refererInfo,
87
+ auctionId: prebidRequest.auctionId
87
88
  };
88
89
 
89
90
  openRTBRequest.site = JSON.parse(JSON.stringify(DEFAULT['OpenRTBBidRequestSite']));
@@ -111,15 +112,17 @@ function parseRequestPrebidjsToOpenRTB(prebidRequest) {
111
112
  openRTBRequest.user = JSON.parse(JSON.stringify(DEFAULT['OpenRTBBidRequestUser']));
112
113
 
113
114
  openRTBRequest.imp = [];
114
- prebidRequest.bids.forEach(function(bid, impId) {
115
- impId++;
115
+ prebidRequest.bids.forEach(function(bid) {
116
116
  if (!ret.partnerId) {
117
117
  ret.partnerId = bid.params.partnerId;
118
118
  }
119
119
  let imp = JSON.parse(JSON.stringify(DEFAULT['OpenRTBBidRequestImp']));
120
- imp.id = impId;
120
+ imp.id = bid.bidId;
121
121
  imp.secure = secure;
122
- imp.tagid = bid.bidId;
122
+ imp.tagid = bid.adUnitCode;
123
+ imp.ext = {
124
+ rawdata: bid
125
+ };
123
126
 
124
127
  openRTBRequest.site.publisher.id = openRTBRequest.site.publisher.id || 0;
125
128
  openRTBRequest.tmax = openRTBRequest.tmax || bid.params.tmax || 0;
@@ -152,7 +155,7 @@ function parseResponseOpenRTBToPrebidjs(openRTBResponse) {
152
155
  if (seatbid.bid && seatbid.bid.forEach) {
153
156
  seatbid.bid.forEach(function(bid) {
154
157
  let prebid = JSON.parse(JSON.stringify(DEFAULT['PrebidBid']));
155
- prebid.requestId = bid.ext.tagid;
158
+ prebid.requestId = bid.impid;
156
159
  prebid.ad = bid.adm;
157
160
  prebid.creativeId = bid.crid;
158
161
  prebid.cpm = bid.price;
@@ -53,7 +53,12 @@ const SOURCE_RTI_MAPPING = {
53
53
  'neustar.biz': 'fabrickId',
54
54
  'zeotap.com': 'zeotapIdPlus',
55
55
  'uidapi.com': 'UID2',
56
- 'adserver.org': 'TDID'
56
+ 'adserver.org': 'TDID',
57
+ 'id5-sync.com': '', // ID5 Universal ID, configured as id5Id
58
+ 'crwdcntrl.net': '', // Lotame Panorama ID, lotamePanoramaId
59
+ 'epsilon.com': '', // Publisher Link, publinkId
60
+ 'audigent.com': '', // Halo ID from Audigent, haloId
61
+ 'pubcid.org': '' // SharedID, pubcid
57
62
  };
58
63
  const PROVIDERS = [
59
64
  'britepoolid',
@@ -69,7 +74,8 @@ const PROVIDERS = [
69
74
  'quantcastId',
70
75
  'pubcid',
71
76
  'TDID',
72
- 'flocId'
77
+ 'flocId',
78
+ 'pubProvidedId'
73
79
  ];
74
80
  const REQUIRED_VIDEO_PARAMS = ['mimes', 'minduration', 'maxduration']; // note: protocol/protocols is also reqd
75
81
  const VIDEO_PARAMS_ALLOW_LIST = [
@@ -194,7 +200,7 @@ function bidToImp(bid) {
194
200
  imp.id = bid.bidId;
195
201
 
196
202
  imp.ext = {};
197
- imp.ext.siteID = bid.params.siteId;
203
+ imp.ext.siteID = bid.params.siteId.toString();
198
204
 
199
205
  if (bid.params.hasOwnProperty('id') &&
200
206
  (typeof bid.params.id === 'string' || typeof bid.params.id === 'number')) {
@@ -444,16 +450,19 @@ function getEidInfo(allEids, flocData) {
444
450
  let seenSources = {};
445
451
  if (isArray(allEids)) {
446
452
  for (const eid of allEids) {
447
- if (SOURCE_RTI_MAPPING[eid.source] && deepAccess(eid, 'uids.0')) {
453
+ if (SOURCE_RTI_MAPPING.hasOwnProperty(eid.source) && deepAccess(eid, 'uids.0')) {
448
454
  seenSources[eid.source] = true;
449
- eid.uids[0].ext = {
450
- rtiPartner: SOURCE_RTI_MAPPING[eid.source]
451
- };
455
+ if (SOURCE_RTI_MAPPING[eid.source] != '') {
456
+ eid.uids[0].ext = {
457
+ rtiPartner: SOURCE_RTI_MAPPING[eid.source]
458
+ };
459
+ }
452
460
  delete eid.uids[0].atype;
453
461
  toSend.push(eid);
454
462
  }
455
463
  }
456
464
  }
465
+
457
466
  const isValidFlocId = flocData && flocData.id && flocData.version;
458
467
  if (isValidFlocId) {
459
468
  const flocEid = {
@@ -466,6 +475,7 @@ function getEidInfo(allEids, flocData) {
466
475
 
467
476
  return { toSend, seenSources };
468
477
  }
478
+
469
479
  /**
470
480
  * Builds a request object to be sent to the ad server based on bid requests.
471
481
  *
@@ -680,6 +690,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
680
690
 
681
691
  if (impressionObjects.length && BANNER in impressionObjects[0]) {
682
692
  const { id, banner: { topframe }, ext } = impressionObjects[0];
693
+ const gpid = impressions[transactionIds[adUnitIndex]].gpid;
683
694
  const _bannerImpression = {
684
695
  id,
685
696
  banner: {
@@ -688,10 +699,10 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
688
699
  },
689
700
  }
690
701
 
691
- if (ext.dfp_ad_unit_code) {
692
- _bannerImpression.ext = {
693
- dfp_ad_unit_code: ext.dfp_ad_unit_code
694
- }
702
+ if (ext.dfp_ad_unit_code || gpid) {
703
+ _bannerImpression.ext = {};
704
+ _bannerImpression.ext.dfp_ad_unit_code = ext.dfp_ad_unit_code;
705
+ _bannerImpression.ext.gpid = gpid;
695
706
  }
696
707
 
697
708
  if ('bidfloor' in impressionObjects[0]) {
@@ -911,6 +922,7 @@ function createBannerImps(validBidRequest, missingBannerSizes, bannerImps) {
911
922
  bannerImps[validBidRequest.transactionId].ixImps = []
912
923
  }
913
924
  bannerImps[validBidRequest.transactionId].ixImps.push(imp);
925
+ bannerImps[validBidRequest.transactionId].gpid = deepAccess(validBidRequest, 'ortb2Imp.ext.gpid');
914
926
  }
915
927
 
916
928
  if (ixConfig.hasOwnProperty('detectMissingSizes') && ixConfig.detectMissingSizes) {
@@ -1186,7 +1198,12 @@ export const spec = {
1186
1198
  }
1187
1199
 
1188
1200
  if (typeof bid.params.siteId !== 'string' && typeof bid.params.siteId !== 'number') {
1189
- logError('IX Bid Adapter: siteId must be string or number value.', { bidder: BIDDER_CODE, code: ERROR_CODES.SITE_ID_INVALID_VALUE });
1201
+ logError('IX Bid Adapter: siteId must be string or number type.', { bidder: BIDDER_CODE, code: ERROR_CODES.SITE_ID_INVALID_VALUE });
1202
+ return false;
1203
+ }
1204
+
1205
+ if (typeof bid.params.siteId !== 'string' && isNaN(Number(bid.params.siteId))) {
1206
+ logError('IX Bid Adapter: siteId must valid value', { bidder: BIDDER_CODE, code: ERROR_CODES.SITE_ID_INVALID_VALUE });
1190
1207
  return false;
1191
1208
  }
1192
1209
 
@@ -155,8 +155,10 @@ export function enrichAdUnits(adUnits) {
155
155
  if (!vat) {
156
156
  return;
157
157
  }
158
+ const contentId = getContentId(vat.mediaID);
159
+ const contentData = getContentData(vat.segments);
158
160
  const targeting = formatTargetingResponse(vat);
159
- addTargetingToBids(adUnit.bids, targeting);
161
+ enrichBids(adUnit.bids, targeting, contentId, contentData);
160
162
  };
161
163
  loadVat(jwTargeting, onVatResponse);
162
164
  });
@@ -235,6 +237,9 @@ export function getVatFromPlayer(playerID, mediaID) {
235
237
  };
236
238
  }
237
239
 
240
+ /*
241
+ deprecated
242
+ */
238
243
  export function formatTargetingResponse(vat) {
239
244
  const { segments, mediaID } = vat;
240
245
  const targeting = {};
@@ -243,23 +248,83 @@ export function formatTargetingResponse(vat) {
243
248
  }
244
249
 
245
250
  if (mediaID) {
246
- const id = 'jw_' + mediaID;
247
251
  targeting.content = {
248
- id
252
+ id: getContentId(mediaID)
249
253
  }
250
254
  }
251
255
  return targeting;
252
256
  }
253
257
 
254
- function addTargetingToBids(bids, targeting) {
255
- if (!bids || !targeting) {
258
+ export function getContentId(mediaID) {
259
+ if (!mediaID) {
260
+ return;
261
+ }
262
+
263
+ return 'jw_' + mediaID;
264
+ }
265
+
266
+ export function getContentData(segments) {
267
+ if (!segments || !segments.length) {
268
+ return;
269
+ }
270
+
271
+ const formattedSegments = segments.reduce((convertedSegments, rawSegment) => {
272
+ convertedSegments.push({
273
+ id: rawSegment,
274
+ value: rawSegment
275
+ });
276
+ return convertedSegments;
277
+ }, []);
278
+
279
+ return {
280
+ name: 'jwplayer',
281
+ ext: {
282
+ segtax: 502
283
+ },
284
+ segment: formattedSegments
285
+ };
286
+ }
287
+
288
+ export function addOrtbSiteContent(bid, contentId, contentData) {
289
+ if (!contentId && !contentData) {
256
290
  return;
257
291
  }
258
292
 
259
- bids.forEach(bid => addTargetingToBid(bid, targeting));
293
+ let ortb2 = bid.ortb2 || {};
294
+ let site = ortb2.site = ortb2.site || {};
295
+ let content = site.content = site.content || {};
296
+
297
+ if (contentId) {
298
+ content.id = contentId;
299
+ }
300
+
301
+ if (contentData) {
302
+ const data = content.data = content.data || [];
303
+ data.push(contentData);
304
+ }
305
+
306
+ bid.ortb2 = ortb2;
260
307
  }
261
308
 
309
+ function enrichBids(bids, targeting, contentId, contentData) {
310
+ if (!bids) {
311
+ return;
312
+ }
313
+
314
+ bids.forEach(bid => {
315
+ addTargetingToBid(bid, targeting);
316
+ addOrtbSiteContent(bid, contentId, contentData);
317
+ });
318
+ }
319
+
320
+ /*
321
+ deprecated
322
+ */
262
323
  export function addTargetingToBid(bid, targeting) {
324
+ if (!targeting) {
325
+ return;
326
+ }
327
+
263
328
  const rtd = bid.rtd || {};
264
329
  const jwRtd = {};
265
330
  jwRtd[SUBMODULE_NAME] = Object.assign({}, rtd[SUBMODULE_NAME], { targeting });
@@ -81,20 +81,30 @@ realTimeData = {
81
81
  # Usage for Bid Adapters:
82
82
 
83
83
  Implement the `buildRequests` function. When it is called, the `bidRequests` param will be an array of bids.
84
- Each bid for which targeting information was found will conform to the following object structure:
84
+ Each bid for which targeting information was found will have a ortb2 param conforming to the [oRTB v2 object structure](https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf). The `ortb2` object will contain our proprietaty targeting segments in a format compliant with the [IAB's segment taxonomy structure](https://github.com/InteractiveAdvertisingBureau/openrtb/blob/master/extensions/community_extensions/segtax.md).
85
+
86
+ Example:
85
87
 
86
88
  ```javascript
87
89
  {
88
90
  adUnitCode: 'xyz',
89
91
  bidId: 'abc',
90
92
  ...,
91
- rtd: {
92
- jwplayer: {
93
- targeting: {
94
- segments: ['123', '456'],
95
- content: {
96
- id: 'jw_abc123'
97
- }
93
+ ortb2: {
94
+ site: {
95
+ content: {
96
+ id: 'jw_abc123',
97
+ data: [{
98
+ name: 'jwplayer',
99
+ ext: {
100
+ segtax: 502
101
+ },
102
+ segment: [{
103
+ id: '123'
104
+ }, {
105
+ id: '456'
106
+ }]
107
+ }]
98
108
  }
99
109
  }
100
110
  }
@@ -102,9 +112,15 @@ Each bid for which targeting information was found will conform to the following
102
112
  ```
103
113
 
104
114
  where:
105
- - `segments` is an array of jwpseg targeting segments, of type string.
106
- - `content` is an object containing metadata for the media. It may contain the following information:
107
- - `id` is a unique identifier for the specific media asset.
115
+ - `ortb2` is an object containing first party data
116
+ - `site` is an object containing page specific information
117
+ - `content` is an object containing metadata for the media. It may contain the following information:
118
+ - `id` is a unique identifier for the specific media asset
119
+ - `data` is an array containing segment taxonomy objects that have the following parameters:
120
+ - `name` is the `jwplayer` string indicating the provider name
121
+ - `ext.segtax` whose `502` value is the unique identifier for JW Player's proprietary taxonomy
122
+ - `segment` is an array containing the segment taxonomy values as an object where:
123
+ - `id` is the string representation of the data segment value.
108
124
 
109
125
  **Example:**
110
126
 
@@ -73,8 +73,8 @@ export const spec = {
73
73
  let meta;
74
74
  if (adUnit.metadata && adUnit.metadata.landingPageDomain) {
75
75
  meta = {
76
- clickUrl: adUnit.metadata.landingPageDomain,
77
- advertiserDomains: [adUnit.metadata.landingPageDomain]
76
+ clickUrl: adUnit.metadata.landingPageDomain[0],
77
+ advertiserDomains: adUnit.metadata.landingPageDomain
78
78
  };
79
79
  }
80
80
  bidResponses.push({
@@ -159,7 +159,8 @@ function buildPlacement(bidRequest) {
159
159
  }
160
160
  }),
161
161
  type: bidRequest.params.adUnitType.toUpperCase(),
162
- publisherId: bidRequest.params.publisherId
162
+ publisherId: bidRequest.params.publisherId,
163
+ userIdAsEids: bidRequest.userIdAsEids
163
164
  }
164
165
  }
165
166
  }