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

prebid / Prebid.js / 16457245554

22 Jul 2025 10:52PM UTC coverage: 96.262% (-0.003%) from 96.265%
16457245554

push

github

ba9a62
web-flow
Linting: no-return-assign (#13608)

* Update eslint.config.js

* merge remote: remove no return assign lint rule (#13609)

* Yieldlab Bid Adapter: ensure netRevenue default

* Core: enable no-return-assign rule

* Update yieldlabBidAdapter.js

* lint fix spacing

* Update eslint.config.js

---------

Co-authored-by: Chris Huie <phoenixtechnerd@gmail.com>

39335 of 48340 branches covered (81.37%)

104 of 111 new or added lines in 44 files covered. (93.69%)

19 existing lines in 15 files now uncovered.

194344 of 201890 relevant lines covered (96.26%)

83.16 hits per line

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

89.52
/modules/pubmaticAnalyticsAdapter.js
1
import {_each, isArray, isStr, logError, logWarn, pick, generateUUID} from '../src/utils.js';
1✔
2
import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js';
3
import adapterManager from '../src/adapterManager.js';
4
import { BID_STATUS, EVENTS, STATUS, REJECTION_REASON } from '../src/constants.js';
5
import {ajax} from '../src/ajax.js';
6
import {config} from '../src/config.js';
7
import {getGlobal} from '../src/prebidGlobal.js';
8
import {getGptSlotInfoForAdUnitCode} from '../libraries/gptUtils/gptUtils.js';
9

10
const FLOOR_VALUES = {
1✔
11
  NO_DATA: 'noData',
12
  AD_UNIT: 'adUnit',
13
  SET_CONFIG: 'setConfig',
14
  FETCH: 'fetch',
15
  SUCCESS: 'success',
16
  ERROR: 'error',
17
  TIMEOUT: 'timeout'
18
};
19

20
/// /////////// CONSTANTS ///////////////
21
const ADAPTER_CODE = 'pubmatic';
1✔
22
const VENDOR_OPENWRAP = 'openwrap';
1✔
23
const DISPLAY_MANAGER = 'Prebid.js';
1✔
24
const SEND_TIMEOUT = 2000;
1✔
25
const END_POINT_HOST = 'https://t.pubmatic.com/';
1✔
26
const END_POINT_BID_LOGGER = END_POINT_HOST + 'wl?';
1✔
27
const END_POINT_WIN_BID_LOGGER = END_POINT_HOST + 'wt?';
1✔
28
const LOG_PRE_FIX = 'PubMatic-Analytics: ';
1✔
29
const cache = {
1✔
30
  auctions: {}
31
};
32
const SUCCESS = 'success';
1✔
33
const NO_BID = 'no-bid';
1✔
34
const ERROR = 'error';
1✔
35
const REQUEST_ERROR = 'request-error';
1✔
36
const TIMEOUT_ERROR = 'timeout-error';
1✔
37
const EMPTY_STRING = '';
1✔
38
const OPEN_AUCTION_DEAL_ID = '-1';
1✔
39
const MEDIA_TYPE_BANNER = 'banner';
1✔
40
const CURRENCY_USD = 'USD';
1✔
41
const BID_PRECISION = 2;
1✔
42
// todo: input profileId and profileVersionId ; defaults to zero or one
43
const DEFAULT_PUBLISHER_ID = 0;
1✔
44
const DEFAULT_PROFILE_ID = 0;
1✔
45
const DEFAULT_PROFILE_VERSION_ID = 0;
1✔
46
const enc = window.encodeURIComponent;
1✔
47
const MEDIATYPE = {
1✔
48
  BANNER: 0,
49
  VIDEO: 1,
50
  NATIVE: 2
51
}
52

53
// TODO : Remove - Once BM calculation moves to Server Side
54
const BROWSER_MAP = [
1✔
55
  { value: /(firefox)\/([\w\.]+)/i, key: 12 }, // Firefox
56
  { value: /\b(?:crios)\/([\w\.]+)/i, key: 1 }, // Chrome for iOS
57
  { value: /edg(?:e|ios|a)?\/([\w\.]+)/i, key: 2 }, // Edge
58
  { value: /(opera|opr)(?:.+version\/|[\/ ]+)([\w\.]+)/i, key: 3 }, // Opera
59
  { value: /(?:ms|\()(ie) ([\w\.]+)|(?:trident\/[\w\.]+)/i, key: 4 }, // Internet Explorer
60
  { value: /fxios\/([-\w\.]+)/i, key: 5 }, // Firefox for iOS
61
  { value: /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i, key: 6 }, // Facebook In-App Browser
62
  { value: / wv\).+(chrome)\/([\w\.]+)/i, key: 7 }, // Chrome WebView
63
  { value: /droid.+ version\/([\w\.]+)\b.+(?:mobile safari|safari)/i, key: 8 }, // Android Browser
64
  { value: /(chrome|chromium|crios)\/v?([\w\.]+)/i, key: 9 }, // Chrome
65
  { value: /version\/([\w\.\,]+) .*mobile\/\w+ (safari)/i, key: 10 }, // Safari Mobile
66
  { value: /version\/([\w(\.|\,)]+) .*(mobile ?safari|safari)/i, key: 11 }, // Safari
67
];
68

69
/// /////////// VARIABLES //////////////
70
let publisherId = DEFAULT_PUBLISHER_ID; // int: mandatory
1✔
71
let profileId = DEFAULT_PROFILE_ID; // int: optional
1✔
72
let profileVersionId = DEFAULT_PROFILE_VERSION_ID; // int: optional
1✔
73
let s2sBidders = [];
1✔
74

75
/// /////////// HELPER FUNCTIONS //////////////
76

77
function sizeToDimensions(size) {
78
  return {
77✔
79
    width: size.w || size[0],
154✔
80
    height: size.h || size[1]
154✔
81
  };
82
}
83

84
function validMediaType(type) {
85
  return ({'banner': 1, 'native': 1, 'video': 1}).hasOwnProperty(type);
39✔
86
}
87

88
function formatSource(src) {
89
  if (typeof src === 'undefined') {
36!
90
    src = 'client';
×
91
  } else if (src === 's2s') {
36✔
92
    src = 'server';
34✔
93
  }
94
  return src.toLowerCase();
36✔
95
}
96

97
function setMediaTypes(types, bid) {
98
  if (bid.mediaType && validMediaType(bid.mediaType)) {
39✔
99
    return [bid.mediaType];
20✔
100
  }
101
  if (Array.isArray(types)) {
19!
102
    return types.filter(validMediaType);
×
103
  }
104
  if (typeof types === 'object') {
19✔
105
    if (!bid.sizes) {
19!
106
      bid.dimensions = [];
×
NEW
107
      _each(types, (type) => {
×
108
        bid.dimensions = bid.dimensions.concat(
×
109
          type.sizes.map(sizeToDimensions)
110
        );
111
      });
112
    }
113
    return Object.keys(types).filter(validMediaType);
19✔
114
  }
115
  return [MEDIA_TYPE_BANNER];
×
116
}
117

118
function copyRequiredBidDetails(bid) {
119
  return pick(bid, [
39✔
120
    'bidder',
121
    'bidderCode',
122
    'adapterCode',
123
    'bidId',
124
    'status', () => NO_BID, // default a bid to NO_BID until response is received or bid is timed out
39✔
125
    'finalSource as source',
126
    'params',
127
    'floorData',
128
    'adUnit', () => pick(bid, [
39✔
129
      'adUnitCode',
130
      'transactionId',
131
      'sizes as dimensions', sizes => sizes && sizes.map(sizeToDimensions),
39✔
132
      'mediaTypes', (types) => setMediaTypes(types, bid)
39✔
133
    ])
134
  ]);
135
}
136

137
function setBidStatus(bid, status) {
138
  switch (status) {
36!
139
    case STATUS.GOOD:
140
      bid.status = SUCCESS;
36✔
141
      delete bid.error; // it's possible for this to be set by a previous timeout
36✔
142
      break;
36✔
143
    default:
144
      bid.status = ERROR;
×
145
      bid.error = {
×
146
        code: REQUEST_ERROR
147
      };
148
  }
149
}
150

151
function parseBidResponse(bid) {
152
  return pick(bid, [
36✔
153
    'bidPriceUSD', () => {
154
      // todo: check whether currency cases are handled here
155
      if (typeof bid.currency === 'string' && bid.currency.toUpperCase() === CURRENCY_USD) {
36✔
156
        return window.parseFloat(Number(bid.cpm).toFixed(BID_PRECISION));
33✔
157
      }
158
      // use currency conversion function if present
159
      if (typeof bid.getCpmInNewCurrency === 'function') {
3!
160
        return window.parseFloat(Number(bid.getCpmInNewCurrency(CURRENCY_USD)).toFixed(BID_PRECISION));
×
161
      }
162
      logWarn(LOG_PRE_FIX + 'Could not determine the Net cpm in USD for the bid thus using bid.cpm', bid);
3✔
163
      return bid.cpm
3✔
164
    },
165
    'bidGrossCpmUSD', () => {
166
      if (typeof bid.originalCurrency === 'string' && bid.originalCurrency.toUpperCase() === CURRENCY_USD) {
36✔
167
        return window.parseFloat(Number(bid.originalCpm).toFixed(BID_PRECISION));
33✔
168
      }
169
      // use currency conversion function if present
170
      if (typeof getGlobal().convertCurrency === 'function') {
3✔
171
        return window.parseFloat(Number(getGlobal().convertCurrency(bid.originalCpm, bid.originalCurrency, CURRENCY_USD)).toFixed(BID_PRECISION));
3✔
172
      }
173
      logWarn(LOG_PRE_FIX + 'Could not determine the Gross cpm in USD for the bid, thus using bid.originalCpm', bid);
×
174
      return bid.originalCpm
×
175
    },
176
    'dealId',
177
    'currency',
178
    'cpm', () => window.parseFloat(Number(bid.cpm).toFixed(BID_PRECISION)),
36✔
179
    'originalCpm', () => window.parseFloat(Number(bid.originalCpm).toFixed(BID_PRECISION)),
36✔
180
    'originalCurrency',
181
    'adserverTargeting',
182
    'dealChannel',
183
    'meta',
184
    'status',
185
    'error',
186
    'bidId',
187
    'mediaType',
188
    'params',
189
    'floorData',
190
    'mi',
191
    'regexPattern', () => bid.regexPattern || undefined,
36✔
192
    'partnerImpId', // partner impression ID
193
    'dimensions', () => pick(bid, [
36✔
194
      'width',
195
      'height'
196
    ])
197
  ]);
198
}
199

200
function getDomainFromUrl(url) {
201
  const a = window.document.createElement('a');
51✔
202
  a.href = url;
51✔
203
  return a.hostname;
51✔
204
}
205

206
function getDevicePlatform() {
207
  var deviceType = 3;
51✔
208
  try {
51✔
209
    var ua = navigator.userAgent;
51✔
210
    if (ua && isStr(ua) && ua.trim() != '') {
51✔
211
      ua = ua.toLowerCase().trim();
48✔
212
      var isMobileRegExp = new RegExp('(mobi|tablet|ios).*');
48✔
213
      if (ua.match(isMobileRegExp)) {
48✔
214
        deviceType = 2;
3✔
215
      } else {
216
        deviceType = 1;
45✔
217
      }
218
    }
219
  } catch (ex) {}
220
  return deviceType;
51✔
221
}
222

223
// TODO : Remove - Once BM calculation moves to Server Side
224
function getBrowserType() {
225
  const userAgent = navigator?.userAgent;
20✔
226
  let browserIndex = userAgent == null ? -1 : 0;
20✔
227

228
  if (userAgent) {
20✔
229
    browserIndex = BROWSER_MAP.find(({ value }) => value.test(userAgent))?.key || 0;
227!
230
  }
231
  return browserIndex;
20✔
232
}
233

234
function getValueForKgpv(bid, adUnitId) {
235
  if (bid.params && bid.params.regexPattern) {
68✔
236
    return bid.params.regexPattern;
4✔
237
  } else if (bid.bidResponse && bid.bidResponse.regexPattern) {
64✔
238
    return bid.bidResponse.regexPattern;
4✔
239
  } else if (bid.params && bid.params.kgpv) {
60✔
240
    return bid.params.kgpv;
24✔
241
  } else {
242
    return adUnitId;
36✔
243
  }
244
}
245

246
function getAdapterNameForAlias(aliasName) {
247
  return adapterManager.aliasRegistry[aliasName] || aliasName;
71✔
248
}
249

250
function getAdDomain(bidResponse) {
251
  if (bidResponse.meta && bidResponse.meta.advertiserDomains) {
64✔
252
    const adomain = bidResponse.meta.advertiserDomains[0]
30✔
253
    if (adomain) {
30✔
254
      try {
30✔
255
        const hostname = (new URL(adomain));
30✔
256
        return hostname.hostname.replace('www.', '');
2✔
257
      } catch (e) {
258
        logWarn(LOG_PRE_FIX + 'Adomain URL (Not a proper URL):', adomain);
28✔
259
        return adomain.replace('www.', '');
28✔
260
      }
261
    }
262
  }
263
}
264

265
function isObject(object) {
266
  return typeof object === 'object' && object !== null;
133✔
267
};
268

269
function isEmptyObject(object) {
270
  return isObject(object) && Object.keys(object).length === 0;
133✔
271
};
272

273
/**
274
 * Prepare meta object to pass in logger call
275
 * @param {*} meta
276
 */
277
export function getMetadata(meta) {
278
  if (!meta || isEmptyObject(meta)) return;
68✔
279
  const metaObj = {};
66✔
280
  if (meta.networkId) metaObj.nwid = meta.networkId;
66✔
281
  if (meta.advertiserId) metaObj.adid = meta.advertiserId;
66✔
282
  if (meta.networkName) metaObj.nwnm = meta.networkName;
66✔
283
  if (meta.primaryCatId) metaObj.pcid = meta.primaryCatId;
66✔
284
  if (meta.advertiserName) metaObj.adnm = meta.advertiserName;
66✔
285
  if (meta.agencyId) metaObj.agid = meta.agencyId;
66✔
286
  if (meta.agencyName) metaObj.agnm = meta.agencyName;
66✔
287
  if (meta.brandId) metaObj.brid = meta.brandId;
66✔
288
  if (meta.brandName) metaObj.brnm = meta.brandName;
66✔
289
  if (meta.dchain) metaObj.dc = meta.dchain;
66✔
290
  if (meta.demandSource) metaObj.ds = meta.demandSource;
66✔
291
  if (meta.secondaryCatIds) metaObj.scids = meta.secondaryCatIds;
66✔
292

293
  if (isEmptyObject(metaObj)) return;
66✔
294
  return metaObj;
65✔
295
}
296

297
function isS2SBidder(bidder) {
298
  return (s2sBidders.indexOf(bidder) > -1) ? 1 : 0
71✔
299
}
300

301
function isOWPubmaticBid(adapterName) {
302
  const s2sConf = config.getConfig('s2sConfig');
71✔
303
  const s2sConfArray = s2sConf ? (isArray(s2sConf) ? s2sConf : [s2sConf]) : [];
71!
304
  return s2sConfArray.some(conf => {
71✔
305
    if (adapterName === ADAPTER_CODE && conf.defaultVendor === VENDOR_OPENWRAP &&
71✔
306
      conf.bidders.indexOf(ADAPTER_CODE) > -1) {
307
      return true;
3✔
308
    }
309
  })
310
}
311

312
function getFloorsCommonField (floorData) {
313
  if (!floorData) return;
51✔
314
  const { location, fetchStatus, floorProvider, modelVersion } = floorData;
49✔
315
  return {
49✔
316
    ffs: {
317
      [FLOOR_VALUES.SUCCESS]: 1,
318
      [FLOOR_VALUES.ERROR]: 2,
319
      [FLOOR_VALUES.TIMEOUT]: 4,
320
      undefined: 0
321
    }[fetchStatus],
322
    fsrc: {
323
      [FLOOR_VALUES.FETCH]: 2,
324
      [FLOOR_VALUES.NO_DATA]: 0,
325
      [FLOOR_VALUES.AD_UNIT]: 1,
326
      [FLOOR_VALUES.SET_CONFIG]: 1
327
    }[location],
328
    fp: floorProvider,
329
    mv: modelVersion
330
  }
331
}
332

333
function getFloorType(floorResponseData) {
334
  return floorResponseData ? (floorResponseData.enforcements.enforceJS == false ? 0 : 1) : undefined;
49!
335
}
336

337
function gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestBid, e) {
338
  highestBid = (highestBid && highestBid.length > 0) ? highestBid[0] : null;
39✔
339
  return Object.keys(adUnit.bids).reduce(function(partnerBids, bidId) {
39✔
340
    adUnit.bids[bidId].forEach(function(bid) {
39✔
341
      const adapterName = getAdapterNameForAlias(bid.adapterCode || bid.bidder);
39!
342
      if (isOWPubmaticBid(adapterName) && isS2SBidder(bid.bidder)) {
39✔
343
        return;
2✔
344
      }
345
      const pg = window.parseFloat(Number(bid.bidResponse?.adserverTargeting?.hb_pb || bid.bidResponse?.adserverTargeting?.pwtpb).toFixed(BID_PRECISION));
37✔
346

347
      const prebidBidsReceived = e?.bidsReceived;
37✔
348
      if (isArray(prebidBidsReceived) && prebidBidsReceived.length > 0) {
37!
349
        prebidBidsReceived.forEach(function(iBid) {
×
350
          if (iBid.adId === bid.adId) {
×
351
            bid.bidderCode = iBid.bidderCode;
×
352
          }
353
        });
354
      }
355

356
      partnerBids.push({
37✔
357
        'pn': adapterName,
358
        'bc': bid.bidderCode || bid.bidder,
37!
359
        'bidid': bid.bidId || bidId,
37!
360
        'origbidid': bid?.bidResponse?.partnerImpId || bid?.bidResponse?.prebidBidId || bid.bidId || bidId,
47!
361
        'db': bid.bidResponse ? 0 : 1,
37✔
362
        'kgpv': getValueForKgpv(bid, adUnitId),
363
        'kgpsv': bid.params && bid.params.kgpv ? bid.params.kgpv : adUnitId,
111✔
364
        'psz': bid.bidResponse ? (bid.bidResponse.dimensions.width + 'x' + bid.bidResponse.dimensions.height) : '0x0',
37✔
365
        'eg': bid.bidResponse ? bid.bidResponse.bidGrossCpmUSD : 0,
37✔
366
        'en': bid.bidResponse ? bid.bidResponse.bidPriceUSD : 0,
37✔
367
        'di': bid.bidResponse ? (bid.bidResponse.dealId || OPEN_AUCTION_DEAL_ID) : OPEN_AUCTION_DEAL_ID,
87✔
368
        'dc': bid.bidResponse ? (bid.bidResponse.dealChannel || EMPTY_STRING) : EMPTY_STRING,
87✔
369
        'l1': bid.bidResponse ? bid.partnerTimeToRespond : 0,
37✔
370
        'ol1': bid.bidResponse ? bid.clientLatencyTimeMs : 0,
37✔
371
        'l2': 0,
372
        'adv': bid.bidResponse ? getAdDomain(bid.bidResponse) || undefined : undefined,
87✔
373
        'ss': isS2SBidder(bid.bidder),
374
        't': (bid.status == ERROR && bid.error.code == TIMEOUT_ERROR) ? 1 : 0,
76✔
375
        'wb': (highestBid && highestBid.adId === bid.adId ? 1 : 0),
94✔
376
        'mi': bid.bidResponse ? (bid.bidResponse.mi || undefined) : undefined,
87✔
377
        'af': bid.bidResponse ? (bid.bidResponse.mediaType || undefined) : undefined,
70!
378
        'ocpm': bid.bidResponse ? (bid.bidResponse.originalCpm || 0) : 0,
70!
379
        'ocry': bid.bidResponse ? (bid.bidResponse.originalCurrency || CURRENCY_USD) : CURRENCY_USD,
70!
380
        'frv': bid.bidResponse ? bid.bidResponse.floorData?.floorRuleValue : undefined,
37✔
381
        'fv': bid.bidResponse ? bid.bidResponse.floorData?.floorValue : undefined,
37✔
382
        'md': bid.bidResponse ? getMetadata(bid.bidResponse.meta) : undefined,
37✔
383
        'pb': pg || undefined
41✔
384
      });
385
    });
386
    return partnerBids;
39✔
387
  }, [])
388
}
389

390
function getSizesForAdUnit(adUnit) {
391
  var bid = Object.values(adUnit.bids).filter((bid) => !!bid.bidResponse && bid.bidResponse.mediaType === 'native')[0];
39!
392
  if (!!bid || (bid === undefined && adUnit.dimensions.length === 0)) {
39!
393
    return ['1x1'];
×
394
  } else {
395
    return adUnit.dimensions.map(function (e) {
39✔
396
      return e[0] + 'x' + e[1];
77✔
397
    })
398
  }
399
}
400

401
function getAdUnitAdFormats(adUnit) {
402
  var af = adUnit ? Object.keys(adUnit.mediaTypes || {}).map(format => MEDIATYPE[format.toUpperCase()]) : [];
39!
403
  return af;
39✔
404
}
405

406
function getAdUnit(adUnits, adUnitId) {
407
  return adUnits.filter(adUnit => (adUnit.divID && adUnit.divID == adUnitId) || (adUnit.code == adUnitId))[0];
70!
408
}
409

410
function getTgId() {
411
  var testGroupId = parseInt(config.getConfig('testGroupId') || 0);
51✔
412
  if (testGroupId <= 15 && testGroupId >= 0) {
51✔
413
    return testGroupId;
46✔
414
  }
415
  return 0;
5✔
416
}
417

418
function getFloorFetchStatus(floorData) {
419
  if (!floorData?.floorRequestData) {
20✔
420
    return false;
1✔
421
  }
422
  const { location, fetchStatus } = floorData?.floorRequestData;
19✔
423
  const isDataValid = location !== FLOOR_VALUES.NO_DATA;
19✔
424
  const isFetchSuccessful = location === FLOOR_VALUES.FETCH && fetchStatus === FLOOR_VALUES.SUCCESS;
19✔
425
  const isAdUnitOrSetConfig = location === FLOOR_VALUES.AD_UNIT || location === FLOOR_VALUES.SET_CONFIG;
19✔
426
  return isDataValid && (isAdUnitOrSetConfig || isFetchSuccessful);
19✔
427
}
428

429
function getListOfIdentityPartners() {
430
  const namespace = getGlobal();
20✔
431
  const publisherProvidedEids = namespace.getConfig("ortb2.user.eids") || [];
20✔
432
  const availableUserIds = namespace.adUnits[0]?.bids[0]?.userId || {};
20✔
433
  const identityModules = namespace.getConfig('userSync')?.userIds || [];
20✔
434
  const identityModuleNameMap = identityModules.reduce((mapping, module) => {
20✔
435
    if (module.storage?.name) {
1✔
436
      mapping[module.storage.name] = module.name;
1✔
437
    }
438
    return mapping;
1✔
439
  }, {});
440

441
  const userIdPartners = Object.keys(availableUserIds).map(storageName =>
20✔
442
    identityModuleNameMap[storageName] || storageName
1!
443
  );
444

445
  const publisherProvidedEidList = publisherProvidedEids.map(eid =>
20✔
446
    identityModuleNameMap[eid.source] || eid.source
×
447
  );
448

449
  const identityPartners = Array.from(new Set([...userIdPartners, ...publisherProvidedEidList]));
20✔
450
  return identityPartners.length > 0 ? identityPartners : undefined;
20✔
451
}
452

453
function executeBidsLoggerCall(e, highestCpmBids) {
454
  const auctionId = e.auctionId;
20✔
455
  const referrer = config.getConfig('pageUrl') || cache.auctions[auctionId]?.referer || '';
20!
456
  const auctionCache = cache.auctions[auctionId];
20✔
457
  const wiid = auctionCache?.wiid || auctionId;
20✔
458
  const floorData = auctionCache?.floorData;
20✔
459
  const floorFetchStatus = getFloorFetchStatus(floorData);
20✔
460
  const outputObj = { s: [] };
20✔
461
  let pixelURL = END_POINT_BID_LOGGER;
20✔
462

463
  const country = e.bidderRequests?.length > 0
20!
464
    ? e.bidderRequests.find(bidder => bidder?.bidderCode === ADAPTER_CODE)?.ortb2?.user?.ext?.ctr || ''
×
465
    : '';
466

467
  if (!auctionCache || auctionCache.sent) {
20!
468
    return;
×
469
  }
470

471
  pixelURL += 'pubid=' + publisherId;
20✔
472
  outputObj['pubid'] = '' + publisherId;
20✔
473
  outputObj['iid'] = '' + wiid;
20✔
474
  outputObj['to'] = '' + auctionCache.timeout;
20✔
475
  outputObj['purl'] = referrer;
20✔
476
  outputObj['orig'] = getDomainFromUrl(referrer);
20✔
477
  outputObj['tst'] = Math.round((new window.Date()).getTime() / 1000);
20✔
478
  outputObj['pid'] = '' + profileId;
20✔
479
  outputObj['pdvid'] = '' + profileVersionId;
20✔
480
  outputObj['dvc'] = {'plt': getDevicePlatform()};
20✔
481
  outputObj['tgid'] = getTgId();
20✔
482
  outputObj['dm'] = DISPLAY_MANAGER;
20✔
483
  outputObj['dmv'] = '$prebid.version$' || '-1';
20!
484
  outputObj['bm'] = getBrowserType();
20✔
485
  outputObj['ctr'] = country || '';
20✔
486
  outputObj['lip'] = getListOfIdentityPartners();
20✔
487

488
  if (floorData) {
20✔
489
    const floorRootValues = getFloorsCommonField(floorData?.floorRequestData);
20✔
490
    if (floorRootValues) {
20✔
491
      const { ffs, fsrc, fp, mv } = floorRootValues;
19✔
492
      if (floorData?.floorRequestData) {
19✔
493
        outputObj['ffs'] = ffs;
19✔
494
        outputObj['fsrc'] = fsrc;
19✔
495
        outputObj['fp'] = fp;
19✔
496
      }
497
      if (floorFetchStatus) {
19✔
498
        outputObj['fmv'] = mv || undefined;
18!
499
      }
500
    }
501
    if (floorFetchStatus) {
20✔
502
      outputObj['ft'] = getFloorType(floorData?.floorResponseData);
18✔
503
    }
504
  }
505

506
  outputObj.s = Object.keys(auctionCache.adUnitCodes).reduce(function(slotsArray, adUnitId) {
20✔
507
    const adUnit = auctionCache.adUnitCodes[adUnitId];
39✔
508
    const origAdUnit = getAdUnit(auctionCache.origAdUnits, adUnitId) || {};
39✔
509
    // getGptSlotInfoForAdUnitCode returns gptslot corresponding to adunit provided as input.
510
    const slotObject = {
39✔
511
      'sn': adUnitId,
512
      'au': origAdUnit.owAdUnitId || getGptSlotInfoForAdUnitCode(adUnitId)?.gptSlot || adUnitId,
97✔
513
      'mt': getAdUnitAdFormats(origAdUnit),
514
      'sz': getSizesForAdUnit(adUnit, adUnitId),
515
      'ps': gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestCpmBids.filter(bid => bid.adUnitCode === adUnitId), e),
43✔
516
      'fskp': floorData && floorFetchStatus ? (floorData.floorRequestData ? (floorData.floorRequestData.skipped == false ? 0 : 1) : undefined) : undefined,
189!
517
      'sid': generateUUID()
518
    };
519
    slotsArray.push(slotObject);
39✔
520
    return slotsArray;
39✔
521
  }, []);
522

523
  auctionCache.sent = true;
20✔
524

525
  ajax(
20✔
526
    pixelURL,
527
    null,
528
    'json=' + enc(JSON.stringify(outputObj)),
529
    {
530
      contentType: 'application/x-www-form-urlencoded',
531
      withCredentials: true,
532
      method: 'POST'
533
    }
534
  );
535
}
536

