• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

prebid / Prebid.js / 16809528788

07 Aug 2025 03:57PM UTC coverage: 96.254%. Remained the same
16809528788

push

github

web-flow
Risemediatech Bid Adapter : New Bidder Adapter (#13600)

* RM-845 : Initial implementation for risemediatech bid adapter

* RM-845 : Added bidder parameter documentation for risemediatech Bid Adapter

* RM-845 : minor modifications

* RM-845 : Handled es lint errors

* RM-847 : Unit Test for Risemediatech Bid Adapter

* Updated unit tests

* Modified the bid adapter code and unit tests

* Modified prebid js code to remove validations and also added bidfloor to the request.

* added the vastxml field in the response for the video media type

* Fixed incorrect media type issue

* Added test mode impressions support

* Added test mode for video ad units

* Added bidfloor for example video ad unit

* Updated default TTL

* Minro fixes

* Update docs

* Minor changes

* Minor changes

* Code cleanup

* Changes as per review

* Semantic changes

* Added support for Http Status 204 No Bids Scenarios

* Updated failing unit tests.

* Modified the check for no bids

* Reverted the status check

* linter modifications

* Updated the documentation for the adapter and formatted adapter

* Modified the documentation as per discussion

* Resolved linter errors from upstream repo PR

39576 of 48646 branches covered (81.36%)

237 of 244 new or added lines in 2 files covered. (97.13%)

148 existing lines in 17 files now uncovered.

195874 of 203497 relevant lines covered (96.25%)

123.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.75
/modules/intentIqIdSystem.js
1
/**
1✔
2
 * This module adds IntentIqId to the User ID module
3
 * The {@link module:modules/userId} module is required
4
 * @module modules/intentIqIdSystem
5
 * @requires module:modules/userId
6
 */
7

8
import {logError, isPlainObject, isStr, isNumber, getWinDimensions} from '../src/utils.js';
9
import {ajax} from '../src/ajax.js';
10
import {submodule} from '../src/hook.js'
11
import {detectBrowser} from '../libraries/intentIqUtils/detectBrowserUtils.js';
12
import {appendSPData} from '../libraries/intentIqUtils/urlUtils.js';
13
import {appendVrrefAndFui} from '../libraries/intentIqUtils/getRefferer.js';
14
import { getCmpData } from '../libraries/intentIqUtils/getCmpData.js';
15
import {readData, storeData, defineStorageType, removeDataByKey, tryParse} from '../libraries/intentIqUtils/storageUtils.js';
16
import {
17
  FIRST_PARTY_KEY,
18
  WITH_IIQ, WITHOUT_IIQ,
19
  NOT_YET_DEFINED,
20
  CLIENT_HINTS_KEY,
21
  EMPTY,
22
  GVLID,
23
  VERSION, INVALID_ID, SCREEN_PARAMS, SYNC_REFRESH_MILL, META_DATA_CONSTANT, PREBID,
24
  HOURS_24
25
} from '../libraries/intentIqConstants/intentIqConstants.js';
26
import {SYNC_KEY} from '../libraries/intentIqUtils/getSyncKey.js';
27
import {iiqPixelServerAddress, iiqServerAddress} from '../libraries/intentIqUtils/intentIqConfig.js';
28
import { handleAdditionalParams } from '../libraries/intentIqUtils/handleAdditionalParams.js';
29
import { decryptData, encryptData } from '../libraries/intentIqUtils/cryptionUtils.js';
30

31
/**
32
 * @typedef {import('../modules/userId/index.js').Submodule} Submodule
33
 * @typedef {import('../modules/userId/index.js').SubmoduleConfig} SubmoduleConfig
34
 * @typedef {import('../modules/userId/index.js').IdResponse} IdResponse
35
 */
36

37
const MODULE_NAME = 'intentIqId';
1✔
38

39
const encoderCH = {
1✔
40
  brands: 0,
41
  mobile: 1,
42
  platform: 2,
43
  architecture: 3,
44
  bitness: 4,
45
  model: 5,
46
  platformVersion: 6,
47
  wow64: 7,
48
  fullVersionList: 8
49
};
50
let sourceMetaData;
51
let sourceMetaDataExternal;
52

53
let FIRST_PARTY_KEY_FINAL = FIRST_PARTY_KEY;
1✔
54
let PARTNER_DATA_KEY;
55
let callCount = 0;
1✔
56
let failCount = 0;
1✔
57
let noDataCount = 0;
1✔
58

59
export let firstPartyData;
60

61
/**
62
 * Generate standard UUID string
63
 * @return {string}
64
 */
65
function generateGUID() {
66
  let d = new Date().getTime();
47✔
67
  const guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
47✔
68
    const r = (d + Math.random() * 16) % 16 | 0;
1,457✔
69
    d = Math.floor(d / 16);
1,457✔
70
    return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
1,457✔
71
  });
