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

prebid / Prebid.js / #294

01 May 2025 06:47PM UTC coverage: 90.113% (+0.09%) from 90.019%
#294

push

travis-ci

prebidjs-release
Prebid 9.42.0 release

42642 of 53640 branches covered (79.5%)

63333 of 70282 relevant lines covered (90.11%)

179.12 hits per line

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

87.3
/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, getWinDimensions} from '../src/utils.js';
9
import {ajax} from '../src/ajax.js';
10
import {submodule} from '../src/hook.js'
11
import AES from 'crypto-js/aes.js';
12
import Utf8 from 'crypto-js/enc-utf8.js';
13
import {detectBrowser} from '../libraries/intentIqUtils/detectBrowserUtils.js';
14
import {appendVrrefAndFui} from '../libraries/intentIqUtils/getRefferer.js';
15
import { getCmpData } from '../libraries/intentIqUtils/getCmpData.js';
16
import {readData, storeData, defineStorageType, removeDataByKey} from '../libraries/intentIqUtils/storageUtils.js';
17
import {
18
  FIRST_PARTY_KEY,
19
  WITH_IIQ, WITHOUT_IIQ,
20
  NOT_YET_DEFINED,
21
  BLACK_LIST,
22
  CLIENT_HINTS_KEY,
23
  EMPTY,
24
  GVLID,
25
  VERSION, INVALID_ID, GDPR_ENDPOINT, VR_ENDPOINT, SYNC_ENDPOINT, SCREEN_PARAMS, GDPR_SYNC_ENDPOINT, SYNC_REFRESH_MILL
26
} from '../libraries/intentIqConstants/intentIqConstants.js';
27
import {SYNC_KEY} from '../libraries/intentIqUtils/getSyncKey.js';
28

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

35
const MODULE_NAME = 'intentIqId';
1✔
36

37
const encoderCH = {
1✔
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
};
48

49
export let firstPartyData;
50

51
/**
52
 * Generate standard UUID string
53
 * @return {string}
54
 */
55
function generateGUID() {
56
  let d = new Date().getTime();
22✔
57
  const guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
22✔
58
    const r = (d + Math.random() * 16) % 16 | 0;
682✔
59
    d = Math.floor(d / 16);
682✔
60
    return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
682✔
61
  });
62
  return guid;
22✔
63
}
64

65
/**
66
 * Encrypts plaintext.
67
 * @param {string} plainText The plaintext to encrypt.
68
 * @returns {string} The encrypted text as a base64 string.
69
 */
70
export function encryptData(plainText) {
71
  return AES.encrypt(plainText, MODULE_NAME).toString();
4✔
72
}
73

74
/**
75
 * Decrypts ciphertext.
76
 * @param {string} encryptedText The encrypted text as a base64 string.
77
 * @returns {string} The decrypted plaintext.
78
 */
79
export function decryptData(encryptedText) {
80
  const bytes = AES.decrypt(encryptedText, MODULE_NAME);
3✔
81
  return bytes.toString(Utf8);
3✔
82
}
83

84
function collectDeviceInfo() {
85
  return {
4✔
86
    windowInnerHeight: getWinDimensions().innerHeight,
87
    windowInnerWidth: getWinDimensions().innerWidth,
88
    devicePixelRatio: window.devicePixelRatio,
89
    windowScreenHeight: window.screen.height,
90
    windowScreenWidth: window.screen.width,
91
    language: navigator.language
92
  }
93
}
94

95
function addUniquenessToUrl(url) {
96
  url += '&tsrnd=' + Math.floor(Math.random() * 1000) + '_' + new Date().getTime();
4✔
97
  return url;
4✔
98
}
99

100
function appendDeviceInfoToUrl(url, deviceInfo) {
101
  const screenParamsString = Object.entries(SCREEN_PARAMS)
4✔
102
    .map(([index, param]) => {
103
      const value = (deviceInfo)[param];
24✔
104
      return `${index}:${value}`;
24✔
105
    })
106
    .join(',');
107

108
  url += `&cz=${encodeURIComponent(screenParamsString)}`;
4✔
109
  url += `&dw=${deviceInfo.windowScreenWidth}&dh=${deviceInfo.windowScreenHeight}&dpr=${deviceInfo.devicePixelRatio}&lan=${deviceInfo.language}`;
4✔
110
  return url;
4✔
111
}
112