537
function executeBidWonLoggerCall(auctionId, adUnitId) {
538
  const winningBidId = cache.auctions[auctionId]?.adUnitCodes[adUnitId]?.bidWon;
32✔
539
  const winningBids = cache.auctions[auctionId]?.adUnitCodes[adUnitId]?.bids[winningBidId];
32✔
540
  if (!winningBids) {
32!
541
    logWarn(LOG_PRE_FIX + 'Could not find winningBids for : ', auctionId);
×
542
    return;
×
543
  }
544

545
  let winningBid = winningBids[0];
32✔
546
  if (winningBids.length > 1) {
32!
547
    winningBid = winningBids.filter(bid => bid.adId === cache.auctions[auctionId]?.adUnitCodes[adUnitId]?.bidWonAdId)[0];
×
548
  }
549

550
  const adapterName = getAdapterNameForAlias(winningBid.adapterCode || winningBid.bidder);
32!
551
  if (isOWPubmaticBid(adapterName) && isS2SBidder(winningBid.bidder)) {
32✔
552
    return;
1✔
553
  }
554
  const origAdUnit = getAdUnit(cache.auctions[auctionId]?.origAdUnits, adUnitId) || {};
31✔
555
  const owAdUnitId = origAdUnit.owAdUnitId || getGptSlotInfoForAdUnitCode(adUnitId)?.gptSlot || adUnitId;
31✔
556
  const auctionCache = cache.auctions[auctionId];
31✔
557
  const floorData = auctionCache?.floorData;
31✔
558
  const wiid = cache.auctions[auctionId]?.wiid || auctionId;
31✔
559
  const referrer = config.getConfig('pageUrl') || cache.auctions[auctionId]?.referer || '';
31!
560
  const adv = winningBid.bidResponse ? getAdDomain(winningBid.bidResponse) || undefined : undefined;
31!
561
  const fskp = floorData ? (floorData.floorRequestData ? (floorData.floorRequestData.skipped == false ? 0 : 1) : undefined) : undefined;
31!
562
  const pg = window.parseFloat(Number(winningBid?.bidResponse?.adserverTargeting?.hb_pb || winningBid?.bidResponse?.adserverTargeting?.pwtpb)) || undefined;
31!
563
  let pixelURL = END_POINT_WIN_BID_LOGGER;
31✔
564

565
  pixelURL += 'pubid=' + publisherId;
31✔
566
  pixelURL += '&purl=' + enc(config.getConfig('pageUrl') || cache.auctions[auctionId]?.referer || '');
31!
567
  pixelURL += '&tst=' + Math.round((new window.Date()).getTime() / 1000);
31✔
568
  pixelURL += '&iid=' + enc(wiid);
31✔
569
  pixelURL += '&bidid=' + enc(winningBidId);
31✔
570
  pixelURL += '&pid=' + enc(profileId);
31✔
571
  pixelURL += '&pdvid=' + enc(profileVersionId);
31✔
572
  pixelURL += '&slot=' + enc(adUnitId);
31✔
573
  pixelURL += '&au=' + enc(owAdUnitId);
31✔
574
  pixelURL += '&pn=' + enc(adapterName);
31✔
575
  pixelURL += '&bc=' + enc(winningBid.bidderCode || winningBid.bidder);
31!
576
  pixelURL += '&en=' + enc(winningBid.bidResponse?.bidPriceUSD);
31✔
577
  pixelURL += '&eg=' + enc(winningBid.bidResponse?.bidGrossCpmUSD);
31✔
578
  pixelURL += '&kgpv=' + enc(getValueForKgpv(winningBid, adUnitId));
31✔
579
  pixelURL += '&dm=' + enc(DISPLAY_MANAGER);
31✔
580
  pixelURL += '&dmv=' + enc('$prebid.version$' || '-1');
31!
581
  pixelURL += '&origbidid=' + enc(winningBid?.bidResponse?.partnerImpId || winningBid?.bidResponse?.prebidBidId || winningBid.bidId);
31✔
582
  pixelURL += '&di=' + enc(winningBid?.bidResponse?.dealId || OPEN_AUCTION_DEAL_ID);
31✔
583
  const ds = winningBid.bidResponse?.meta ? getMetadata(winningBid.bidResponse.meta)?.ds : undefined;
31!
584
  if (ds) {
31✔
585
    pixelURL += '&ds=' + enc(ds);
31✔
586
  }
587
  pg && (pixelURL += '&pb=' + enc(pg));
31✔
588

589
  pixelURL += '&plt=' + enc(getDevicePlatform());
31✔
590
  pixelURL += '&psz=' + enc((winningBid?.bidResponse?.dimensions?.width || '0') + 'x' +
31!
591
    (winningBid?.bidResponse?.dimensions?.height || '0'));
31!
592
  pixelURL += '&tgid=' + enc(getTgId());
31✔
593
  adv && (pixelURL += '&adv=' + enc(adv));
31✔
594
  pixelURL += '&orig=' + enc(getDomainFromUrl(referrer));
31✔
595
  pixelURL += '&ss=' + enc(isS2SBidder(winningBid.bidder));
31✔
596
  (fskp != undefined) && (pixelURL += '&fskp=' + enc(fskp));
31✔
597
  if (floorData) {
31✔
598
    const floorRootValues = getFloorsCommonField(floorData.floorRequestData);
31✔
599
    if (floorRootValues) {
31✔
600
      const { ffs, fsrc, fp, mv } = floorRootValues || {};
30!
601
      const params = { ffs, fsrc, fp, fmv: mv };
30✔
602
      Object.entries(params).forEach(([key, value]) => {
120✔
603
        if (value !== undefined) {
120✔
604
          pixelURL += `&${key}=${enc(value)}`;
120✔
605
        }
606
      });
607
    }
608
    const floorType = getFloorType(floorData.floorResponseData);
31✔
609
    if (floorType !== undefined) {
31✔
610
      pixelURL += '&ft=' + enc(floorType);
31✔
611
    }
612
    const floorRuleValue = winningBid?.bidResponse?.floorData?.floorRuleValue;
31✔
613
    (floorRuleValue !== undefined) && (pixelURL += '&frv=' + enc(floorRuleValue));
31✔
614

615
    const floorValue = winningBid?.bidResponse?.floorData?.floorValue;
31✔
616
    (floorValue !== undefined) && (pixelURL += '&fv=' + enc(floorValue));
31✔
617
  }
618
  pixelURL += '&af=' + enc(winningBid.bidResponse ? (winningBid.bidResponse.mediaType || undefined) : undefined);
31!
619

620
  ajax(
31✔
621
    pixelURL,
622
    null,
623
    null,
624
    {
625
      contentType: 'application/x-www-form-urlencoded',
626
      withCredentials: true,
627
      method: 'GET'
628
    }
629
  );
630
}
631