72
  return guid;
47✔
73
}
74

75
function collectDeviceInfo() {
76
  const windowDimensions = getWinDimensions();
14✔
77
  return {
14✔
78
    windowInnerHeight: windowDimensions.innerHeight,
79
    windowInnerWidth: windowDimensions.innerWidth,
80
    devicePixelRatio: windowDimensions.devicePixelRatio,
81
    windowScreenHeight: windowDimensions.screen.height,
82
    windowScreenWidth: windowDimensions.screen.width,
83
    language: navigator.language
84
  }
85
}
86

87
function addUniquenessToUrl(url) {
88
  url += '&tsrnd=' + Math.floor(Math.random() * 1000) + '_' + new Date().getTime();
14✔
89
  return url;
14✔
90
}
91

92
function appendDeviceInfoToUrl(url, deviceInfo) {
93
  const screenParamsString = Object.entries(SCREEN_PARAMS)
14✔
94
    .map(([index, param]) => {
84✔
95
      const value = (deviceInfo)[param];
84✔
96
      return `${index}:${value}`;
84✔
97
    })
98
    .join(',');
99

100
  url += `&cz=${encodeURIComponent(screenParamsString)}`;
14✔
101
  url += `&dw=${deviceInfo.windowScreenWidth}&dh=${deviceInfo.windowScreenHeight}&dpr=${deviceInfo.devicePixelRatio}&lan=${deviceInfo.language}`;
14✔
102
  return url;
14✔
103
}
104

105
function appendFirstPartyData (url, firstPartyData, partnerData) {
106
  url += firstPartyData.pid ? '&pid=' + encodeURIComponent(firstPartyData.pid) : '';
57!
107
  url += firstPartyData.pcid ? '&iiqidtype=2&iiqpcid=' + encodeURIComponent(firstPartyData.pcid) : '';
57✔
108
  url += firstPartyData.pcidDate ? '&iiqpciddate=' + encodeURIComponent(firstPartyData.pcidDate) : '';
57✔
109
  return url
57✔
110
}
111

112
function verifyIdType(value) {
113
  if (value === 0 || value === 1 || value === 3 || value === 4) return value;
23!
UNCOV
114
  return -1;
×
115
}
116

117
function appendPartnersFirstParty (url, configParams) {
118
  const partnerClientId = typeof configParams.partnerClientId === 'string' ? encodeURIComponent(configParams.partnerClientId) : '';
57✔
119
  const partnerClientIdType = typeof configParams.partnerClientIdType === 'number' ? verifyIdType(configParams.partnerClientIdType) : -1;
57✔
120

121
  if (partnerClientIdType === -1) return url;
57✔
122
  if (partnerClientId !== '') {
23✔
123
    url = url + '&pcid=' + partnerClientId;
21✔
124
    url = url + '&idtype=' + partnerClientIdType;
21✔
125
  }
126
  return url;
23✔
127
}
128

129
function appendCMPData (url, cmpData) {
130
  url += cmpData.uspString ? '&us_privacy=' + encodeURIComponent(cmpData.uspString) : '';
57✔
131
  url += cmpData.gppString ? '&gpp=' + encodeURIComponent(cmpData.gppString) : '';
57✔
132
  url += cmpData.gdprApplies
57✔
133
    ? '&gdpr_consent=' + encodeURIComponent(cmpData.gdprString) + '&gdpr=1'
134
    : '&gdpr=0';
135
  return url
57✔
136
}
137

138
function appendCounters (url) {
139
  url += '&jaesc=' + encodeURIComponent(callCount);
43✔
140
  url += '&jafc=' + encodeURIComponent(failCount);
43✔
141
  url += '&jaensc=' + encodeURIComponent(noDataCount);
43✔
142
  return url
43✔
143
}
144

