prebid.js 9.2.0 → 9.4.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 (279) hide show
  1. package/creative/constants.js +2 -1
  2. package/creative/crossDomain.js +16 -4
  3. package/dist/33acrossAnalyticsAdapter.js +1 -1
  4. package/dist/33acrossBidAdapter.js +1 -1
  5. package/dist/33acrossIdSystem.js +1 -1
  6. package/dist/BTBidAdapter.js +1 -1
  7. package/dist/adagioAnalyticsAdapter.js +1 -1
  8. package/dist/adagioBidAdapter.js +1 -1
  9. package/dist/adagioRtdProvider.js +1 -1
  10. package/dist/adagioUtils.js +1 -1
  11. package/dist/addefendBidAdapter.js +1 -1
  12. package/dist/adfBidAdapter.js +1 -1
  13. package/dist/adgenerationBidAdapter.js +1 -1
  14. package/dist/adlooxRtdProvider.js +1 -1
  15. package/dist/adnuntiusBidAdapter.js +1 -1
  16. package/dist/adqueryBidAdapter.js +1 -1
  17. package/dist/adrelevantisBidAdapter.js +1 -1
  18. package/dist/adstirBidAdapter.js +1 -1
  19. package/dist/adtrgtmeBidAdapter.js +1 -1
  20. package/dist/adxcgAnalyticsAdapter.js +1 -1
  21. package/dist/adxcgBidAdapter.js +1 -1
  22. package/dist/adyoulikeBidAdapter.js +1 -1
  23. package/dist/agmaAnalyticsAdapter.js +1 -1
  24. package/dist/ajaBidAdapter.js +1 -1
  25. package/dist/amxBidAdapter.js +1 -1
  26. package/dist/amxIdSystem.js +1 -1
  27. package/dist/appierAnalyticsAdapter.js +1 -1
  28. package/dist/appnexusBidAdapter.js +1 -1
  29. package/dist/asoBidAdapter.js +1 -1
  30. package/dist/axonixBidAdapter.js +1 -1
  31. package/dist/bidglassBidAdapter.js +1 -1
  32. package/dist/big-richmediaBidAdapter.js +1 -1
  33. package/dist/bridBidAdapter.js +1 -1
  34. package/dist/bridgewellBidAdapter.js +1 -1
  35. package/dist/brightMountainMediaBidAdapter.js +1 -1
  36. package/dist/carodaBidAdapter.js +1 -1
  37. package/dist/chtnwBidAdapter.js +1 -1
  38. package/dist/chunk-core.js +1 -1
  39. package/dist/codefuelBidAdapter.js +1 -1
  40. package/dist/concertBidAdapter.js +1 -1
  41. package/dist/connectadBidAdapter.js +1 -1
  42. package/dist/consentManagement.js +1 -0
  43. package/dist/consentManagementGpp.js +1 -1
  44. package/dist/consentManagementTcf.js +1 -1
  45. package/dist/consumableBidAdapter.js +1 -1
  46. package/dist/conversantAnalyticsAdapter.js +1 -1
  47. package/dist/conversantBidAdapter.js +1 -1
  48. package/dist/copper6sspBidAdapter.js +1 -0
  49. package/dist/cpmstarBidAdapter.js +1 -1
  50. package/dist/craftBidAdapter.js +1 -1
  51. package/dist/criteoBidAdapter.js +1 -1
  52. package/dist/cwireBidAdapter.js +1 -1
  53. package/dist/dailymotionBidAdapter.js +1 -1
  54. package/dist/deltaprojectsBidAdapter.js +1 -1
  55. package/dist/dependencies.json +51 -13
  56. package/dist/dianomiBidAdapter.js +1 -1
  57. package/dist/dspxBidAdapter.js +1 -1
  58. package/dist/dxkultureBidAdapter.js +1 -1
  59. package/dist/eplanningBidAdapter.js +1 -1
  60. package/dist/euidIdSystem.js +1 -1
  61. package/dist/exadsBidAdapter.js +1 -1
  62. package/dist/feedadBidAdapter.js +1 -1
  63. package/dist/finativeBidAdapter.js +1 -1
  64. package/dist/freewheel-sspBidAdapter.js +1 -1
  65. package/dist/gmosspBidAdapter.js +1 -1
  66. package/dist/goldbachBidAdapter.js +1 -1
  67. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  68. package/dist/greenbidsRtdProvider.js +1 -1
  69. package/dist/gridBidAdapter.js +1 -1
  70. package/dist/gumgumBidAdapter.js +1 -1
  71. package/dist/h12mediaBidAdapter.js +1 -1
  72. package/dist/hypelabBidAdapter.js +1 -1
  73. package/dist/id5AnalyticsAdapter.js +1 -1
  74. package/dist/id5IdSystem.js +1 -1
  75. package/dist/illuminBidAdapter.js +1 -1
  76. package/dist/imdsBidAdapter.js +1 -1
  77. package/dist/improvedigitalBidAdapter.js +1 -1
  78. package/dist/insticatorBidAdapter.js +1 -1
  79. package/dist/intentIqIdSystem.js +1 -1
  80. package/dist/ixBidAdapter.js +1 -1
  81. package/dist/jixieBidAdapter.js +1 -1
  82. package/dist/justpremiumBidAdapter.js +1 -1
  83. package/dist/kargoBidAdapter.js +1 -1
  84. package/dist/kimberliteBidAdapter.js +1 -1
  85. package/dist/konduitAnalyticsAdapter.js +1 -1
  86. package/dist/kueezBidAdapter.js +1 -1
  87. package/dist/kueezRtbBidAdapter.js +1 -1
  88. package/dist/lassoBidAdapter.js +1 -1
  89. package/dist/lifestreetBidAdapter.js +1 -1
  90. package/dist/liveIntentIdSystem.js +1 -1
  91. package/dist/logicadBidAdapter.js +1 -1
  92. package/dist/loglyliftBidAdapter.js +1 -1
  93. package/dist/luceadBidAdapter.js +1 -1
  94. package/dist/luponmediaBidAdapter.js +1 -1
  95. package/dist/mabidderBidAdapter.js +1 -1
  96. package/dist/magniteAnalyticsAdapter.js +1 -1
  97. package/dist/malltvAnalyticsAdapter.js +1 -1
  98. package/dist/marsmediaBidAdapter.js +1 -1
  99. package/dist/mediafuseBidAdapter.js +1 -1
  100. package/dist/medianetAnalyticsAdapter.js +1 -1
  101. package/dist/medianetBidAdapter.js +1 -1
  102. package/dist/mediasquareBidAdapter.js +1 -1
  103. package/dist/mgidBidAdapter.js +1 -1
  104. package/dist/minutemediaBidAdapter.js +1 -1
  105. package/dist/missenaBidAdapter.js +1 -1
  106. package/dist/nexx360BidAdapter.js +1 -1
  107. package/dist/nobidAnalyticsAdapter.js +1 -1
  108. package/dist/nobidBidAdapter.js +1 -1
  109. package/dist/not-for-prod/prebid.js +184 -178
  110. package/dist/oguryBidAdapter.js +1 -1
  111. package/dist/onetagBidAdapter.js +1 -1
  112. package/dist/ooloAnalyticsAdapter.js +1 -1
  113. package/dist/openwebBidAdapter.js +1 -1
  114. package/dist/openxBidAdapter.js +1 -1
  115. package/dist/optidigitalBidAdapter.js +1 -1
  116. package/dist/orakiBidAdapter.js +1 -0
  117. package/dist/orbidderBidAdapter.js +1 -1
  118. package/dist/outbrainBidAdapter.js +1 -1
  119. package/dist/ozoneBidAdapter.js +1 -1
  120. package/dist/pairIdSystem.js +1 -1
  121. package/dist/pixfutureBidAdapter.js +1 -1
  122. package/dist/prebidServerBidAdapter.js +1 -1
  123. package/dist/processResponse.js +1 -0
  124. package/dist/publinkIdSystem.js +1 -1
  125. package/dist/publirBidAdapter.js +1 -1
  126. package/dist/pubmaticAnalyticsAdapter.js +1 -1
  127. package/dist/pubmaticBidAdapter.js +1 -1
  128. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  129. package/dist/pxyzBidAdapter.js +1 -1
  130. package/dist/quantcastBidAdapter.js +1 -1
  131. package/dist/readpeakBidAdapter.js +1 -1
  132. package/dist/relaidoBidAdapter.js +1 -1
  133. package/dist/retailspotBidAdapter.js +1 -1
  134. package/dist/rhythmoneBidAdapter.js +1 -1
  135. package/dist/riseBidAdapter.js +1 -1
  136. package/dist/rubiconBidAdapter.js +1 -1
  137. package/dist/seedingAllianceBidAdapter.js +1 -1
  138. package/dist/seedtagBidAdapter.js +1 -1
  139. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  140. package/dist/sharethroughBidAdapter.js +1 -1
  141. package/dist/shinezBidAdapter.js +1 -1
  142. package/dist/shinezRtbBidAdapter.js +1 -1
  143. package/dist/smaatoBidAdapter.js +1 -1
  144. package/dist/smartadserverBidAdapter.js +1 -1
  145. package/dist/smartxBidAdapter.js +1 -1
  146. package/dist/smartyadsBidAdapter.js +1 -1
  147. package/dist/smartyadsUtils.js +1 -0
  148. package/dist/smilewantedBidAdapter.js +1 -1
  149. package/dist/snigelBidAdapter.js +1 -1
  150. package/dist/sonobiBidAdapter.js +1 -1
  151. package/dist/sovrnBidAdapter.js +1 -1
  152. package/dist/sspBCBidAdapter.js +1 -1
  153. package/dist/stnBidAdapter.js +1 -1
  154. package/dist/stvBidAdapter.js +1 -1
  155. package/dist/sublimeBidAdapter.js +1 -1
  156. package/dist/taboolaBidAdapter.js +1 -1
  157. package/dist/tagorasBidAdapter.js +1 -1
  158. package/dist/tappxBidAdapter.js +1 -1
  159. package/dist/targetVideoBidAdapter.js +1 -1
  160. package/dist/teadsBidAdapter.js +1 -1
  161. package/dist/terceptAnalyticsAdapter.js +1 -1
  162. package/dist/themoneytizerBidAdapter.js +1 -1
  163. package/dist/trionBidAdapter.js +1 -1
  164. package/dist/tripleliftBidAdapter.js +1 -1
  165. package/dist/ttdBidAdapter.js +1 -1
  166. package/dist/twistDigitalBidAdapter.js +1 -1
  167. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  168. package/dist/uid2IdSystem.js +1 -1
  169. package/dist/underdogmediaBidAdapter.js +1 -1
  170. package/dist/undertoneBidAdapter.js +1 -1
  171. package/dist/unrulyBidAdapter.js +1 -1
  172. package/dist/userId.js +1 -1
  173. package/dist/viantOrtbBidAdapter.js +1 -1
  174. package/dist/vidazooBidAdapter.js +1 -1
  175. package/dist/vidazooUtils.js +1 -0
  176. package/dist/videobyteBidAdapter.js +1 -1
  177. package/dist/visxBidAdapter.js +1 -1
  178. package/dist/vuukleBidAdapter.js +1 -1
  179. package/dist/widespaceBidAdapter.js +1 -1
  180. package/dist/winrBidAdapter.js +1 -1
  181. package/dist/yahooAdsBidAdapter.js +1 -1
  182. package/dist/yieldmoBidAdapter.js +1 -1
  183. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  184. package/dist/yuktamediaAnalyticsAdapter.js +1 -1
  185. package/dist/zeta_global_sspBidAdapter.js +1 -1
  186. package/integrationExamples/gpt/x-domain/creative.html +1 -1
  187. package/libraries/consentManagement/cmUtils.js +38 -0
  188. package/libraries/processResponse/index.js +12 -0
  189. package/libraries/smartyadsUtils/getAdUrlByRegion.js +32 -0
  190. package/libraries/vidazooUtils/bidderUtils.js +480 -0
  191. package/libraries/vidazooUtils/constants.js +7 -0
  192. package/modules/adagioRtdProvider.js +9 -7
  193. package/modules/addefendBidAdapter.js +1 -2
  194. package/modules/adfBidAdapter.js +1 -10
  195. package/modules/adlooxRtdProvider.js +1 -1
  196. package/modules/adnuntiusBidAdapter.js +1 -0
  197. package/modules/adxcgAnalyticsAdapter.js +1 -2
  198. package/modules/carodaBidAdapter.js +3 -8
  199. package/modules/codefuelBidAdapter.js +1 -10
  200. package/modules/consentManagementGpp.js +2 -38
  201. package/modules/consentManagementTcf.js +7 -38
  202. package/modules/conversantAnalyticsAdapter.js +1 -2
  203. package/modules/copper6sspBidAdapter.js +19 -0
  204. package/modules/copper6sspBidAdapter.md +79 -0
  205. package/modules/cpmstarBidAdapter.js +52 -36
  206. package/modules/cpmstarBidAdapter.md +1 -4
  207. package/modules/criteoBidAdapter.js +10 -3
  208. package/modules/dailymotionBidAdapter.js +1 -1
  209. package/modules/deltaprojectsBidAdapter.js +2 -11
  210. package/modules/dianomiBidAdapter.js +1 -9
  211. package/modules/finativeBidAdapter.js +1 -10
  212. package/modules/gridBidAdapter.js +2 -12
  213. package/modules/id5AnalyticsAdapter.js +1 -2
  214. package/modules/illuminBidAdapter.js +9 -304
  215. package/modules/intentIqIdSystem.js +408 -50
  216. package/modules/intentIqIdSystem.md +92 -0
  217. package/modules/kueezRtbBidAdapter.js +17 -312
  218. package/modules/liveIntentIdSystem.js +2 -2
  219. package/modules/luponmediaBidAdapter.js +4 -10
  220. package/modules/mabidderBidAdapter.js +1 -2
  221. package/modules/medianetAnalyticsAdapter.js +1 -2
  222. package/modules/medianetBidAdapter.js +1 -1
  223. package/modules/mgidBidAdapter.js +1 -10
  224. package/modules/orakiBidAdapter.js +19 -0
  225. package/modules/orakiBidAdapter.md +79 -0
  226. package/modules/orbidderBidAdapter.js +4 -2
  227. package/modules/outbrainBidAdapter.js +8 -43
  228. package/modules/ozoneBidAdapter.js +9 -7
  229. package/modules/pairIdSystem.js +27 -10
  230. package/modules/pixfutureBidAdapter.js +1 -2
  231. package/modules/prebidServerBidAdapter/index.js +1 -1
  232. package/modules/seedtagBidAdapter.js +4 -0
  233. package/modules/shinezRtbBidAdapter.js +12 -304
  234. package/modules/smartadserverBidAdapter.js +3 -0
  235. package/modules/smartyadsBidAdapter.js +6 -110
  236. package/modules/snigelBidAdapter.js +1 -2
  237. package/modules/tagorasBidAdapter.js +13 -316
  238. package/modules/tappxBidAdapter.js +1 -2
  239. package/modules/terceptAnalyticsAdapter.js +1 -2
  240. package/modules/twistDigitalBidAdapter.js +9 -433
  241. package/modules/userId/index.js +31 -21
  242. package/modules/viantOrtbBidAdapter.js +20 -0
  243. package/modules/vidazooBidAdapter.js +26 -468
  244. package/modules/visxBidAdapter.js +27 -29
  245. package/modules/yahooAdsBidAdapter.js +4 -1
  246. package/modules/yuktamediaAnalyticsAdapter.js +1 -2
  247. package/modules/zeta_global_sspBidAdapter.js +2 -2
  248. package/package.json +1 -1
  249. package/src/adRendering.js +25 -2
  250. package/src/constants.js +2 -0
  251. package/src/prebid.js +2 -1
  252. package/src/utils.js +19 -1
  253. package/test/spec/creative/crossDomainCreative_spec.js +38 -2
  254. package/test/spec/fpd/gdpr_spec.js +24 -2
  255. package/test/spec/libraries/processResponse_spec.js +60 -0
  256. package/test/spec/modules/adagioRtdProvider_spec.js +12 -0
  257. package/test/spec/modules/adnuntiusBidAdapter_spec.js +6 -3
  258. package/test/spec/modules/conversantAnalyticsAdapter_spec.js +1 -1
  259. package/test/spec/modules/copper6sspBidAdapter_spec.js +514 -0
  260. package/test/spec/modules/cpmstarBidAdapter_spec.js +1 -1
  261. package/test/spec/modules/dailymotionBidAdapter_spec.js +18 -14
  262. package/test/spec/modules/illuminBidAdapter_spec.js +26 -13
  263. package/test/spec/modules/intentIqIdSystem_spec.js +264 -36
  264. package/test/spec/modules/kueezRtbBidAdapter_spec.js +26 -15
  265. package/test/spec/modules/orakiBidAdapter_spec.js +510 -0
  266. package/test/spec/modules/outbrainBidAdapter_spec.js +32 -1
  267. package/test/spec/modules/seedtagBidAdapter_spec.js +27 -0
  268. package/test/spec/modules/shinezRtbBidAdapter_spec.js +26 -14
  269. package/test/spec/modules/smartadserverBidAdapter_spec.js +7 -0
  270. package/test/spec/modules/smartyadsBidAdapter_spec.js +6 -83
  271. package/test/spec/modules/tagorasBidAdapter_spec.js +26 -15
  272. package/test/spec/modules/twistDigitalBidAdapter_spec.js +19 -22
  273. package/test/spec/modules/userId_spec.js +86 -47
  274. package/test/spec/modules/viantOrtbBidAdapter_spec.js +87 -6
  275. package/test/spec/modules/vidazooBidAdapter_spec.js +21 -23
  276. package/test/spec/modules/visxBidAdapter_spec.js +180 -0
  277. package/test/spec/modules/yahooAdsBidAdapter_spec.js +1 -1
  278. package/test/spec/modules/zeta_global_sspBidAdapter_spec.js +11 -0
  279. package/test/spec/unit/pbjs_api_spec.js +6 -1