632
/// /////////// ADAPTER EVENT HANDLER FUNCTIONS //////////////
633

634
function auctionInitHandler(args) {
635
  s2sBidders = (function () {
22✔
636
    const s2sBidders = [];
22✔
637
    try {
22✔
638
      const s2sConf = config.getConfig('s2sConfig');
22✔
639
      if (isArray(s2sConf)) {
22!
640
        s2sConf.forEach(conf => {
×
641
          if (conf?.bidders) {
×
642
            s2sBidders.push(...conf.bidders);
×
643
          }
644
        });
645
      } else if (s2sConf?.bidders) {
22✔
646
        s2sBidders.push(...s2sConf.bidders);
22✔
647
      }
648
    } catch (e) {
649
      logError('Error processing s2s bidders:', e);
×
650
    }
651
    return s2sBidders || [];
22!
652
  }());
653
  const cacheEntry = pick(args, [
22✔
654
    'timestamp',
655
    'timeout',
656
    'bidderDonePendingCount', () => args.bidderRequests.length,
22✔
657
  ]);
658
  cacheEntry.adUnitCodes = {};
22✔
659
  cacheEntry.floorData = {};
22✔
660
  cacheEntry.origAdUnits = args.adUnits;
22✔
661
  cacheEntry.referer = args.bidderRequests[0].refererInfo.topmostLocation;
22✔
662
  cache.auctions[args.auctionId] = cacheEntry;
22✔
663
}
664