113
function appendFirstPartyData (url, firstPartyData, partnerData) {
114
  url += firstPartyData.pid ? '&pid=' + encodeURIComponent(firstPartyData.pid) : '';
24!
115
  url += firstPartyData.pcid ? '&iiqidtype=2&iiqpcid=' + encodeURIComponent(firstPartyData.pcid) : '';
24✔
116
  url += firstPartyData.pcidDate ? '&iiqpciddate=' + encodeURIComponent(firstPartyData.pcidDate) : '';
24✔
117
  return url
24✔
118
}
119

120
function appendCMPData (url, cmpData) {
121
  url += cmpData.uspString ? '&us_privacy=' + encodeURIComponent(cmpData.uspString) : '';
24✔
122
  url += cmpData.gppString ? '&gpp=' + encodeURIComponent(cmpData.gppString) : '';
24✔
123
  url += cmpData.gdprApplies
24✔
124
    ? '&gdpr_consent=' + encodeURIComponent(cmpData.gdprString) + '&gdpr=1'
125
    : '&gdpr=0';
126
  return url
24✔
127
}
128

129
export function createPixelUrl(firstPartyData, clientHints, configParams, partnerData, cmpData) {
130
  const deviceInfo = collectDeviceInfo()
4✔
131

132
  let url = cmpData.gdprString ? GDPR_SYNC_ENDPOINT : SYNC_ENDPOINT;
4!
133
  url += '/profiles_engine/ProfilesEngineServlet?at=20&mi=10&secure=1'
4✔
134
  url += '&dpi=' + configParams.partner;
4✔
135
  url = appendFirstPartyData(url, firstPartyData, partnerData);
4✔
136
  url = addUniquenessToUrl(url);
4✔
137
  url += partnerData?.clientType ? '&idtype=' + partnerData.clientType : '';
4!
138
  if (deviceInfo) url = appendDeviceInfoToUrl(url, deviceInfo)
4!
139
  url += VERSION ? '&jsver=' + VERSION : '';
4!
140
  if (clientHints) url += '&uh=' + encodeURIComponent(clientHints);
4✔
141
  url = appendVrrefAndFui(url, configParams.domainName);
4✔
142
  url = appendCMPData(url, cmpData)
4✔
143
  return url;
4✔
144
}
145

146
function sendSyncRequest(allowedStorage, url, partner, firstPartyData, newUser) {
147
  const lastSyncDate = Number(readData(SYNC_KEY(partner) || '', allowedStorage)) || false;
2!
148
  const lastSyncElapsedTime = Date.now() - lastSyncDate
2✔
149

150
  if (firstPartyData.isOptedOut) {
2!
151
    const needToDoSync = (Date.now() - (firstPartyData?.date || firstPartyData?.sCal || Date.now())) > SYNC_REFRESH_MILL
×
152
    if (newUser || needToDoSync) {
×
153
      ajax(url, () => {
×
154
      }, undefined, {method: 'GET', withCredentials: true});
155
      if (firstPartyData?.date) {
×
156
        firstPartyData.date = Date.now()
×
157
        storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), allowedStorage, firstPartyData);
×
158
      }
159
    }
160
  } else if (!lastSyncDate || lastSyncElapsedTime > SYNC_REFRESH_MILL) {
2!
161
    storeData(SYNC_KEY(partner), Date.now() + '', allowedStorage);
2✔
162
    ajax(url, () => {
2✔
163
    }, undefined, {method: 'GET', withCredentials: true});
164
  }
165
}
166

167
/**
168
 * Parse json if possible, else return null
169
 * @param data
170
 */
171
function tryParse(data) {
172
  try {
63✔
173
    return JSON.parse(data);
63✔
174
  } catch (err) {
175
    logError(err);
2✔
176
    return null;
2✔
177
  }
178
}
179

180
/**
181
 * Configures and updates A/B testing group in Google Ad Manager (GAM).
182
 *
183
 * @param {object} gamObjectReference - Reference to the GAM object, expected to have a `cmd` queue and `pubads()` API.
184
 * @param {string} gamParameterName - The name of the GAM targeting parameter where the group value will be stored.
185
 * @param {string} userGroup - The A/B testing group assigned to the user (e.g., 'A', 'B', or a custom value).
186
 */
187
export function setGamReporting(gamObjectReference, gamParameterName, userGroup) {
188
  if (isPlainObject(gamObjectReference) && gamObjectReference.cmd) {
26✔
189
    gamObjectReference.cmd.push(() => {
10✔
190
      gamObjectReference
3✔
191
        .pubads()
192
        .setTargeting(gamParameterName, userGroup || NOT_YET_DEFINED);
5✔
193
    });
194
  }
195
}
196

197
/**
198
 * Processes raw client hints data into a structured format.
199
 * @param {object} clientHints - Raw client hints data
200
 * @return {string} A JSON string of processed client hints or an empty string if no hints
201
 */
202
export function handleClientHints(clientHints) {
203
  const chParams = {};
23✔
204
  for (const key in clientHints) {
23✔
205
    if (clientHints.hasOwnProperty(key) && clientHints[key] !== '') {
207✔
206
      if (['brands', 'fullVersionList'].includes(key)) {
184✔
207
        let handledParam = '';
46✔
208
        clientHints[key].forEach((element, index) => {
46✔
209
          const isNotLast = index < clientHints[key].length - 1;
124✔
210
          handledParam += `"${element.brand}";v="${element.version}"${isNotLast ? ', ' : ''}`;
124✔
211
        });
212
        chParams[encoderCH[key]] = handledParam;
46✔
213
      } else if (typeof clientHints[key] === 'boolean') {
138✔
214
        chParams[encoderCH[key]] = `?${clientHints[key] ? 1 : 0}`;
46!
215
      } else {
216
        chParams[encoderCH[key]] = `"${clientHints[key]}"`;
92✔
217
      }
218
    }
219
  }
220
  return Object.keys(chParams).length ? JSON.stringify(chParams) : '';
23!
221
}
222

223
export function isCMPStringTheSame(fpData, cmpData) {
224
  const firstPartyDataCPString = `${fpData.gdprString}${fpData.gppString}${fpData.uspString}`;
8✔
225
  const cmpDataString = `${cmpData.gdprString}${cmpData.gppString}${cmpData.uspString}`;
8✔
226
  return firstPartyDataCPString === cmpDataString;
8✔
227
}
228

229
/** @type {Submodule} */
230
export const intentIqIdSubmodule = {
1✔
231
  /**
232
   * used to link submodule with config
233
   * @type {string}
234
   */
235
  name: MODULE_NAME,
236
  gvlid: GVLID,
237
  /**
238
   * decode the stored id value for passing to bid requests
239
   * @function
240
   * @param {{string}} value
241
   * @returns {{intentIqId: {string}}|undefined}
242
   */
243
  decode(value) {
244
    return value && value != '' && INVALID_ID != value ? {'intentIqId': value} : undefined;
3!
245
  },
246

247
  /**
248
   * performs action to obtain id and return a value in the callback's response argument
249
   * @function
250
   * @param {SubmoduleConfig} [config]
251
   * @returns {IdResponse|undefined}
252
   */
253
  getId(config) {
254
    const configParams = (config?.params) || {};
25!
255
    let decryptedData, callbackTimeoutID;
256
    let callbackFired = false;
25✔
257
    let runtimeEids = { eids: [] };
25✔
258

259
    let gamObjectReference = isPlainObject(configParams.gamObjectReference) ? configParams.gamObjectReference : undefined;
25✔
260
    let gamParameterName = configParams.gamParameterName ? configParams.gamParameterName : 'intent_iq_group';
25✔
261

262
    const allowedStorage = defineStorageType(config.enabledStorageTypes);
25✔
263

264
    let rrttStrtTime = 0;
25✔
265
    let partnerData = {};
25✔
266
    let shouldCallServer = false;
25✔
267
    const FIRST_PARTY_DATA_KEY = `${FIRST_PARTY_KEY}_${configParams.partner}`;
25✔
268
    const cmpData = getCmpData();
25✔
269
    const gdprDetected = cmpData.gdprString;
25✔
270
    firstPartyData = tryParse(readData(FIRST_PARTY_KEY, allowedStorage));
25✔
271
    const isGroupB = firstPartyData?.group === WITHOUT_IIQ;
25✔
272
    setGamReporting(gamObjectReference, gamParameterName, firstPartyData?.group)
25✔
273

274
    const firePartnerCallback = () => {
25✔
275
      if (configParams.callback && !callbackFired) {
30✔
276
        callbackFired = true;
1✔
277
        if (callbackTimeoutID) clearTimeout(callbackTimeoutID);
1!
278
        if (isGroupB) runtimeEids = { eids: [] };
1!
279
        configParams.callback(runtimeEids, firstPartyData?.group || NOT_YET_DEFINED);
1!
280
      }
281
    }
282

283
    callbackTimeoutID = setTimeout(() => {
25✔
284
      firePartnerCallback();
11✔
285
    }, configParams.timeoutInMillis || 500
50✔
286
    );
287

288
    if (typeof configParams.partner !== 'number') {
25✔
289
      logError('User ID - intentIqId submodule requires a valid partner to be defined');
3✔
290
      firePartnerCallback()
3✔
291
      return;
3✔
292
    }
293

294
    const currentBrowserLowerCase = detectBrowser();
22✔
295
    const browserBlackList = typeof configParams.browserBlackList === 'string' ? configParams.browserBlackList.toLowerCase() : '';
22✔
296
    let newUser = false;
22✔
297

298
    if (!firstPartyData?.pcid) {
22!
299
      const firstPartyId = generateGUID();
22✔
300
      firstPartyData = {
22✔
301
        pcid: firstPartyId,
302
        pcidDate: Date.now(),
303
        group: NOT_YET_DEFINED,
304
        cttl: 0,
305
        uspString: EMPTY,
306
        gppString: EMPTY,
307
        gdprString: EMPTY,
308
        date: Date.now()
309
      };
310
      newUser = true;
22✔
311
      storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), allowedStorage, firstPartyData);
22✔
312
    } else if (!firstPartyData.pcidDate) {
×
313
      firstPartyData.pcidDate = Date.now();
×
314
      storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), allowedStorage, firstPartyData);
×
315
    }
316

317
    if (gdprDetected && !('isOptedOut' in firstPartyData)) {
22✔
318
      firstPartyData.isOptedOut = true;
4✔
319
    }
320

321
    // Read client hints from storage
322
    let clientHints = readData(CLIENT_HINTS_KEY, allowedStorage);
22✔
323

324
    // Get client hints and save to storage
325
    if (navigator?.userAgentData?.getHighEntropyValues) {
22!
326
      navigator.userAgentData
22✔
327
        .getHighEntropyValues([
328
          'brands',
329
          'mobile',
330
          'bitness',
331
          'wow64',
332
          'architecture',
333
          'model',
334
          'platform',
335
          'platformVersion',
336
          'fullVersionList'
337
        ])
338
        .then(ch => {
339
          clientHints = handleClientHints(ch);
22✔
340
          storeData(CLIENT_HINTS_KEY, clientHints, allowedStorage, firstPartyData)
22✔
341
        });
342
    }
343

344
    const savedData = tryParse(readData(FIRST_PARTY_DATA_KEY, allowedStorage))
22✔
345
    if (savedData) {
22✔
346
      partnerData = savedData;
3✔
347

348
      if (partnerData.wsrvcll) {
3!
349
        partnerData.wsrvcll = false;
×
350
        storeData(FIRST_PARTY_DATA_KEY, JSON.stringify(partnerData), allowedStorage, firstPartyData);
×
351
      }
352
    }
353

354
    if (partnerData.data) {
22✔
355
      if (partnerData.data.length) { // encrypted data
1!
356
        decryptedData = tryParse(decryptData(partnerData.data));
1✔
357
        runtimeEids = decryptedData;
1✔
358
      }
359
    }
360

361
    if (!firstPartyData.cttl || Date.now() - firstPartyData.date > firstPartyData.cttl || !isCMPStringTheSame(firstPartyData, cmpData)) {
22!
362
      firstPartyData.uspString = cmpData.uspString;
22✔
363
      firstPartyData.gppString = cmpData.gppString;
22✔
364
      firstPartyData.gdprString = cmpData.gdprString;
22✔
365
      shouldCallServer = true;
22✔
366
      storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), allowedStorage, firstPartyData);
22✔
367
      storeData(FIRST_PARTY_DATA_KEY, JSON.stringify(partnerData), allowedStorage, firstPartyData);
22✔
368
    } else if (firstPartyData.isOptedOut) {
×
369
      partnerData.data = runtimeEids = { eids: [] };
×
370
      firePartnerCallback()
×
371
    }
372

373
    if (firstPartyData.group === WITHOUT_IIQ || (firstPartyData.group !== WITHOUT_IIQ && runtimeEids?.eids?.length)) {
22✔
374
      firePartnerCallback()
1✔
375
    }
376

377
    // Check if current browser is in blacklist
378
    if (browserBlackList?.includes(currentBrowserLowerCase)) {
22✔
379
      logError('User ID - intentIqId submodule: browser is in blacklist! Data will be not provided.');
2✔
380
      if (configParams.callback) configParams.callback('', BLACK_LIST);
2✔
381
      const url = createPixelUrl(firstPartyData, clientHints, configParams, partnerData, cmpData)
2✔
382
      sendSyncRequest(allowedStorage, url, configParams.partner, firstPartyData, newUser)
2✔
383
      return
2✔
384
    }
385

386
    if (!shouldCallServer) {
20!
387
      if (isGroupB) runtimeEids = { eids: [] };
×
388
      firePartnerCallback();
×
389
      return { id: runtimeEids.eids };
×
390
    }
391

392
    // use protocol relative urls for http or https
393
    let url = `${gdprDetected ? GDPR_ENDPOINT : VR_ENDPOINT}/profiles_engine/ProfilesEngineServlet?at=39&mi=10&dpi=${configParams.partner}&pt=17&dpn=1`;
20✔
394
    url += configParams.pcid ? '&pcid=' + encodeURIComponent(configParams.pcid) : '';
20✔
395
    url += configParams.pai ? '&pai=' + encodeURIComponent(configParams.pai) : '';
20✔
396
    url = appendFirstPartyData(url, firstPartyData, partnerData);
20✔
397
    url += (partnerData.cttl) ? '&cttl=' + encodeURIComponent(partnerData.cttl) : '';
20✔
398
    url += (partnerData.rrtt) ? '&rrtt=' + encodeURIComponent(partnerData.rrtt) : '';
20✔
399
    url = appendCMPData(url, cmpData)
20✔
400
    url += clientHints ? '&uh=' + encodeURIComponent(clientHints) : '';
20✔
401
    url += VERSION ? '&jsver=' + VERSION : '';
20!
402
    url += firstPartyData?.group ? '&testGroup=' + encodeURIComponent(firstPartyData.group) : '';
20!
403

404
    // Add vrref and fui to the URL
405
    url = appendVrrefAndFui(url, configParams.domainName);
20✔
406

407
    const storeFirstPartyData = () => {
20✔
408
      partnerData.eidl = runtimeEids?.eids?.length || -1
13✔
409
      storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), allowedStorage, firstPartyData);
13✔
410
      storeData(FIRST_PARTY_DATA_KEY, JSON.stringify(partnerData), allowedStorage, firstPartyData);
13✔
411
    }
412

413
    const resp = function (callback) {
20✔
414
      const callbacks = {
18✔
415
        success: response => {
416
          let respJson = tryParse(response);
15✔
417
          // If response is a valid json and should save is true
418
          if (respJson) {
15✔
419
            partnerData.date = Date.now();
14✔
420
            firstPartyData.date = Date.now();
14✔
421
            const defineEmptyDataAndFireCallback = () => {
14✔
422
              respJson.data = partnerData.data = runtimeEids = { eids: [] };
1✔
423
              storeFirstPartyData()
1✔
424
              firePartnerCallback()
1✔
425
              callback(runtimeEids)
1✔
426
            }
427
            if (callbackTimeoutID) clearTimeout(callbackTimeoutID)
14!
428
            if ('cttl' in respJson) {
14!
429
              firstPartyData.cttl = respJson.cttl;
×
430
            } else firstPartyData.cttl = 86400000;
14✔
431

432
            if ('tc' in respJson) {
14✔
433
              partnerData.terminationCause = respJson.tc;
2✔
434
              if (respJson.tc == 41) {
2!
435
                firstPartyData.group = WITHOUT_IIQ;
×
436
                storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), allowedStorage, firstPartyData);
×
437
                defineEmptyDataAndFireCallback();
×
438
                if (gamObjectReference) setGamReporting(gamObjectReference, gamParameterName, firstPartyData.group);
×
439
                return
×
440
              } else {
441
                firstPartyData.group = WITH_IIQ;
2✔
442
                if (gamObjectReference) setGamReporting(gamObjectReference, gamParameterName, firstPartyData.group);
2✔
443
              }
444
            }
445
            if ('isOptedOut' in respJson) {
14✔
446
              if (respJson.isOptedOut !== firstPartyData.isOptedOut) {
3✔
447
                firstPartyData.isOptedOut = respJson.isOptedOut;
2✔
448
              }
449
              if (respJson.isOptedOut === true) {
3✔
450
                respJson.data = partnerData.data = runtimeEids = { eids: [] };
1✔
451

452
                const keysToRemove = [
1✔
453
                  FIRST_PARTY_DATA_KEY,
454
                  CLIENT_HINTS_KEY
455
                ];
456

457
                keysToRemove.forEach(key => removeDataByKey(key, allowedStorage));
2✔
458

459
                storeData(FIRST_PARTY_KEY, JSON.stringify(firstPartyData), allowedStorage, firstPartyData);
1✔
460
                firePartnerCallback();
1✔
461
                callback(runtimeEids);
1✔
462
                return
1✔
463
              }
464
            }
465
            if ('pid' in respJson) {
13✔
466
              firstPartyData.pid = respJson.pid;
4✔
467
            }
468
            if ('ls' in respJson) {
13✔
469
              if (respJson.ls === false) {
5✔
470
                defineEmptyDataAndFireCallback()
1✔
471
                return
1✔
472
              }
473
              // If data is empty, means we should save as INVALID_ID
474
              if (respJson.data == '') {
4!
475
                respJson.data = INVALID_ID;
×
476
              } else {
477
                // If data is a single string, assume it is an id with source intentiq.com
478
                if (respJson.data && typeof respJson.data === 'string') {
4!
479
                  respJson.data = {eids: [respJson.data]}
4✔
480
                }
481
              }
482
              partnerData.data = respJson.data;
4✔
483
            }
484

485
            if ('ct' in respJson) {
12✔
486
              partnerData.clientType = respJson.ct;
1✔
487
            }
488

489
            if ('sid' in respJson) {
12!
490
              partnerData.siteId = respJson.sid;
×
491
            }
492

493
            if (rrttStrtTime && rrttStrtTime > 0) {
12!
494
              partnerData.rrtt = Date.now() - rrttStrtTime;
12✔
495
            }
496

497
            if (respJson.data?.eids) {
12✔
498
              runtimeEids = respJson.data
4✔
499
              callback(respJson.data.eids);
4✔
500
              firePartnerCallback()
4✔
501
              const encryptedData = encryptData(JSON.stringify(respJson.data))
4✔
502
              partnerData.data = encryptedData;
4✔
503
            } else {
504
              callback(runtimeEids);
8✔
505
              firePartnerCallback()
8✔
506
            }
507
            storeFirstPartyData();
12✔
508
          } else {
509
            callback(runtimeEids);
1✔
510
            firePartnerCallback()
1✔
511
          }
512
        },
513
        error: error => {
514
          logError(MODULE_NAME + ': ID fetch encountered an error', error);
1✔
515
          callback(runtimeEids);
1✔
516
        }
517
      };
518
      rrttStrtTime = Date.now();
18✔
519

520
      partnerData.wsrvcll = true;
18✔
521
      storeData(FIRST_PARTY_DATA_KEY, JSON.stringify(partnerData), allowedStorage, firstPartyData);
18✔
522
      ajax(url, callbacks, undefined, {method: 'GET', withCredentials: true});
18✔
523
    };
524
    const respObj = {callback: resp};
20✔
525

526
    if (runtimeEids?.eids?.length) respObj.id = runtimeEids.eids;
20✔
527
    return respObj
20✔
528
  },
529
  eids: {
530
    'intentIqId': {
531
      source: 'intentiq.com',
532
      atype: 1,
533
      getSource: function (data) {
534
        return data.source;
×
535
      },
536
      getValue: function (data) {
537
        if (data?.uids?.length) {
×
538
          return data.uids[0].id
×
539
        }
540
        return null
×
541
      },
542
      getUidExt: function (data) {
543
        if (data?.uids?.length) {
×
544
          return data.uids[0].ext;
×
545
        }
546
        return null
×
547
      }
548
    },
549
  }
550
};
551

552
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