@@ -10,6 +10,9 @@ import { ajax } from '../src/ajax.js';
10
10
  import { submodule } from '../src/hook.js'
11
11
  import { getStorageManager } from '../src/storageManager.js';
12
12
  import { MODULE_TYPE_UID } from '../src/activities/modules.js';
13
+ import { gppDataHandler, uspDataHandler } from '../src/consentHandler.js';
14
+ import AES from 'crypto-js/aes.js';
15
+ import Utf8 from 'crypto-js/enc-utf8.js';
13
16
 
14
17
  /**
15
18
  * @typedef {import('../modules/userId/index.js').Submodule} Submodule
@@ -21,11 +24,31 @@ const PCID_EXPIRY = 365;
21
24
 
22
25
  const MODULE_NAME = 'intentIqId';
23
26
  export const FIRST_PARTY_KEY = '_iiq_fdata';
24
- export var FIRST_PARTY_DATA_KEY = '_iiq_fdata';
25
-
26
- export const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME });
27
+ export let FIRST_PARTY_DATA_KEY = '_iiq_fdata';
28
+ export const WITH_IIQ = 'A';
29
+ export const WITHOUT_IIQ = 'B';
30
+ export const NOT_YET_DEFINED = 'U';
31
+ export const OPT_OUT = 'O';
32
+ export const BLACK_LIST = 'L';
33
+ export const CLIENT_HINTS_KEY = '_iiq_ch';
34
+ export const EMPTY = 'EMPTY'
35
+ export const VERSION = 0.1
27
36
 
37
+ const encoderCH = {
38
+ brands: 0,
39
+ mobile: 1,
40
+ platform: 2,
41
+ architecture: 3,
42
+ bitness: 4,
43
+ model: 5,
44
+ platformVersion: 6,
45
+ wow64: 7,
46
+ fullVersionList: 8
47
+ };
28
48
  const INVALID_ID = 'INVALID_ID';
49
+ const SUPPORTED_TYPES = ['html5', 'cookie']
50
+
51
+ export const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME });
29
52
 
30
53
  /**
31
54
  * Generate standard UUID string
@@ -42,16 +65,35 @@ function generateGUID() {
42
65
  }
43
66
 
44
67
  /**
45
- * Read Intent IQ data from cookie or local storage
68
+ * Encrypts plaintext.
69
+ * @param {string} plainText The plaintext to encrypt.
70
+ * @returns {string} The encrypted text as a base64 string.
71
+ */
72
+ export function encryptData(plainText) {
73
+ return AES.encrypt(plainText, MODULE_NAME).toString();
74
+ }
75
+
76
+ /**
77
+ * Decrypts ciphertext.
78
+ * @param {string} encryptedText The encrypted text as a base64 string.
79
+ * @returns {string} The decrypted plaintext.
80
+ */
81
+ export function decryptData(encryptedText) {
82
+ const bytes = AES.decrypt(encryptedText, MODULE_NAME);
83
+ return bytes.toString(Utf8);
84
+ }
85
+
86
+ /**
87
+ * Read Intent IQ data from local storage or cookie
46
88
  * @param key
47
89
  * @return {string}
48
90
  */