145
/**
146
 * Translate and validate sourceMetaData
147
 */
148
export function translateMetadata(data) {
149
  try {
22✔
150
    const d = data.split('.');
22✔
151
    return (
22✔
152
      ((+d[0] * META_DATA_CONSTANT + +d[1]) * META_DATA_CONSTANT + +d[2]) * META_DATA_CONSTANT +
153
      +d[3]
154
    );
155
  } catch (e) {
UNCOV
156
    return NaN;
×
157
  }
158
}
159

160
/**
161
 * Add sourceMetaData to URL if valid
162
 */
163
function addMetaData(url, data) {
164
  if (typeof data !== 'number' || isNaN(data)) {
57✔
165
    return url;
38✔
166
  }
167
  return url + '&fbp=' + data;
19✔
168
}
169

170
export function createPixelUrl(firstPartyData, clientHints, configParams, partnerData, cmpData) {
171
  const deviceInfo = collectDeviceInfo();
14✔
172
  const browser = detectBrowser();
14✔
173

174
  let url = iiqPixelServerAddress(configParams, cmpData.gdprString);
14✔
175
  url += '/profiles_engine/ProfilesEngineServlet?at=20&mi=10&secure=1';
14✔
176
  url += '&dpi=' + configParams.partner;
14✔
177
  url = appendFirstPartyData(url, firstPartyData, partnerData);
14✔
178
  url = appendPartnersFirstParty(url, configParams);
14✔
179
  url = addUniquenessToUrl(url);
14✔
180
  url += partnerData?.clientType ? '&idtype=' + partnerData.clientType : '';
14!
181
  if (deviceInfo) url = appendDeviceInfoToUrl(url, deviceInfo);
14✔
182
  url += VERSION ? '&jsver=' + VERSION : '';
14!
183
  if (clientHints) url += '&uh=' + encodeURIComponent(clientHints);
14✔
184
  url = appendVrrefAndFui(url, configParams.domainName);
14✔
185
  url = appendCMPData(url, cmpData);
14✔
186
  url = addMetaData(url, sourceMetaDataExternal || sourceMetaData);
14✔
187
  url = handleAdditionalParams(browser, url, 0, configParams.additionalParams);
14✔
188
  url = appendSPData(url, firstPartyData)
14✔
189
  url += '&source=' + PREBID;
14✔
190
  return url;
14✔
191
}
192

193
function sendSyncRequest(allowedStorage, url, partner, firstPartyData, newUser) {
194
  const lastSyncDate = Number(readData(SYNC_KEY(partner) || '', allowedStorage)) || false;
12!
195
  const lastSyncElapsedTime = Date.now() - lastSyncDate
12✔
196

197
  if (firstPartyData.isOptedOut) {
12!
UNCOV
198
    const needToDoSync = (Date.now() - (firstPartyData?.date || firstPartyData?.sCal || Date.now())) > SYNC_REFRESH_MILL
×
UNCOV
199
    if (newUser || needToDoSync) {
×
UNCOV
200
      ajax(url, () => {
×
201
      }, undefined, {method: 'GET', withCredentials: true});
UNCOV
202
      if (firstPartyData?.date) {
×
UNCOV
203
        firstPartyData.date = Date.now()
×
UNCOV
204
        storeData(FIRST_PARTY_KEY_FINAL, JSON.stringify(firstPartyData), allowedStorage, firstPartyData);
×
205
      }
206
    }
207
  } else if (!lastSyncDate || lastSyncElapsedTime > SYNC_REFRESH_MILL) {
12!
208
    storeData(SYNC_KEY(partner), Date.now() + '', allowedStorage);
12✔
209
    ajax(url, () => {
12✔
210
    }, undefined, {method: 'GET', withCredentials: true});
211
  }
212
}
213

214
/**
215
 * Configures and updates A/B testing group in Google Ad Manager (GAM).
216
 *
217
 * @param {object} gamObjectReference - Reference to the GAM object, expected to have a `cmd` queue and `pubads()` API.
218
 * @param {string} gamParameterName - The name of the GAM targeting parameter where the group value will be stored.
219
 * @param {string} userGroup - The A/B testing group assigned to the user (e.g., 'A', 'B', or a custom value).
220
 */
