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
@@ -1,14 +1,14 @@
1
1
  # ID5 Universal ID
2
2
 
3
- The ID5 Universal ID is a shared, neutral identifier that publishers and ad tech platforms can use to recognise users even in environments where 3rd party cookies are not available. The ID5 Universal ID is designed to respect users' privacy choices and publishers’ preferences throughout the advertising value chain. For more information about the ID5 Universal ID and detailed integration docs, please visit [our documentation](https://support.id5.io/portal/en/kb/articles/prebid-js-user-id-module). We also recommend that you sign up for our [release notes](https://id5.io/universal-id/release-notes) to stay up-to-date with any changes to the implementation of the ID5 Universal ID in Prebid.
3
+ The ID5 ID is a shared, neutral identifier that publishers and ad tech platforms can use to recognise users even in environments where 3rd party cookies are not available. The ID5 ID is designed to respect users' privacy choices and publishers’ preferences throughout the advertising value chain. For more information about the ID5 ID and detailed integration docs, please visit [our documentation](https://support.id5.io/portal/en/kb/articles/prebid-js-user-id-module).
4
4
 
5
- ## ID5 Universal ID Registration
5
+ ## ID5 ID Registration
6
6
 
7
- The ID5 Universal ID is free to use, but requires a simple registration with ID5. Please visit [id5.io/universal-id](https://id5.io/universal-id) to sign up and request your ID5 Partner Number to get started.
7
+ The ID5 ID is free to use, but requires a simple registration with ID5. Please visit [our website](https://id5.io/solutions/#publishers) to sign up and request your ID5 Partner Number to get started.
8
8
 
9
- The ID5 privacy policy is at [https://www.id5.io/platform-privacy-policy](https://www.id5.io/platform-privacy-policy).
9
+ The ID5 privacy policy is at [https://id5.io/platform-privacy-policy](https://id5.io/platform-privacy-policy).
10
10
 
11
- ## ID5 Universal ID Configuration
11
+ ## ID5 ID Configuration
12
12
 
13
13
  First, make sure to add the ID5 submodule to your Prebid.js package with:
14
14
 
@@ -46,7 +46,7 @@ pbjs.setConfig({
46
46
  | Param under userSync.userIds[] | Scope | Type | Description | Example |
47
47
  | --- | --- | --- | --- | --- |
48
48
  | name | Required | String | The name of this module: `"id5Id"` | `"id5Id"` |
49
- | params | Required | Object | Details for the ID5 Universal ID. | |
49
+ | params | Required | Object | Details for the ID5 ID. | |
50
50
  | params.partner | Required | Number | This is the ID5 Partner Number obtained from registering with ID5. | `173` |
51
51
  | params.pd | Optional | String | Partner-supplied data used for linking ID5 IDs across domains. See [our documentation](https://support.id5.io/portal/en/kb/articles/passing-partner-data-to-id5) for details on generating the string. Omit the parameter or leave as an empty string if no data to supply | `"MT1iNTBjY..."` |
52
52
  | params.provider | Optional | String | An identifier provided by ID5 to technology partners who manage Prebid setups on behalf of publishers. Reach out to [ID5](mailto:prebid@id5.io) if you have questions about this parameter | `pubmatic-identity-hub` |
@@ -37,6 +37,34 @@ function setImDataInCookie(value) {
37
37
  );
38
38
  }
39
39
 
40
+ /**
41
+ * @param {string} bidderName
42
+ */
43
+ export function getBidderFunction(bidderName) {
44
+ const biddersFunction = {
45
+ ix: function (bid, data) {
46
+ if (data.im_segments && data.im_segments.length) {
47
+ config.setConfig({
48
+ ix: {firstPartyData: {im_segments: data.im_segments}},
49
+ });
50
+ }
51
+ return bid
52
+ },
53
+ pubmatic: function (bid, data) {
54
+ if (data.im_segments && data.im_segments.length) {
55
+ const dctr = deepAccess(bid, 'params.dctr');
56
+ deepSetValue(
57
+ bid,
58
+ 'params.dctr',
59
+ `${dctr ? dctr + '|' : ''}im_segments=${data.im_segments.join(',')}`
60
+ );
61
+ }
62
+ return bid
63
+ }
64
+ }
65
+ return biddersFunction[bidderName] || null;
66
+ }
67
+
40
68
  export function getCustomBidderFunction(config, bidder) {
41
69
  const overwriteFn = deepAccess(config, `params.overwrites.${bidder}`)
42
70
 
@@ -73,9 +101,12 @@ export function setRealTimeData(bidConfig, moduleConfig, data) {
73
101
 
74
102
  adUnits.forEach(adUnit => {
75
103
  adUnit.bids.forEach(bid => {
104
+ const bidderFunction = getBidderFunction(bid.bidder);
76
105
  const overwriteFunction = getCustomBidderFunction(moduleConfig, bid.bidder);
77
106
  if (overwriteFunction) {
78
107
  overwriteFunction(bid, data, utils, config);
108
+ } else if (bidderFunction) {
109
+ bidderFunction(bid, data);
79
110
  }
80
111
  })
81
112
  });
@@ -55,7 +55,11 @@ export const spec = {
55
55
  parallel: true
56
56
  }, validBidRequests[0].params);
57
57
 
58
- if (data.publisherId) {
58
+ if (validBidRequests[0].schain) {
59
+ data.rtb = {
60
+ schain: validBidRequests[0].schain
61
+ };
62
+ } else if (data.publisherId) {
59
63
  data.rtb = {
60
64
  schain: {
61
65
  ext: {
@@ -63,10 +67,10 @@ export const spec = {
63
67
  }
64
68
  }
65
69
  };
66
-
67
- delete data.publisherId;
68
70
  }
69
71
 
72
+ delete data.publisherId;
73
+
70
74
  data.keywords = data.keywords || [];
71
75
  const restrictions = [];
72
76
 
@@ -1,6 +1,9 @@
1
1
  import { deepAccess, parseGPTSingleSizeArray, inIframe, deepClone, logError, logWarn, isFn, contains, isInteger, isArray, deepSetValue, parseQueryStringParameters, isEmpty, mergeDeep, convertTypes } from '../src/utils.js';
2
2
  import { BANNER, VIDEO } from '../src/mediaTypes.js';
3
3
  import { config } from '../src/config.js';
4
+ import { EVENTS } from '../src/constants.json';
5
+ import { getStorageManager } from '../src/storageManager.js';
6
+ import events from '../src/events.js';
4
7
  import find from 'core-js-pure/features/array/find.js';
5
8
  import { registerBidder } from '../src/adapters/bidderFactory.js';
6
9
  import { INSTREAM, OUTSTREAM } from '../src/video.js';
@@ -20,15 +23,23 @@ const VIDEO_TIME_TO_LIVE = 3600; // 1hr
20
23
  const NET_REVENUE = true;
21
24
  const MAX_REQUEST_SIZE = 8000;
22
25
  const MAX_REQUEST_LIMIT = 4;
23
-
24
26
  const PRICE_TO_DOLLAR_FACTOR = {
25
27
  JPY: 1
26
28
  };
27
29
  const USER_SYNC_URL = 'https://js-sec.indexww.com/um/ixmatch.html';
28
30
  const RENDERER_URL = 'https://js-sec.indexww.com/htv/video-player.js';
29
31
  const FLOOR_SOURCE = { PBJS: 'p', IX: 'x' };
30
- // determines which eids we send and the rtiPartner field in ext
31
-
32
+ export const ERROR_CODES = {
33
+ BID_SIZE_INVALID_FORMAT: 1,
34
+ BID_SIZE_NOT_INCLUDED: 2,
35
+ PROPERTY_NOT_INCLUDED: 3,
36
+ SITE_ID_INVALID_VALUE: 4,
37
+ BID_FLOOR_INVALID_FORMAT: 5,
38
+ IX_FPD_EXCEEDS_MAX_SIZE: 6,
39
+ EXCEEDS_MAX_SIZE: 7,
40
+ PB_FPD_EXCEEDS_MAX_SIZE: 8,
41
+ VIDEO_DURATION_INVALID: 9
42
+ };
32
43
  const FIRST_PARTY_DATA = {
33
44
  SITE: [
34
45
  'id', 'name', 'domain', 'cat', 'sectioncat', 'pagecat', 'page', 'ref', 'search', 'mobile',
@@ -36,7 +47,6 @@ const FIRST_PARTY_DATA = {
36
47
  ],
37
48
  USER: ['id', 'buyeruid', 'yob', 'gender', 'keywords', 'customdata', 'geo', 'data', 'ext']
38
49
  };
39
-
40
50
  const SOURCE_RTI_MAPPING = {
41
51
  'liveramp.com': 'idl',
42
52
  'netid.de': 'NETID',
@@ -45,7 +55,6 @@ const SOURCE_RTI_MAPPING = {
45
55
  'uidapi.com': 'UID2',
46
56
  'adserver.org': 'TDID'
47
57
  };
48
-
49
58
  const PROVIDERS = [
50
59
  'britepoolid',
51
60
  'id5id',
@@ -62,9 +71,7 @@ const PROVIDERS = [
62
71
  'TDID',
63
72
  'flocId'
64
73
  ];
65
-
66
74
  const REQUIRED_VIDEO_PARAMS = ['mimes', 'minduration', 'maxduration']; // note: protocol/protocols is also reqd
67
-
68
75
  const VIDEO_PARAMS_ALLOW_LIST = [
69
76
  'mimes', 'minduration', 'maxduration', 'protocols', 'protocol',
70
77
  'startdelay', 'placement', 'linearity', 'skip', 'skipmin',
@@ -73,6 +80,17 @@ const VIDEO_PARAMS_ALLOW_LIST = [
73
80
  'delivery', 'pos', 'companionad', 'api', 'companiontype', 'ext',
74
81
  'playerSize', 'w', 'h'
75
82
  ];
83
+ const LOCAL_STORAGE_KEY = 'ixdiag';
84
+ let hasRegisteredHandler = false;
85
+ export const storage = getStorageManager(GLOBAL_VENDOR_ID, BIDDER_CODE);
86
+
87
+ // Possible values for bidResponse.seatBid[].bid[].mtype which indicates the type of the creative markup so that it can properly be associated with the right sub-object of the BidRequest.Imp.
88
+ const MEDIA_TYPES = {
89
+ Banner: 1,
90
+ Video: 2,
91
+ Audio: 3,
92
+ Native: 4
93
+ }
76
94
 
77
95
  /**
78
96
  * Transform valid bid request config object to banner impression object that will be sent to ad server.
@@ -125,7 +143,10 @@ function bidToVideoImp(bid) {
125
143
  }
126
144
 
127
145
  if (imp.video.minduration > imp.video.maxduration) {
128
- logError(`IX Bid Adapter: video minduration [${imp.video.minduration}] cannot be greater than video maxduration [${imp.video.maxduration}]`);
146
+ logError(
147
+ `IX Bid Adapter: video minduration [${imp.video.minduration}] cannot be greater than video maxduration [${imp.video.maxduration}]`,
148
+ { bidder: BIDDER_CODE, code: ERROR_CODES.VIDEO_DURATION_INVALID }
149
+ );
129
150
  return {};
130
151
  }
131
152
 
@@ -262,9 +283,14 @@ function parseBid(rawBid, currency, bidRequest) {
262
283
  bid.currency = currency;
263
284
  bid.creativeId = rawBid.hasOwnProperty('crid') ? rawBid.crid : '-';
264
285
 
265
- // in the event of a video
266
- if (deepAccess(rawBid, 'ext.vasturl')) {
286
+ if (rawBid.mtype == MEDIA_TYPES.Video) {
287
+ bid.vastXml = rawBid.adm
288
+ } else if (rawBid.ext && rawBid.ext.vasturl) {
267
289
  bid.vastUrl = rawBid.ext.vasturl
290
+ }
291
+
292
+ // in the event of a video
293
+ if ((rawBid.ext && rawBid.ext.vasturl) || rawBid.mtype == MEDIA_TYPES.Video) {
268
294
  bid.width = bidRequest.video.w;
269
295
  bid.height = bidRequest.video.h;
270
296
  bid.mediaType = VIDEO;
@@ -490,6 +516,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
490
516
  r.ext.ixdiag.msd = 0;
491
517
  r.ext.ixdiag.msi = 0;
492
518
  r.imp = [];
519
+ r.at = 1;
493
520
 
494
521
  // getting ixdiags for adunits of the video, outstream & multi format (MF) style
495
522
  let ixdiag = buildIXDiag(validBidRequests);
@@ -497,6 +524,13 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
497
524
  r.ext.ixdiag[key] = ixdiag[key];
498
525
  }
499
526
 
527
+ // Get cached errors stored in LocalStorage
528
+ const cachedErrors = getCachedErrors();
529
+
530
+ if (!isEmpty(cachedErrors)) {
531
+ r.ext.ixdiag.err = cachedErrors;
532
+ }
533
+
500
534
  // if an schain is provided, send it along
501
535
  if (validBidRequests[0].schain) {
502
536
  r.source = {
@@ -575,7 +609,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
575
609
  const baseRequestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(r) })}`.length;
576
610
 
577
611
  if (baseRequestSize > MAX_REQUEST_SIZE) {
578
- logError('ix bidder: Base request size has exceeded maximum request size.');
612
+ logError('IX Bid Adapter: Base request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.EXCEEDS_MAX_SIZE });
579
613
  return requests;
580
614
  }
581
615
 
@@ -605,7 +639,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
605
639
  }
606
640
  currentRequestSize += fpdRequestSize;
607
641
  } else {
608
- logError('ix bidder: IX config FPD request size has exceeded maximum request size.');
642
+ logError('IX Bid Adapter: IX config FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.IX_FPD_EXCEEDS_MAX_SIZE });
609
643
  }
610
644
  }
611
645
 
@@ -645,7 +679,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
645
679
  }
646
680
 
647
681
  if (impressionObjects.length && BANNER in impressionObjects[0]) {
648
- const { id, banner: { topframe } } = impressionObjects[0];
682
+ const { id, banner: { topframe }, ext } = impressionObjects[0];
649
683
  const _bannerImpression = {
650
684
  id,
651
685
  banner: {
@@ -654,6 +688,12 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
654
688
  },
655
689
  }
656
690
 
691
+ if (ext.dfp_ad_unit_code) {
692
+ _bannerImpression.ext = {
693
+ dfp_ad_unit_code: ext.dfp_ad_unit_code
694
+ }
695
+ }
696
+
657
697
  if ('bidfloor' in impressionObjects[0]) {
658
698
  _bannerImpression.bidfloor = impressionObjects[0].bidfloor;
659
699
  }
@@ -706,7 +746,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
706
746
  const fpdRequestSize = encodeURIComponent(JSON.stringify({ ...site, ...user })).length;
707
747
  currentRequestSize += fpdRequestSize;
708
748
  } else {
709
- logError('ix bidder: FPD request size has exceeded maximum request size.');
749
+ logError('IX Bid Adapter: FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.PB_FPD_EXCEEDS_MAX_SIZE });
710
750
  }
711
751
  }
712
752
 
@@ -939,10 +979,99 @@ function createMissingBannerImp(bid, imp, newSize) {
939
979
  }
940
980
 
941
981
  /**
982
+ * @typedef {Array[message: string, err: Object<bidder: string, code: number>]} ErrorData
983
+ * @property {string} message - The error message.
984
+ * @property {object} err - The error object.
985
+ * @property {string} err.bidder - The bidder of the error.
986
+ * @property {string} err.code - The error code.
987
+ */
988
+
989
+ /**
990
+ * Error Event handler that receives type and arguments in a data object.
991
+ *
992
+ * @param {ErrorData} data
993
+ */
994
+ function errorEventHandler(data) {
995
+ if (!storage.localStorageIsEnabled()) {
996
+ return;
997
+ }
998
+
999
+ let currentStorage;
1000
+
1001
+ try {
1002
+ currentStorage = JSON.parse(storage.getDataFromLocalStorage(LOCAL_STORAGE_KEY) || '{}');
1003
+ } catch (e) {
1004
+ logWarn('ix can not read ixdiag from localStorage.');
1005
+ }
1006
+
1007
+ const todayDate = new Date();
1008
+
1009
+ Object.keys(currentStorage).map((errorDate) => {
1010
+ const date = new Date(errorDate);
1011
+
1012
+ if (date.setDate(date.getDate() + 7) - todayDate < 0) {
1013
+ delete currentStorage[errorDate];
1014
+ }
1015
+ });
1016
+
1017
+ if (data.type === 'ERROR' && data.arguments && data.arguments[1] && data.arguments[1].bidder === BIDDER_CODE) {
1018
+ const todayString = todayDate.toISOString().slice(0, 10);
1019
+
1020
+ const errorCode = data.arguments[1].code;
1021
+
1022
+ if (errorCode) {
1023
+ currentStorage[todayString] = currentStorage[todayString] || {};
1024
+
1025
+ if (!Number(currentStorage[todayString][errorCode])) {
1026
+ currentStorage[todayString][errorCode] = 0;
1027
+ }
1028
+
1029
+ currentStorage[todayString][errorCode]++;
1030
+ };
1031
+ }
1032
+
1033
+ storage.setDataInLocalStorage(LOCAL_STORAGE_KEY, JSON.stringify(currentStorage));
1034
+ }
1035
+
1036
+ /**
1037
+ * Get ixdiag stored in LocalStorage and format to be added to request payload
1038
+ *
1039
+ * @returns {Object} Object with error codes and counts
1040
+ */
1041
+ function getCachedErrors() {
1042
+ if (!storage.localStorageIsEnabled()) {
1043
+ return;
1044
+ }
1045
+
1046
+ const errors = {};
1047
+ let currentStorage;
1048
+
1049
+ try {
1050
+ currentStorage = JSON.parse(storage.getDataFromLocalStorage(LOCAL_STORAGE_KEY) || '{}');
1051
+ } catch (e) {
1052
+ logError('ix can not read ixdiag from localStorage.');
1053
+ return null;
1054
+ }
1055
+
1056
+ Object.keys(currentStorage).forEach((date) => {
1057
+ Object.keys(currentStorage[date]).forEach((code) => {
1058
+ if (typeof currentStorage[date][code] === 'number') {
1059
+ errors[code] = errors[code]
1060
+ ? errors[code] + currentStorage[date][code]
1061
+ : currentStorage[date][code];
1062
+ }
1063
+ });
1064
+ });
1065
+
1066
+ return errors;
1067
+ }
1068
+
1069
+ /**
1070
+ *
942
1071
  * Initialize Outstream Renderer
943
1072
  * @param {Object} bid
944
1073
  */
945
- function outstreamRenderer (bid) {
1074
+ function outstreamRenderer(bid) {
946
1075
  bid.renderer.push(() => {
947
1076
  var config = {
948
1077
  width: bid.width,
@@ -950,7 +1079,13 @@ function outstreamRenderer (bid) {
950
1079
  timeout: 3000
951
1080
  };
952
1081
 
953
- window.IXOutstreamPlayer(bid.vastUrl, bid.adUnitCode, config);
1082
+ // IXOutstreamPlayer supports both vastUrl and vastXml, so we can pass either.
1083
+ // Since vastUrl is going to be deprecated from exchange response, vastXml takes priority.
1084
+ if (bid.vastXml) {
1085
+ window.IXOutstreamPlayer(bid.vastXml, bid.adUnitCode, config);
1086
+ } else {
1087
+ window.IXOutstreamPlayer(bid.vastUrl, bid.adUnitCode, config);
1088
+ }
954
1089
  });
955
1090
  }
956
1091
 
@@ -959,7 +1094,7 @@ function outstreamRenderer (bid) {
959
1094
  * @param {string} id
960
1095
  * @returns {Renderer}
961
1096
  */
962
- function createRenderer (id) {
1097
+ function createRenderer(id) {
963
1098
  const renderer = Renderer.install({
964
1099
  id: id,
965
1100
  url: RENDERER_URL,
@@ -993,6 +1128,12 @@ export const spec = {
993
1128
  * @return {boolean} True if this is a valid bid, and false otherwise.
994
1129
  */
995
1130
  isBidRequestValid: function (bid) {
1131
+ if (!hasRegisteredHandler) {
1132
+ events.on(EVENTS.AUCTION_DEBUG, errorEventHandler);
1133
+ events.on(EVENTS.AD_RENDER_FAILED, errorEventHandler);
1134
+ hasRegisteredHandler = true;
1135
+ }
1136
+
996
1137
  const paramsVideoRef = deepAccess(bid, 'params.video');
997
1138
  const paramsSize = deepAccess(bid, 'params.size');
998
1139
  const mediaTypeBannerSizes = deepAccess(bid, 'mediaTypes.banner.sizes');
@@ -1002,6 +1143,7 @@ export const spec = {
1002
1143
  const hasBidFloorCur = bid.params.hasOwnProperty('bidFloorCur');
1003
1144
 
1004
1145
  if (bid.hasOwnProperty('mediaType') && !(contains(SUPPORTED_AD_TYPES, bid.mediaType))) {
1146
+ logWarn('IX Bid Adapter: media type is not supported.');
1005
1147
  return false;
1006
1148
  }
1007
1149
 
@@ -1013,26 +1155,26 @@ export const spec = {
1013
1155
  // since there is an ix bidder level size, make sure its valid
1014
1156
  const ixSize = getFirstSize(paramsSize);
1015
1157
  if (!ixSize) {
1016
- logError('ix bidder params: size has invalid format.');
1158
+ logError('IX Bid Adapter: size has invalid format.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_SIZE_INVALID_FORMAT });
1017
1159
  return false;
1018
1160
  }
1019
1161
  // check if the ix bidder level size, is present in ad unit level
1020
1162
  if (!includesSize(bid.sizes, ixSize) &&
1021
1163
  !(includesSize(mediaTypeVideoPlayerSize, ixSize)) &&
1022
1164
  !(includesSize(mediaTypeBannerSizes, ixSize))) {
1023
- logError('ix bidder params: bid size is not included in ad unit sizes or player size.');
1165
+ logError('IX Bid Adapter: bid size is not included in ad unit sizes or player size.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_SIZE_NOT_INCLUDED });
1024
1166
  return false;
1025
1167
  }
1026
1168
  }
1027
1169
 
1028
1170
  if (typeof bid.params.siteId !== 'string' && typeof bid.params.siteId !== 'number') {
1029
- logError('ix bidder params: siteId must be string or number value.');
1171
+ logError('IX Bid Adapter: siteId must be string or number value.', { bidder: BIDDER_CODE, code: ERROR_CODES.SITE_ID_INVALID_VALUE });
1030
1172
  return false;
1031
1173
  }
1032
1174
 
1033
1175
  if (hasBidFloor || hasBidFloorCur) {
1034
1176
  if (!(hasBidFloor && hasBidFloorCur && isValidBidFloorParams(bid.params.bidFloor, bid.params.bidFloorCur))) {
1035
- logError('ix bidder params: bidFloor / bidFloorCur parameter has invalid format.');
1177
+ logError('IX Bid Adapter: bidFloor / bidFloorCur parameter has invalid format.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_FLOOR_INVALID_FORMAT });
1036
1178
  return false;
1037
1179
  }
1038
1180
  }
@@ -1041,7 +1183,7 @@ export const spec = {
1041
1183
  const errorList = checkVideoParams(mediaTypeVideoRef, paramsVideoRef);
1042
1184
  if (errorList.length) {
1043
1185
  errorList.forEach((err) => {
1044
- logError(err);
1186
+ logError(err, { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED });
1045
1187
  });
1046
1188
  return false;
1047
1189
  }
@@ -1162,6 +1304,16 @@ export const spec = {
1162
1304
 
1163
1305
  bids.push(bid);
1164
1306
  }
1307
+
1308
+ if (deepAccess(requestBid, 'ext.ixdiag.err')) {
1309
+ if (storage.localStorageIsEnabled()) {
1310
+ try {
1311
+ storage.removeDataFromLocalStorage(LOCAL_STORAGE_KEY);
1312
+ } catch (e) {
1313
+ logError('ix can not clear ixdiag from localStorage.');
1314
+ }
1315
+ }
1316
+ }
1165
1317
  }
1166
1318
 
1167
1319
  return bids;
@@ -10,7 +10,7 @@ export const storage = getStorageManager();
10
10
 
11
11
  const BIDDER_CODE = 'jixie';
12
12
  const EVENTS_URL = 'https://hbtra.jixie.io/sync/hb?';
13
- const JX_OUTSTREAM_RENDERER_URL = 'https://scripts.jixie.io/jxhboutstream.js';
13
+ const JX_OUTSTREAM_RENDERER_URL = 'https://scripts.jixie.media/jxhbrenderer.1.1.min.js';
14
14
  const REQUESTS_URL = 'https://hb.jixie.io/v2/hbpost';
15
15
  const sidTTLMins_ = 30;
16
16
 
@@ -104,7 +104,8 @@ function getMiscDims_() {
104
104
  let ret = {
105
105
  pageurl: '',
106
106
  domain: '',
107
- device: 'unknown'
107
+ device: 'unknown',
108
+ mkeywords: ''
108
109
  }
109
110
  try {
110
111
  let refererInfo_ = getRefererInfo();
@@ -112,6 +113,10 @@ function getMiscDims_() {
112
113
  ret.pageurl = url_;
113
114
  ret.domain = parseUrl(url_).host;
114
115
  ret.device = getDevice_();
116
+ let keywords = document.getElementsByTagName('meta')['keywords'];
117
+ if (keywords && keywords.content) {
118
+ ret.mkeywords = keywords.content;
119
+ }
115
120
  } catch (error) {}
116
121
  return ret;
117
122
  }
@@ -167,6 +172,7 @@ export const spec = {
167
172
  device: miscDims.device,
168
173
  domain: miscDims.domain,
169
174
  pageurl: miscDims.pageurl,
175
+ mkeywords: miscDims.mkeywords,
170
176
  bids: bids,
171
177
  cfg: jixieCfgBlob
172
178
  }, ids);
@@ -4,7 +4,7 @@ import { deepAccess } from '../src/utils.js';
4
4
  const BIDDER_CODE = 'justpremium'
5
5
  const GVLID = 62
6
6
  const ENDPOINT_URL = 'https://pre.ads.justpremium.com/v/2.0/t/xhr'
7
- const JP_ADAPTER_VERSION = '1.8'
7
+ const JP_ADAPTER_VERSION = '1.8.1'
8
8
  const pixels = []
9
9
 
10
10
  export const spec = {
@@ -101,6 +101,11 @@ export const spec = {
101
101
  advertiserDomains: bid.adomain && bid.adomain.length > 0 ? bid.adomain : []
102
102
  }
103
103
  }
104
+ if (bid.ext && bid.ext.pg) {
105
+ bidResponse.adserverTargeting = {
106
+ 'hb_deal_justpremium': 'jp_pg'
107
+ }
108
+ }
104
109
  bidResponses.push(bidResponse)
105
110
  }
106
111
  })
@@ -1,4 +1,4 @@
1
- import { logMessage, groupBy, uniques } from '../src/utils.js';
1
+ import { logMessage, groupBy, uniques, flatten, deepAccess } from '../src/utils.js';
2
2
  import { registerBidder } from '../src/adapters/bidderFactory.js';
3
3
  import { BANNER, VIDEO } from '../src/mediaTypes.js';
4
4
  import {ajax} from '../src/ajax.js';
@@ -92,6 +92,26 @@ export const spec = {
92
92
  }
93
93
  return bidResponses;
94
94
  },
95
+
96
+ getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => {
97
+ const syncs = serverResponses.map(response => response.body).reduce(flatten, [])
98
+ .map(response => deepAccess(response, 'ext.sync')).filter(Boolean);
99
+ const iframeSyncUrls = !syncOptions.iframeEnabled ? [] : syncs.map(sync => sync.iframe).filter(Boolean)
100
+ .filter(uniques).map(url => {
101
+ return {
102
+ type: 'iframe',
103
+ url: url
104
+ }
105
+ });
106
+ const pixelSyncUrls = !syncOptions.pixelEnabled ? [] : syncs.map(sync => sync.pixel).filter(Boolean)
107
+ .filter(uniques).map(url => {
108
+ return {
109
+ type: 'image',
110
+ url: url
111
+ }
112
+ });
113
+ return [iframeSyncUrls, pixelSyncUrls].reduce(flatten, []);
114
+ }
95
115
  };
96
116
 
97
117
  registerBidder(spec);
@@ -125,7 +145,7 @@ function buildPlacement(bidRequest) {
125
145
  break;
126
146
  }
127
147
  }
128
- sizes = (sizes || []).concat(bidRequest.sizes || []).filter(uniques);
148
+ sizes = (sizes || []).concat(bidRequest.sizes || []);
129
149
  return {
130
150
  host: bidRequest.params.host,
131
151
  adUnit: {