49
- export function readData(key) {
91
+ export function readData(key, allowedStorage) {
50
92
  try {
51
- if (storage.hasLocalStorage()) {
93
+ if (storage.hasLocalStorage() && allowedStorage.includes('html5')) {
52
94
  return storage.getDataFromLocalStorage(key);
53
95
  }
54
- if (storage.cookiesAreEnabled()) {
96
+ if (storage.cookiesAreEnabled() && allowedStorage.includes('cookie')) {
55
97
  return storage.getCookie(key);
56
98
  }
57
99
  } catch (error) {
@@ -60,21 +102,20 @@ export function readData(key) {
60
102
  }
61
103
 
62
104
  /**
63
- * Store Intent IQ data in either cookie or local storage
105
+ * Store Intent IQ data in cookie, local storage or both of them
64
106
  * expiration date: 365 days
65
107
  * @param key
66
108
  * @param {string} value IntentIQ ID value to sintentIqIdSystem_spec.jstore
67
109
  */
68
- function storeData(key, value, cookieStorageEnabled = false) {
110
+ export function storeData(key, value, allowedStorage) {
69
111
  try {
70
112
  logInfo(MODULE_NAME + ': storing data: key=' + key + ' value=' + value);
71
-
72
113
  if (value) {
73
- if (storage.hasLocalStorage()) {
114
+ if (storage.hasLocalStorage() && allowedStorage.includes('html5')) {
74
115
  storage.setDataInLocalStorage(key, value);
75
116
  }
76
- const expiresStr = (new Date(Date.now() + (PCID_EXPIRY * (60 * 60 * 24 * 1000)))).toUTCString();
77
- if (storage.cookiesAreEnabled() && cookieStorageEnabled) {
117
+ if (storage.cookiesAreEnabled() && allowedStorage.includes('cookie')) {
118
+ const expiresStr = (new Date(Date.now() + (PCID_EXPIRY * (60 * 60 * 24 * 1000)))).toUTCString();
78
119
  storage.setCookie(key, value, expiresStr, 'LAX');
79
120
  }
80
121
  }
@@ -83,10 +124,28 @@ function storeData(key, value, cookieStorageEnabled = false) {
83
124
  }
84
125
  }
85
126
 
127
+ /**
128
+ * Remove Intent IQ data from cookie or local storage
129
+ * @param key
130
+ */
131
+
132
+ export function removeDataByKey(key, allowedStorage) {
133
+ try {
134
+ if (storage.hasLocalStorage() && allowedStorage.includes('html5')) {
135
+ storage.removeDataFromLocalStorage(key);
136
+ }
137
+ if (storage.cookiesAreEnabled() && allowedStorage.includes('cookie')) {
138
+ const expiredDate = new Date(0).toUTCString();
139
+ storage.setCookie(key, '', expiredDate, 'LAX');
140
+ }
141
+ } catch (error) {
142
+ logError(error);
143
+ }
144
+ }
145
+
86
146
  /**
87
147
  * Parse json if possible, else return null
88
148
  * @param data
89
- * @param {object|null}
90
149
  */
91
150
  function tryParse(data) {
92
151
  try {
@@ -97,6 +156,125 @@ function tryParse(data) {
97
156
  }
98
157
  }
99
158
 
159
+ /**
160
+ * Convert GPP data to an object
161
+ * @param {Object} data
162
+ * @return {string} The JSON string representation of the input data.
163
+ */
164
+ export function handleGPPData(data = {}) {
165
+ if (Array.isArray(data)) {
166
+ let obj = {};
167
+ for (const element of data) {
168
+ obj = Object.assign(obj, element);
169
+ }
170
+ return JSON.stringify(obj);
171
+ }
172
+ return JSON.stringify(data);
173
+ }
174
+
175
+ /**
176
+ * Detects the browser using either userAgent or userAgentData
177
+ * @return {string} The name of the detected browser or 'unknown' if unable to detect
178
+ */
179
+ function detectBrowser() {
180
+ try {
181
+ if (navigator.userAgent) {
182
+ return detectBrowserFromUserAgent(navigator.userAgent);
183
+ } else if (navigator.userAgentData) {
184
+ return detectBrowserFromUserAgentData(navigator.userAgentData);
185
+ }
186
+ } catch (error) {
187
+ logError('Error detecting browser:', error);
188
+ }
189
+ return 'unknown';
190
+ }
191
+
192
+ /**
193
+ * Detects the browser from the user agent string
194
+ * @param {string} userAgent - The user agent string from the browser
195
+ * @return {string} The name of the detected browser or 'unknown' if unable to detect
196
+ */
197
+ export function detectBrowserFromUserAgent(userAgent) {
198
+ const browserRegexPatterns = {
199
+ opera: /Opera|OPR/,
200
+ edge: /Edg/,
201
+ chrome: /Chrome|CriOS/,
202
+ safari: /Safari/,
203
+ firefox: /Firefox/,
204
+ ie: /MSIE|Trident/,
205
+ };
206
+
207
+ // Check for Chrome first to avoid confusion with Safari
208
+ if (browserRegexPatterns.chrome.test(userAgent)) {
209
+ return 'chrome';
210
+ }
211
+
212
+ // Now we can safely check for Safari
213
+ if (browserRegexPatterns.safari.test(userAgent) && !browserRegexPatterns.chrome.test(userAgent)) {
214
+ return 'safari';
215
+ }
216
+
217
+ // Check other browsers
218
+ for (const browser in browserRegexPatterns) {
219
+ if (browserRegexPatterns[browser].test(userAgent)) {
220
+ return browser;
221
+ }
222
+ }
223
+
224
+ return 'unknown';
225
+ }
226
+
227
+ /**
228
+ * Detects the browser from the NavigatorUAData object
229
+ * @param {NavigatorUAData} userAgentData - The user agent data object from the browser
230
+ * @return {string} The name of the detected browser or 'unknown' if unable to detect
231
+ */
232
+ export function detectBrowserFromUserAgentData(userAgentData) {
233
+ const brandNames = userAgentData.brands.map(brand => brand.brand);
234
+
235
+ if (brandNames.includes('Microsoft Edge')) {
236
+ return 'edge';
237
+ } else if (brandNames.includes('Opera')) {
238
+ return 'opera';
239
+ } else if (brandNames.some(brand => brand === 'Chromium' || brand === 'Google Chrome')) {
240
+ return 'chrome';
241
+ }
242
+
243
+ return 'unknown';
244
+ }
245
+
246
+ /**
247
+ * Processes raw client hints data into a structured format.
248
+ * @param {object} clientHints - Raw client hints data
249
+ * @return {string} A JSON string of processed client hints or an empty string if no hints
250
+ */
251
+ export function handleClientHints(clientHints) {
252
+ const chParams = {};
253
+ for (const key in clientHints) {
254
+ if (clientHints.hasOwnProperty(key) && clientHints[key] !== '') {
255
+ if (['brands', 'fullVersionList'].includes(key)) {
256
+ let handledParam = '';
257
+ clientHints[key].forEach((element, index) => {
258
+ const isNotLast = index < clientHints[key].length - 1;
259
+ handledParam += `"${element.brand}";v="${element.version}"${isNotLast ? ', ' : ''}`;
260
+ });
261
+ chParams[encoderCH[key]] = handledParam;
262
+ } else if (typeof clientHints[key] === 'boolean') {
263
+ chParams[encoderCH[key]] = `?${clientHints[key] ? 1 : 0}`;
264
+ } else {
265
+ chParams[encoderCH[key]] = `"${clientHints[key]}"`;
266
+ }
267
+ }
268
+ }
269
+ return Object.keys(chParams).length ? JSON.stringify(chParams) : '';
270
+ }
271
+
272
+ function defineStorageType(params) {
273
+ if (!params || !Array.isArray(params)) return ['html5']; // use locale storage be default
274
+ const filteredArr = params.filter(item => SUPPORTED_TYPES.includes(item));
275
+ return filteredArr.length ? filteredArr : ['html5'];
276
+ }
277
+
100
278
  /** @type {Submodule} */
101
279
  export const intentIqIdSubmodule = {
102
280
  /**
@@ -120,25 +298,136 @@ export const intentIqIdSubmodule = {
120
298
  * @returns {IdResponse|undefined}
121
299
  */
122
300
  getId(config) {
123
- const configParams = (config && config.params) || {};
124
- if (!configParams || typeof configParams.partner !== 'number') {
301
+ const configParams = (config?.params) || {};
302
+ let decryptedData, callbackTimeoutID;
303
+ let callbackFired = false
304
+ let runtimeEids = {}
305
+
306
+ const firePartnerCallback = () => {
307
+ if (configParams.callback && !callbackFired) {
308
+ callbackFired = true;
309
+ if (callbackTimeoutID) clearTimeout(callbackTimeoutID);
310
+ configParams.callback(runtimeEids, firstPartyData?.group || NOT_YET_DEFINED);
311
+ }
312
+ }
313
+
314
+ callbackTimeoutID = setTimeout(() => {
315
+ firePartnerCallback();
316
+ }, configParams.timeoutInMillis || 500
317
+ );
318
+
319
+ if (typeof configParams.partner !== 'number') {
125
320
  logError('User ID - intentIqId submodule requires a valid partner to be defined');
321
+ firePartnerCallback()
126
322
  return;
127
323
  }
128
- const cookieStorageEnabled = typeof configParams.enableCookieStorage === 'boolean' ? configParams.enableCookieStorage : false
129
- if (!FIRST_PARTY_DATA_KEY.includes(configParams.partner)) { FIRST_PARTY_DATA_KEY += '_' + configParams.partner; }
130
324
  let rrttStrtTime = 0;
325
+ let partnerData = {};
326
+ let shouldCallServer = false
327
+
328
+ const currentBrowserLowerCase = detectBrowser();
329
+ const browserBlackList = typeof configParams.browserBlackList === 'string' ? configParams.browserBlackList.toLowerCase() : '';
330
+ const allowedStorage = defineStorageType(config.enabledStorageTypes);
331
+
332
+ // Check if current browser is in blacklist
333
+ if (browserBlackList?.includes(currentBrowserLowerCase)) {
334
+ logError('User ID - intentIqId submodule: browser is in blacklist!');
335
+ if (configParams.callback) configParams.callback('', BLACK_LIST);
336
+ return;
337
+ }
338
+
339
+ // Get consent information
340
+ const cmpData = {};
341
+ const uspData = uspDataHandler.getConsentData();
342
+ const gppData = gppDataHandler.getConsentData();
343
+
344
+ if (uspData) {
345
+ cmpData.us_privacy = uspData;
346
+ }
347
+
348
+ if (gppData) {
349
+ cmpData.gpp = '';
350
+ cmpData.gpi = 1;
351
+
352
+ if (gppData.parsedSections && 'usnat' in gppData.parsedSections) {
353
+ cmpData.gpp = handleGPPData(gppData.parsedSections['usnat']);
354
+ cmpData.gpi = 0
355
+ }
356
+ cmpData.gpp_sid = gppData.applicableSections;
357
+ }
358
+
359
+ // Read client hints from storage
360
+ let clientHints = readData(CLIENT_HINTS_KEY, allowedStorage);
361
+
362
+ // Get client hints and save to storage
363
+ if (navigator.userAgentData) {
364
+ navigator.userAgentData
365
+ .getHighEntropyValues([
366
+ 'brands',
367
+ 'mobile',
368
+ 'bitness',
369
+ 'wow64',
370
+ 'architecture',
371
+ 'model',
372
+ 'platform',
373
+ 'platformVersion',
374
+ 'fullVersionList'
375
+ ])
376
+ .then(ch => {
377
+ clientHints = handleClientHints(ch);
378
+ storeData(CLIENT_HINTS_KEY, clientHints, allowedStorage)
379
+ });
380
+ }
381
+
382
+ if (!FIRST_PARTY_DATA_KEY.includes(configParams.partner)) {
383
+ FIRST_PARTY_DATA_KEY += '_' + configParams.partner;
384
+ }
131
385
 
132
386
  // Read Intent IQ 1st party id or generate it if none exists
133
- let firstPartyData = tryParse(readData(FIRST_PARTY_KEY));
134
- if (!firstPartyData || !firstPartyData.pcid || firstPartyData.pcidDate) {
387
+ let firstPartyData = tryParse(readData(FIRST_PARTY_KEY, allowedStorage));
388
+
389
+ if (!firstPartyData?.pcid) {
135
390
  const firstPartyId = generateGUID();
136
- firstPartyData = { 'pcid': firstPartyId, 'pcidDate': Date.now() };
137
- storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), cookieStorageEnabled);
391
+ firstPartyData = { pcid: firstPartyId, pcidDate: Date.now(), group: NOT_YET_DEFINED, cttl: 0, uspapi_value: EMPTY, gpp_value: EMPTY, date: Date.now() };
392
+ storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), allowedStorage);
393
+ } else if (!firstPartyData.pcidDate) {
394
+ firstPartyData.pcidDate = Date.now();
395
+ storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), allowedStorage);
396
+ }
397
+
398
+ const savedData = tryParse(readData(FIRST_PARTY_DATA_KEY, allowedStorage))
399
+ if (savedData) {
400
+ partnerData = savedData;
401
+ }
402
+
403
+ if (partnerData.data) {
404
+ if (partnerData.data.length) { // encrypted data
405
+ decryptedData = tryParse(decryptData(partnerData.data));
406
+ runtimeEids = decryptedData;
407
+ }
138
408
  }
139
409
 
140
- let partnerData = tryParse(readData(FIRST_PARTY_DATA_KEY));
141
- if (!partnerData) partnerData = {};
410
+ if (!firstPartyData.cttl || Date.now() - firstPartyData.date > firstPartyData.cttl || firstPartyData.uspapi_value !== cmpData.us_privacy || firstPartyData.gpp_value !== cmpData.gpp) {
411
+ firstPartyData.uspapi_value = cmpData.us_privacy;
412
+ firstPartyData.gpp_value = cmpData.gpp;
413
+ firstPartyData.isOptedOut = false
414
+ firstPartyData.cttl = 0
415
+ shouldCallServer = true;
416
+ partnerData.data = {}
417
+ storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), allowedStorage);
418
+ storeData(FIRST_PARTY_DATA_KEY, JSON.stringify(partnerData), allowedStorage);
419
+ } else if (firstPartyData.isOptedOut) {
420
+ firePartnerCallback()
421
+ }
422
+
423
+ if (firstPartyData.group === WITHOUT_IIQ || (firstPartyData.group !== WITHOUT_IIQ && runtimeEids && Object.keys(runtimeEids).length)) {
424
+ firePartnerCallback()
425
+ }
426
+
427
+ if (!shouldCallServer) {
428
+ firePartnerCallback();
429
+ return { id: runtimeEids };
430
+ }
142
431
 
143
432
  // use protocol relative urls for http or https
144
433
  let url = `https://api.intentiq.com/profiles_engine/ProfilesEngineServlet?at=39&mi=10&dpi=${configParams.partner}&pt=17&dpn=1`;
@@ -149,42 +438,97 @@ export const intentIqIdSubmodule = {
149
438
  url += (partnerData.cttl) ? '&cttl=' + encodeURIComponent(partnerData.cttl) : '';
150
439
  url += (partnerData.rrtt) ? '&rrtt=' + encodeURIComponent(partnerData.rrtt) : '';
151
440
  url += firstPartyData.pcidDate ? '&iiqpciddate=' + encodeURIComponent(firstPartyData.pcidDate) : '';
441
+ url += cmpData.us_privacy ? '&pa=' + encodeURIComponent(cmpData.us_privacy) : '';
442
+ url += cmpData.gpp ? '&gpv=' + encodeURIComponent(cmpData.gpp) : '';
443
+ url += cmpData.gpi ? '&gpi=' + cmpData.gpi : '';
444
+ url += clientHints ? '&uh=' + encodeURIComponent(clientHints) : '';
445
+ url += VERSION ? '&jsver=' + VERSION : '';
446
+ url += firstPartyData?.group ? '&testGroup=' + encodeURIComponent(firstPartyData.group) : '';
447
+
448
+ const storeFirstPartyData = () => {
449
+ storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), allowedStorage);
450
+ storeData(FIRST_PARTY_DATA_KEY, JSON.stringify(partnerData), allowedStorage);
451
+ }
152
452
 
153
453
  const resp = function (callback) {
154
454
  const callbacks = {
155
455
  success: response => {
156
456
  let respJson = tryParse(response);
157
457
  // If response is a valid json and should save is true
158
- if (respJson && respJson.ls) {
159
- // Store pid field if found in response json
160
- let shouldUpdateLs = false;
161
- if ('pid' in respJson) {
162
- firstPartyData.pid = respJson.pid;
163
- shouldUpdateLs = true;
458
+ if (respJson) {
459
+ partnerData.date = Date.now();
460
+ firstPartyData.date = Date.now();
461
+ const defineEmptyDataAndFireCallback = () => {
462
+ respJson.data = partnerData.data = runtimeEids = {};
463
+ removeDataByKey(FIRST_PARTY_DATA_KEY, allowedStorage)
464
+ firePartnerCallback()
465
+ callback()
164
466
  }
467
+ if (callbackTimeoutID) clearTimeout(callbackTimeoutID)
165
468
  if ('cttl' in respJson) {
166
- partnerData.cttl = respJson.cttl;
167
- shouldUpdateLs = true;
469
+ firstPartyData.cttl = respJson.cttl;
470
+ } else firstPartyData.cttl = 86400000;
471
+
472
+ if ('tc' in respJson) {
473
+ partnerData.terminationCause = respJson.tc;
474
+ if (respJson.tc == 41) {
475
+ firstPartyData.group = WITHOUT_IIQ;
476
+ storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), allowedStorage);
477
+ defineEmptyDataAndFireCallback();
478
+ return;
479
+ } else {
480
+ firstPartyData.group = WITH_IIQ;
481
+ }
168
482
  }
169
- // If should save and data is empty, means we should save as INVALID_ID
170
- if (respJson.data == '') {
171
- respJson.data = INVALID_ID;
172
- } else {
483
+ if ('isOptedOut' in respJson) {
484
+ if (respJson.isOptedOut !== firstPartyData.isOptedOut) {
485
+ firstPartyData.isOptedOut = respJson.isOptedOut;
486
+ }
487
+ if (respJson.isOptedOut === true) {
488
+ firstPartyData.group = OPT_OUT;
489
+ storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), allowedStorage);
490
+ defineEmptyDataAndFireCallback()
491
+ return;
492
+ }
493
+ }
494
+ if ('pid' in respJson) {
495
+ firstPartyData.pid = respJson.pid;
496
+ }
497
+ if ('ls' in respJson) {
498
+ if (respJson.ls === false) {
499
+ defineEmptyDataAndFireCallback();
500
+ return
501
+ }
502
+ // If data is empty, means we should save as INVALID_ID
503
+ if (respJson.data == '') {
504
+ respJson.data = INVALID_ID;
505
+ } else {
506
+ // If data is a single string, assume it is an id with source intentiq.com
507
+ if (respJson.data && typeof respJson.data === 'string') {
508
+ respJson.data = { eids: [respJson.data] }
509
+ }
510
+ }
173
511
  partnerData.data = respJson.data;
174
- shouldUpdateLs = true;
175
512
  }
513
+
176
514
  if (rrttStrtTime && rrttStrtTime > 0) {
177
515
  partnerData.rrtt = Date.now() - rrttStrtTime;
178
- shouldUpdateLs = true;
179
516
  }
180
- if (shouldUpdateLs === true) {
181
- partnerData.date = Date.now();
182
- storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), cookieStorageEnabled);
183
- storeData(FIRST_PARTY_DATA_KEY, JSON.stringify(partnerData), cookieStorageEnabled);
517
+
518
+ if (respJson.data?.eids) {
519
+ runtimeEids = respJson.data.eids
520
+ callback(respJson.data.eids);
521
+ firePartnerCallback()
522
+ const encryptedData = encryptData(JSON.stringify(respJson.data.eids))
523
+ partnerData.data = encryptedData;
524
+ } else {
525
+ callback();
526
+ firePartnerCallback()
184
527
  }
185
- callback(respJson.data);
528
+ storeFirstPartyData();
186
529
  } else {
187
530
  callback();
531
+ firePartnerCallback()
188
532
  }
189
533
  },
190
534
  error: error => {
@@ -192,18 +536,32 @@ export const intentIqIdSubmodule = {
192
536
  callback();
193
537
  }
194
538
  };
195
- if (partnerData.date && partnerData.cttl && partnerData.data &&
196
- Date.now() - partnerData.date < partnerData.cttl) { callback(partnerData.data); } else {
197
- rrttStrtTime = Date.now();
198
- ajax(url, callbacks, undefined, { method: 'GET', withCredentials: true });
199
- }
539
+
540
+ ajax(url, callbacks, undefined, { method: 'GET', withCredentials: true });
200
541
  };
201
- return { callback: resp };
542
+ const respObj = { callback: resp };
543
+ if (runtimeEids?.length) respObj.id = runtimeEids;
544
+ return respObj
202
545
  },
203
546
  eids: {
204
547
  'intentIqId': {
205
548
  source: 'intentiq.com',
206
- atype: 1
549
+ atype: 1,
550
+ getSource: function (data) {
551
+ return data.source;
552
+ },
553
+ getValue: function (data) {
554
+ if (data?.uids?.length) {
555
+ return data.uids[0].id
556
+ }
557
+ return null
558
+ },
559
+ getUidExt: function (data) {
560
+ if (data?.uids?.length) {
561
+ return data.uids[0].ext;
562
+ }
563
+ return null
564
+ }
207
565
  },
208
566
  }
209
567
  };
@@ -0,0 +1,92 @@
1
+ ```
2
+ Module Name: IntentIQ Id System
3
+ Module Type: Id System
4
+ Maintainer: julian@intentiq.com, dmytro.piskun@intentiq.com
5
+ usp_supported: true
6
+ gpp_sids: usnat
7
+ ```
8
+
9
+ # Intent IQ Universal ID module
10
+
11
+ By leveraging the Intent IQ identity graph, our module helps publishers, SSPs, and DSPs overcome the challenges of monetizing cookie-less inventory and preparing for a future without 3rd-party cookies. Our solution implements 1st-party data clustering and provides Intent IQ person IDs with over 90% coverage and unmatched accuracy in supported countries while remaining privacy-friendly and CCPA compliant. This results in increased CPMs, higher fill rates, and, ultimately, lifting overall revenue
12
+
13
+ # All you need is a few basic steps to start using our solution.
14
+
15
+ ## Registration
16
+
17
+ Navigate to [our portal ](https://www.intentiq.com/) and contact our team for partner ID.
18
+ check our [documentation](https://pbmodule.documents.intentiq.com/) to get more information about our solution and how utilze it's full potential
19
+
20
+ ## Integration
21
+
22
+ ```
23
+ gulp build –modules=intentIqIdSystem
24
+ ```
25
+
26
+ We recommend including the Intent IQ Analytics adapter module for improved visibility
27
+
28
+ ## Configuration
29
+
30
+ ### Parameters
31
+
32
+ Please find below list of paramters that could be used in configuring Intent IQ Universal ID module
33
+
34
+ | Param under userSync.userIds[] | Scope | Type | Description | Example |
35
+ | ------------------------------ | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
36
+ | name | Required | String | The name of this module: "intentIqId" | `"intentIqId"` |
37
+ | params | Required | Object | Details for IntentIqId initialization. | |
38
+ | params.partner | Required | Number | This is the partner ID value obtained from registering with IntentIQ. | `1177538` |
39
+ | params.pcid | Optional | String | This is the partner cookie ID, it is a dynamic value attached to the request. | `"g3hC52b"` |
40
+ | params.pai | Optional | String | This is the partner customer ID / advertiser ID, it is a dynamic value attached to the request. | `"advertiser1"` |
41
+ | params.callback | Required | Function | This is a callback which is trigered with data and AB group | `(data, group) => console.log({ data, group })` |
42
+ | params.timeoutInMillis | Optional | Number | This is the timeout in milliseconds, which defines the maximum duration before the callback is triggered. The default value is 500. | `450` |
43
+ | params.browserBlackList | Optional |  String | This is the name of a browser that can be added to a blacklist. | `"chrome"` |
44
+
45
+ ### Configuration example
46
+
47
+ ```javascript
48
+ pbjs.setConfig({
49
+ userSync: {
50
+ userIds: [
51
+ {
52
+ name: "intentIqId",
53
+ params: {
54
+ partner: 123456, // valid partner id
55
+ callback: (data, group) => window.pbjs.requestBids(),
56
+ },
57
+ storage: {
58
+ type: "html5",
59
+ name: "intentIqId", // set localstorage with this name
60
+ expires: 60,
61
+ refreshInSeconds: 4 * 3600, // refresh ID every 4 hours to ensure it's fresh
62
+ },
63
+ },
64
+ ],
65
+ syncDelay: 3000,
66
+ },
67
+ });
68
+ ```
69
+
70
+ ```javascript
71
+ pbjs.setConfig({
72
+ userSync: {
73
+ userIds: [{
74
+ name: "intentIqId",
75
+ params: {
76
+ partner: 123456 // valid partner id
77
+ pcid: PCID_VARIABLE, // string value, dynamically loaded into a variable before setting the configuration
78
+ pai: PAI_VARIABLE , // string value, dynamically loaded into a variable before setting the configuration
79
+ timeoutInMillis: 500,
80
+ browserBlackList: "chrome",
81
+ callback: (data, group) => window.pbjs.requestBids()
82
+ },
83
+ storage: {
84
+ type: "html5",
85
+ name: "intentIqId", // set localstorage with this name
86
+ expires: 60
87
+ }
88
+ }],
89
+ syncDelay: 3000
90
+ }
91
+ });
92
+ ```