221
export function setGamReporting(gamObjectReference, gamParameterName, userGroup) {
222
  if (isPlainObject(gamObjectReference) && gamObjectReference.cmd) {
59✔
223
    gamObjectReference.cmd.push(() => {
25✔
224
      gamObjectReference
3✔
225
        .pubads()
226
        .setTargeting(gamParameterName, userGroup || NOT_YET_DEFINED);
5✔
227
    });
228
  }
229
}
230

231
/**
232
 * Processes raw client hints data into a structured format.
233
 * @param {object} clientHints - Raw client hints data
234
 * @return {string} A JSON string of processed client hints or an empty string if no hints
235
 */
236
export function handleClientHints(clientHints) {
237
  const chParams = {};
34✔
238
  for (const key in clientHints) {
34✔
239
    if (clientHints.hasOwnProperty(key) && clientHints[key] !== '') {
306✔
240
      if (['brands', 'fullVersionList'].includes(key)) {
272✔
241
        let handledParam = '';
68✔
242
        clientHints[key].forEach((element, index) => {
68✔
243
          const isNotLast = index < clientHints[key].length - 1;
136✔
244
          handledParam += `"${element.brand}";v="${element.version}"${isNotLast ? ', ' : ''}`;
136✔
245
        });
246
        chParams[encoderCH[key]] = handledParam;
68✔
247
      } else if (typeof clientHints[key] === 'boolean') {
204✔
248
        chParams[encoderCH[key]] = `?${clientHints[key] ? 1 : 0}`;
68!
249
      } else {
250
        chParams[encoderCH[key]] = `"${clientHints[key]}"`;
136✔
251
      }
252
    }
253
  }
254
  return Object.keys(chParams).length ? JSON.stringify(chParams) : '';
34!
255
}
256

257
export function isCMPStringTheSame(fpData, cmpData) {
258
  const firstPartyDataCPString = `${fpData.gdprString}${fpData.gppString}${fpData.uspString}`;
64✔
259
  const cmpDataString = `${cmpData.gdprString}${cmpData.gppString}${cmpData.uspString}`;
64✔
260
  return firstPartyDataCPString === cmpDataString;
64✔
261
}
262

263
function updateCountersAndStore(runtimeEids, allowedStorage, partnerData) {
264
  if (!runtimeEids?.eids?.length) {
19✔
265
    noDataCount++;
13✔
266
  } else {
267
    callCount++;
6✔
268
  }
269
  storeCounters(allowedStorage, partnerData);
19✔
270
}
271

272
function clearCountersAndStore(allowedStorage, partnerData) {
273
  callCount = 0;
39✔
274
  failCount = 0;
39✔
275
  noDataCount = 0;
39✔
276
  storeCounters(allowedStorage, partnerData);
39✔
277
}
278

279
function storeCounters(storage, partnerData) {
280
  partnerData.callCount = callCount;
58✔
281
  partnerData.failCount = failCount;
58✔
282
  partnerData.noDataCounter = noDataCount;
58✔
283
  storeData(PARTNER_DATA_KEY, JSON.stringify(partnerData), storage, firstPartyData);
58✔
284
}
285