665
function bidRequestedHandler(args) {
666
  args.bids.forEach(function(bid) {
20✔
667
    if (!cache.auctions[args.auctionId].adUnitCodes.hasOwnProperty(bid.adUnitCode)) {
39✔
668
      cache.auctions[args.auctionId].adUnitCodes[bid.adUnitCode] = {
39✔
669
        bids: {},
670
        bidWon: false,
671
        dimensions: bid.sizes
672
      };
673
    }
674
    if (bid.bidder === 'pubmatic' && !!bid?.params?.wiid) {
39!
675
      cache.auctions[args.auctionId].wiid = bid.params.wiid;
×
676
    }
677
    cache.auctions[args.auctionId].adUnitCodes[bid.adUnitCode].bids[bid.bidId] = [copyRequiredBidDetails(bid)];
39✔
678
    if (bid.floorData) {
39✔
679
      cache.auctions[args.auctionId].floorData['floorRequestData'] = bid.floorData;
19✔
680
    }
681
  })
682
}
683

684
function bidResponseHandler(args) {
685
  if (!args.requestId) {
36!
686
    logWarn(LOG_PRE_FIX + 'Got null requestId in bidResponseHandler');
×
687
    return;
×
688
  }
689
  const requestId = args.originalRequestId || args.requestId;
36✔
690
  let bid = cache.auctions[args.auctionId].adUnitCodes[args.adUnitCode].bids[requestId][0];
36✔
691
  if (!bid) {
36!
692
    logError(LOG_PRE_FIX + 'Could not find associated bid request for bid response with requestId: ', args.requestId);
×
693
    return;
×
694
  }
695

696
  if ((bid.bidder && args.bidderCode && bid.bidder !== args.bidderCode) || (bid.bidder === args.bidderCode && bid.status === SUCCESS)) {
36!
697
    bid = copyRequiredBidDetails(args);
×
698
    cache.auctions[args.auctionId].adUnitCodes[args.adUnitCode].bids[requestId].push(bid);
×
699
  } else if (args.originalRequestId) {
36✔
700
    bid.bidId = args.requestId;
2✔
701
  }
702

703
  if (args.floorData) {
36✔
704
    cache.auctions[args.auctionId].floorData['floorResponseData'] = args.floorData;
36✔
705
  }
706

707
  bid.adId = args.adId;
36✔
708
  bid.source = formatSource(bid.source || args.source);
36✔
709
  setBidStatus(bid, 1);
36✔
710
  const latency = args?.timeToRespond || Date.now() - cache.auctions[args.auctionId].timestamp;
36!
711
  const auctionTime = cache.auctions[args.auctionId].timeout;
36✔
712
  // Check if latency is greater than auctiontime+150, then log auctiontime+150 to avoid large numbers
713
  bid.partnerTimeToRespond = latency > (auctionTime + 150) ? (auctionTime + 150) : latency;
36!
714
  bid.clientLatencyTimeMs = Date.now() - cache.auctions[args.auctionId].timestamp;
36✔
715
  bid.bidResponse = parseBidResponse(args);
36✔
716
}
717

718
function bidRejectedHandler(args) {
719
  // If bid is rejected due to floors value did not met
720
  // make cpm as 0, status as bidRejected and forward the bid for logging
721
  if (args.rejectionReason === REJECTION_REASON.FLOOR_NOT_MET) {
1✔
722
    args.cpm = 0;
1✔
723
    args.status = BID_STATUS.BID_REJECTED;
1✔
724
    bidResponseHandler(args);
1✔
725
  }
726
}
727

728
function bidderDoneHandler(args) {
729
  cache.auctions[args.auctionId].bidderDonePendingCount--;
18✔
730
  args.bids.forEach(bid => {
×
731
    const cachedBid = cache.auctions[bid.auctionId].adUnitCodes[bid.adUnitCode].bids[bid.bidId || bid.originalRequestId || bid.requestId];
×
732
    if (typeof bid.serverResponseTimeMs !== 'undefined') {
×
733
      cachedBid.serverLatencyTimeMs = bid.serverResponseTimeMs;
×
734
    }
735
    if (!cachedBid.status) {
×
736
      cachedBid.status = NO_BID;
×
737
    }
738
    if (!cachedBid.clientLatencyTimeMs) {
×
739
      cachedBid.clientLatencyTimeMs = Date.now() - cache.auctions[bid.auctionId].timestamp;
×
740
    }
741
  });
742
}
743

744
function bidWonHandler(args) {
745
  const auctionCache = cache.auctions[args.auctionId];
32✔
746
  auctionCache.adUnitCodes[args.adUnitCode].bidWon = args.originalRequestId || args.requestId;
32✔
747
  auctionCache.adUnitCodes[args.adUnitCode].bidWonAdId = args.adId;
32✔
748
  executeBidWonLoggerCall(args.auctionId, args.adUnitCode);
32✔
749
}
750

751
function auctionEndHandler(args) {
752
  // if for the given auction bidderDonePendingCount == 0 then execute logger call sooners
753
  const highestCpmBids = getGlobal().getHighestCpmBids() || [];
20!
754
  setTimeout(() => {
20✔
755
    executeBidsLoggerCall.call(this, args, highestCpmBids);
20✔
756
  }, (cache.auctions[args.auctionId]?.bidderDonePendingCount === 0 ? 500 : SEND_TIMEOUT));
20!
757
}
758

759
function bidTimeoutHandler(args) {
760
  // db = 1 and t = 1 means bidder did NOT respond with a bid but we got a timeout notification
761
  // db = 0 and t = 1 means bidder did  respond with a bid but post timeout
762
  args.forEach(badBid => {
2✔
763
    const auctionCache = cache.auctions[badBid.auctionId];
2✔
764
    const bid = auctionCache.adUnitCodes[badBid.adUnitCode].bids[ badBid.bidId || badBid.originalRequestId || badBid.requestId ][0];
2!
765
    if (bid) {
2!
766
      bid.status = ERROR;
2✔
767
      bid.error = {
2✔
768
        code: TIMEOUT_ERROR
769
      };
770
    } else {
771
      logWarn(LOG_PRE_FIX + 'bid not found');
×
772
    }
773
  });
774
}
775

776
/// /////////// ADAPTER DEFINITION //////////////
777

778
const baseAdapter = adapter({analyticsType: 'endpoint'});
1✔
779
const pubmaticAdapter = Object.assign({}, baseAdapter, {
1✔
780

781
  enableAnalytics(conf = {}) {
21!
782
    let error = false;
21✔
783

784
    if (typeof conf.options === 'object') {
21!
785
      if (conf.options.publisherId) {
21✔
786
        publisherId = Number(conf.options.publisherId);
20✔
787
      }
788
      profileId = Number(conf.options.profileId) || DEFAULT_PROFILE_ID;
21✔
789
      profileVersionId = Number(conf.options.profileVersionId) || DEFAULT_PROFILE_VERSION_ID;
21✔
790
    } else {
791
      logError(LOG_PRE_FIX + 'Config not found.');
×
792
      error = true;
×
793
    }
794

795
    if (!publisherId) {
21✔
796
      logError(LOG_PRE_FIX + 'Missing publisherId(Number).');
1✔
797
      error = true;
1✔
798
    }
799

800
    if (error) {
21✔
801
      logError(LOG_PRE_FIX + 'Not collecting data due to error(s).');
1✔
802
    } else {
803
      baseAdapter.enableAnalytics.call(this, conf);
20✔
804
    }
805
  },
806

807
  disableAnalytics() {
808
    publisherId = DEFAULT_PUBLISHER_ID;
20✔
809
    profileId = DEFAULT_PROFILE_ID;
20✔
810
    profileVersionId = DEFAULT_PROFILE_VERSION_ID;
20✔
811
    s2sBidders = [];
20✔
812
    baseAdapter.disableAnalytics.apply(this, arguments);
20✔
813
  },
814

815
  track({eventType, args}) {
168✔
816
    switch (eventType) {
168✔
817
      case EVENTS.AUCTION_INIT:
818
        auctionInitHandler(args);
22✔
819
        break;
22✔
820
      case EVENTS.BID_REQUESTED:
821
        bidRequestedHandler(args);
20✔
822
        break;
20✔
823
      case EVENTS.BID_RESPONSE:
824
        bidResponseHandler(args);
35✔
825
        break;
35✔
826
      case EVENTS.BID_REJECTED:
827
        bidRejectedHandler(args)
1✔
828
        break;
1✔
829
      case EVENTS.BIDDER_DONE:
830
        bidderDoneHandler(args);
18✔
831
        break;
×
832
      case EVENTS.BID_WON:
833
        bidWonHandler(args);
32✔
834
        break;
32✔
835
      case EVENTS.AUCTION_END:
836
        auctionEndHandler(args);
20✔
837
        break;
20✔
838
      case EVENTS.BID_TIMEOUT:
839
        bidTimeoutHandler(args);
2✔
840
        break;
2✔
841
    }
842
  }
843
});
844

845
/// /////////// ADAPTER REGISTRATION //////////////
846

847
adapterManager.registerAnalyticsAdapter({
1✔
848
  adapter: pubmaticAdapter,
849
  code: ADAPTER_CODE
850
});
851

852
export default pubmaticAdapter;
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