286
/** @type {Submodule} */
287
export const intentIqIdSubmodule = {
1✔
288
  /**
289
   * used to link submodule with config
290
   * @type {string}
291
   */
292
  name: MODULE_NAME,
293
  gvlid: GVLID,
294
  /**
295
   * decode the stored id value for passing to bid requests
296
   * @function
297
   * @param {{string}} value
298
   * @returns {{intentIqId: {string}}|undefined}
299
   */
300
  decode(value) {
301
    return value && value != '' && INVALID_ID != value ? {'intentIqId': value} : undefined;
3!
302
  },
303

304
  /**
305
   * performs action to obtain id and return a value in the callback's response argument
306
   * @function
307
   * @param {SubmoduleConfig} [config]
308
   * @returns {IdResponse|undefined}
309
   */
310
  getId(config) {
311
    const configParams = (config?.params) || {};
59!
312

313
    const firePartnerCallback = () => {
59✔
314
      if (configParams.callback && !callbackFired) {
67✔
315
        callbackFired = true;
2✔
316
        if (callbackTimeoutID) clearTimeout(callbackTimeoutID);
2✔
317
        if (isGroupB) runtimeEids = { eids: [] };
2!
318
        configParams.callback(runtimeEids);
2✔
319
      }
320
    }
321

322
    if (typeof configParams.partner !== 'number') {
59✔
323
      logError('User ID - intentIqId submodule requires a valid partner to be defined');
3✔
324
      firePartnerCallback()
3✔
325
      return;
3✔
326
    }
327

328
    let decryptedData, callbackTimeoutID;
329
    let callbackFired = false;
56✔
330
    let runtimeEids = { eids: [] };
56✔
331

332
    const gamObjectReference = isPlainObject(configParams.gamObjectReference) ? configParams.gamObjectReference : undefined;
56✔
333
    const gamParameterName = configParams.gamParameterName ? configParams.gamParameterName : 'intent_iq_group';
56✔
334
    const groupChanged = typeof configParams.groupChanged === 'function' ? configParams.groupChanged : undefined;
56✔
335
    const siloEnabled = typeof configParams.siloEnabled === 'boolean' ? configParams.siloEnabled : false;
56✔
336
    sourceMetaData = isStr(configParams.sourceMetaData) ? translateMetadata(configParams.sourceMetaData) : '';
56✔
337
    sourceMetaDataExternal = isNumber(configParams.sourceMetaDataExternal) ? configParams.sourceMetaDataExternal : undefined;
56✔
338
    const additionalParams = configParams.additionalParams ? configParams.additionalParams : undefined;
56✔
339
    PARTNER_DATA_KEY = `${FIRST_PARTY_KEY}_${configParams.partner}`;
56✔
340

341
    const allowedStorage = defineStorageType(config.enabledStorageTypes);
56✔
342

343
    let rrttStrtTime = 0;
56✔
344
    let partnerData = {};
56✔
345
    let shouldCallServer = false;
56✔
346
    FIRST_PARTY_KEY_FINAL = `${FIRST_PARTY_KEY}${siloEnabled ? '_p_' + configParams.partner : ''}`;
56✔
347
    const cmpData = getCmpData();
56✔
348
    const gdprDetected = cmpData.gdprString;
56✔
349
    firstPartyData = tryParse(readData(FIRST_PARTY_KEY_FINAL, allowedStorage));
56✔
350
    const isGroupB = firstPartyData?.group === WITHOUT_IIQ;
56✔
351
    setGamReporting(gamObjectReference, gamParameterName, firstPartyData?.group);
56✔
352

353
    if (groupChanged) groupChanged(firstPartyData?.group || NOT_YET_DEFINED);
56✔
354

355
    callbackTimeoutID = setTimeout(() => {
56✔
356
      firePartnerCallback();
37✔
357
    }, configParams.timeoutInMillis || 500
112✔
358
    );
359

360
    const currentBrowserLowerCase = detectBrowser();
56✔
361
    const browserBlackList = typeof configParams.browserBlackList === 'string' ? configParams.browserBlackList.toLowerCase() : '';
56✔
362
    let newUser = false;
56✔
363

364
    if (!firstPartyData?.pcid) {
56✔
365
      const firstPartyId = generateGUID();
47✔
366
      firstPartyData = {
47✔
367
        pcid: firstPartyId,
368
        pcidDate: Date.now(),
369
        group: NOT_YET_DEFINED,
370
        uspString: EMPTY,
371
        gppString: EMPTY,
372
        gdprString: EMPTY,
373
        date: Date.now()
374
      };
375
      newUser = true;
47✔
376
      storeData(FIRST_PARTY_KEY_FINAL, JSON.stringify(firstPartyData), allowedStorage, firstPartyData);
47✔
377
    } else if (!firstPartyData.pcidDate) {
9✔
378
      firstPartyData.pcidDate = Date.now();
7✔
379
      storeData(FIRST_PARTY_KEY_FINAL, JSON.stringify(firstPartyData), allowedStorage, firstPartyData);
7✔
380
    }
381

382
    if (gdprDetected && !('isOptedOut' in firstPartyData)) {
56✔
383
      firstPartyData.isOptedOut = true;
4✔
384
    }
385

386
    // Read client hints from storage
387
    let clientHints = readData(CLIENT_HINTS_KEY, allowedStorage);
56✔
388

389
    // Get client hints and save to storage
390
    if (navigator?.userAgentData?.getHighEntropyValues) {
56✔
391
      navigator.userAgentData
33✔
392
        .getHighEntropyValues([
393
          'brands',
394
          'mobile',
395
          'bitness',
396
          'wow64',
397
          'architecture',
398
          'model',
399
          'platform',
400
          'platformVersion',
401
          'fullVersionList'
402
        ])
403
        .then(ch => {
404
          clientHints = handleClientHints(ch);
33✔
405
          storeData(CLIENT_HINTS_KEY, clientHints, allowedStorage, firstPartyData)
33✔
406
        });
407
    }
408

409
    const savedData = tryParse(readData(PARTNER_DATA_KEY, allowedStorage))
56✔
410
    if (savedData) {
56✔
411
      partnerData = savedData;
6✔
412

413
      if (typeof partnerData.callCount === 'number') callCount = partnerData.callCount;
6✔
414
      if (typeof partnerData.failCount === 'number') failCount = partnerData.failCount;
6✔
415
      if (typeof partnerData.noDataCounter === 'number') noDataCount = partnerData.noDataCounter;
6✔
416

417
      if (partnerData.wsrvcll) {
6!
UNCOV
418
        partnerData.wsrvcll = false;
×
UNCOV
419
        storeData(PARTNER_DATA_KEY, JSON.stringify(partnerData), allowedStorage, firstPartyData);
×
420
      }
421
    }
422

423
    if (partnerData.data) {
56✔
424
      if (partnerData.data.length) { // encrypted data
1✔
425
        decryptedData = tryParse(decryptData(partnerData.data));
1✔
426
        runtimeEids = decryptedData;
1✔
427
      }
428
    }
429

430
    if (!isCMPStringTheSame(firstPartyData, cmpData) ||
56!
431
          !firstPartyData.sCal ||
432
          (savedData && (!partnerData.cttl || !partnerData.date || Date.now() - partnerData.date > partnerData.cttl))) {
433
      firstPartyData.uspString = cmpData.uspString;
54✔
434
      firstPartyData.gppString = cmpData.gppString;
54✔
435
      firstPartyData.gdprString = cmpData.gdprString;
54✔
436
      shouldCallServer = true;
54✔
437
      storeData(FIRST_PARTY_KEY_FINAL, JSON.stringify(firstPartyData), allowedStorage, firstPartyData);
54✔
438
      storeData(PARTNER_DATA_KEY, JSON.stringify(partnerData), allowedStorage, firstPartyData);
54✔
439
    }
440
    if (!shouldCallServer) {
56✔
441
      if (!savedData && !firstPartyData.isOptedOut) {
2✔
442
        shouldCallServer = true;
1✔
443
      } else shouldCallServer = Date.now() > firstPartyData.sCal + HOURS_24;
1✔
444
    }
445

446
    if (firstPartyData.isOptedOut) {
56✔
447
      partnerData.data = runtimeEids = { eids: [] };
5✔
448
      firePartnerCallback()
5✔
449
    }
450

451
    if (firstPartyData.group === WITHOUT_IIQ || (firstPartyData.group !== WITHOUT_IIQ && runtimeEids?.eids?.length)) {
56✔
452
      firePartnerCallback()
1✔
453
    }
454

455
    // Check if current browser is in blacklist
456
    if (browserBlackList?.includes(currentBrowserLowerCase)) {
56✔
457
      logError('User ID - intentIqId submodule: browser is in blacklist! Data will be not provided.');
12✔
458
      if (configParams.callback) configParams.callback('');
12✔
459
      const url = createPixelUrl(firstPartyData, clientHints, configParams, partnerData, cmpData)
12✔
460
      sendSyncRequest(allowedStorage, url, configParams.partner, firstPartyData, newUser)
12✔
461
      return
12✔
462
    }
463

464
    if (!shouldCallServer) {
44✔
465
      if (isGroupB) runtimeEids = { eids: [] };
1!
466
      firePartnerCallback();
1✔
467
      updateCountersAndStore(runtimeEids, allowedStorage, partnerData);
1✔
468
      return { id: runtimeEids.eids };
1✔
469
    }
470

471
    // use protocol relative urls for http or https
472
    let url = `${iiqServerAddress(configParams, gdprDetected)}/profiles_engine/ProfilesEngineServlet?at=39&mi=10&dpi=${configParams.partner}&pt=17&dpn=1`;
43✔
473
    url += configParams.pai ? '&pai=' + encodeURIComponent(configParams.pai) : '';
43✔
474
    url = appendFirstPartyData(url, firstPartyData, partnerData);
43✔
475
    url = appendPartnersFirstParty(url, configParams);
43✔
476
    url += (partnerData.cttl) ? '&cttl=' + encodeURIComponent(partnerData.cttl) : '';
43✔
477
    url += (partnerData.rrtt) ? '&rrtt=' + encodeURIComponent(partnerData.rrtt) : '';
43✔
478
    url = appendCMPData(url, cmpData);
43✔
479
    url += '&japs=' + encodeURIComponent(configParams.siloEnabled === true);
43✔
480
    url = appendCounters(url);
43✔
481
    url += clientHints ? '&uh=' + encodeURIComponent(clientHints) : '';
43✔
482
    url += VERSION ? '&jsver=' + VERSION : '';
43!
483
    url += firstPartyData?.group ? '&testGroup=' + encodeURIComponent(firstPartyData.group) : '';
43✔
484
    url = addMetaData(url, sourceMetaDataExternal || sourceMetaData);
43✔
485
    url = handleAdditionalParams(currentBrowserLowerCase, url, 1, additionalParams);
43✔
486
    url = appendSPData(url, firstPartyData)
43✔
487
    url += '&source=' + PREBID;
43✔
488

489
    // Add vrref and fui to the URL
490
    url = appendVrrefAndFui(url, configParams.domainName);
43✔
491

492
    const storeFirstPartyData = () => {
43✔
493
      partnerData.eidl = runtimeEids?.eids?.length || -1
18✔
494
      storeData(FIRST_PARTY_KEY_FINAL, JSON.stringify(firstPartyData), allowedStorage, firstPartyData);
18✔
495
      storeData(PARTNER_DATA_KEY, JSON.stringify(partnerData), allowedStorage, firstPartyData);
18✔
496
    }
497

498
    const resp = function (callback) {
43✔
499
      const callbacks = {
39✔
500
        success: response => {
501
          const respJson = tryParse(response);
20✔
502
          // If response is a valid json and should save is true
503
          if (respJson) {
20✔
504
            partnerData.date = Date.now();
19✔
505
            firstPartyData.sCal = Date.now();
19✔
506
            const defineEmptyDataAndFireCallback = () => {
19✔
507
              respJson.data = partnerData.data = runtimeEids = { eids: [] };
2✔
508
              storeFirstPartyData()
2✔
509
              firePartnerCallback()
2✔
510
              callback(runtimeEids)
2✔
511
            }
512
            if (callbackTimeoutID) clearTimeout(callbackTimeoutID)
19✔
513
            if ('cttl' in respJson) {
19!
UNCOV
514
              partnerData.cttl = respJson.cttl;
×
515
            } else partnerData.cttl = HOURS_24;
19✔
516

517
            if ('tc' in respJson) {
19✔
518
              partnerData.terminationCause = respJson.tc;
4✔
519
              if (respJson.tc == 41) {
4✔
520
                firstPartyData.group = WITHOUT_IIQ;
1✔
521
                storeData(FIRST_PARTY_KEY_FINAL, JSON.stringify(firstPartyData), allowedStorage, firstPartyData);
1✔
522
                if (groupChanged) groupChanged(firstPartyData.group);
1✔
523
                defineEmptyDataAndFireCallback();
1✔
524
                if (gamObjectReference) setGamReporting(gamObjectReference, gamParameterName, firstPartyData.group);
1✔
525
                return
1✔
526
              } else {
527
                firstPartyData.group = WITH_IIQ;
3✔
528
                if (gamObjectReference) setGamReporting(gamObjectReference, gamParameterName, firstPartyData.group);
3✔
529
                if (groupChanged) groupChanged(firstPartyData.group);
3✔
530
              }
531
            }
532
            if ('isOptedOut' in respJson) {
18✔
533
              if (respJson.isOptedOut !== firstPartyData.isOptedOut) {
4✔
534
                firstPartyData.isOptedOut = respJson.isOptedOut;
3✔
535
              }
536
              if (respJson.isOptedOut === true) {
4✔
537
                respJson.data = partnerData.data = runtimeEids = { eids: [] };
1✔
538

539
                const keysToRemove = [
1✔
540
                  PARTNER_DATA_KEY,
541
                  CLIENT_HINTS_KEY
542
                ];
543

544
                keysToRemove.forEach(key => removeDataByKey(key, allowedStorage));
2✔
545

546
                storeData(FIRST_PARTY_KEY_FINAL, JSON.stringify(firstPartyData), allowedStorage, firstPartyData);
1✔
547
                firePartnerCallback();
1✔
548
                callback(runtimeEids);
1✔
549
                return
1✔
550
              }
551
            }
552
            if ('pid' in respJson) {
17✔
553
              firstPartyData.pid = respJson.pid;
5✔
554
            }
555
            if ('dbsaved' in respJson) {
17✔
556
              firstPartyData.dbsaved = respJson.dbsaved;
1✔
557
            }
558
            if ('ls' in respJson) {
17✔
559
              if (respJson.ls === false) {
8✔
560
                defineEmptyDataAndFireCallback()
1✔
561
                return
1✔
562
              }
563
              // If data is empty, means we should save as INVALID_ID
564
              if (respJson.data == '') {
7!
UNCOV
565
                respJson.data = INVALID_ID;
×
566
              } else {
567
                // If data is a single string, assume it is an id with source intentiq.com
568
                if (respJson.data && typeof respJson.data === 'string') {
7✔
569
                  respJson.data = {eids: [respJson.data]}
5✔
570
                }
571
              }
572
              partnerData.data = respJson.data;
7✔
573
            }
574

575
            if ('ct' in respJson) {
16✔
576
              partnerData.clientType = respJson.ct;
1✔
577
            }
578

579
            if ('sid' in respJson) {
16!
UNCOV
580
              partnerData.siteId = respJson.sid;
×
581
            }
582

583
            if ('spd' in respJson) {
16✔
584
              // server provided data
585
              firstPartyData.spd = respJson.spd;
1✔
586
            }
587

588
            if (rrttStrtTime && rrttStrtTime > 0) {
16✔
589
              partnerData.rrtt = Date.now() - rrttStrtTime;
16✔
590
            }
591

592
            if (respJson.data?.eids) {
16✔
593
              runtimeEids = respJson.data
8✔
594
              callback(respJson.data.eids);
8✔
595
              firePartnerCallback()
8✔
596
              const encryptedData = encryptData(JSON.stringify(respJson.data));
8✔
597
              partnerData.data = encryptedData;
8✔
598
            } else {
599
              callback(runtimeEids);
8✔
600
              firePartnerCallback()
8✔
601
            }
602
            updateCountersAndStore(runtimeEids, allowedStorage, partnerData);
16✔
603
            storeFirstPartyData();
16✔
604
          } else {
605
            callback(runtimeEids);
1✔
606
            firePartnerCallback()
1✔
607
          }
608
        },
609
        error: error => {
610
          logError(MODULE_NAME + ': ID fetch encountered an error', error);
2✔
611
          failCount++;
2✔
612
          updateCountersAndStore(runtimeEids, allowedStorage, partnerData);
2✔
613
          callback(runtimeEids);
2✔
614
        }
615
      };
616
      rrttStrtTime = Date.now();
39✔
617

618
      partnerData.wsrvcll = true;
39✔
619
      storeData(PARTNER_DATA_KEY, JSON.stringify(partnerData), allowedStorage, firstPartyData);
39✔
620
      clearCountersAndStore(allowedStorage, partnerData);
39✔
621

622
      ajax(url, callbacks, undefined, {method: 'GET', withCredentials: true});
39✔
623
    };
624
    const respObj = {callback: resp};
43✔
625

626
    if (runtimeEids?.eids?.length) respObj.id = runtimeEids.eids;
43✔
627
    return respObj
43✔
628
  },
629
  eids: {
630
    'intentIqId': {
631
      source: 'intentiq.com',
632
      atype: 1,
633
      getSource: function (data) {
UNCOV
634
        return data.source;
×
635
      },
636
      getValue: function (data) {
UNCOV
637
        if (data?.uids?.length) {
×
UNCOV
638
          return data.uids[0].id
×
639
        }
UNCOV
640
        return null
×
641
      },
642
      getUidExt: function (data) {
UNCOV
643
        if (data?.uids?.length) {
×
UNCOV
644
          return data.uids[0].ext;
×
645
        }
UNCOV
646
        return null
×
647
      }
648
    },
649
  }
650
};
651

652
submodule('userId', intentIqIdSubmodule);
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc