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

prebid / Prebid.js / 18594521186

17 Oct 2025 01:40PM UTC coverage: 96.238% (-0.001%) from 96.239%
18594521186

push

github

web-flow
Semantiq RTD module: fix incorrect property name (#14027)

Co-authored-by: Alexandr Kim <alexandr.kim@audienzz.ch>

52437 of 64151 branches covered (81.74%)

1 of 1 new or added line in 1 file covered. (100.0%)

401 existing lines in 53 files now uncovered.

200307 of 208138 relevant lines covered (96.24%)

125.2 hits per line

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

83.48
/modules/atsAnalyticsAdapter.js
1
import { logError, logInfo } from '../src/utils.js';
1✔
2
import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js';
3
import { EVENTS } from '../src/constants.js';
4
import adaptermanager from '../src/adapterManager.js';
5
import {ajax} from '../src/ajax.js';
6
import {getStorageManager} from '../src/storageManager.js';
7
import {getGlobal} from '../src/prebidGlobal.js';
8

9
import {MODULE_TYPE_ANALYTICS} from '../src/activities/modules.js';
10
const MODULE_CODE = 'atsAnalytics';
1✔
11
export const storage = getStorageManager({moduleType: MODULE_TYPE_ANALYTICS, moduleName: MODULE_CODE});
1✔
12

13
/**
14
 * Analytics adapter for - https://liveramp.com
15
 * Maintainer - prebid@liveramp.com
16
 */
17

18
const analyticsType = 'endpoint';
1✔
19

20
const preflightUrl = 'https://check.analytics.rlcdn.com/check/';
1✔
21
export const analyticsUrl = 'https://analytics.rlcdn.com';
1✔
22

23
let handlerRequest = [];
1✔
24
const handlerResponse = [];
1✔
25

26
const atsAnalyticsAdapterVersion = 3;
1✔
27

28
const browsersList = [
1✔
29
  /* Googlebot */
30
  {
31
    test: /googlebot/i,
32
    name: 'Googlebot'
33
  },
34

35
  /* Opera < 13.0 */
36
  {
37
    test: /opera/i,
38
    name: 'Opera',
39
  },
40

41
  /* Opera > 13.0 */
42
  {
43
    test: /opr\/|opios/i,
44
    name: 'Opera'
45
  },
46
  {
47
    test: /SamsungBrowser/i,
48
    name: 'Samsung Internet for Android',
49
  },
50
  {
51
    test: /Whale/i,
52
    name: 'NAVER Whale Browser',
53
  },
54
  {
55
    test: /MZBrowser/i,
56
    name: 'MZ Browser'
57
  },
58
  {
59
    test: /focus/i,
60
    name: 'Focus',
61
  },
62
  {
63
    test: /swing/i,
64
    name: 'Swing',
65
  },
66
  {
67
    test: /coast/i,
68
    name: 'Opera Coast',
69
  },
70
  {
71
    test: /opt\/\d+(?:.?_?\d+)+/i,
72
    name: 'Opera Touch',
73
  },
74
  {
75
    test: /yabrowser/i,
76
    name: 'Yandex Browser',
77
  },
78
  {
79
    test: /ucbrowser/i,
80
    name: 'UC Browser',
81
  },
82
  {
83
    test: /Maxthon|mxios/i,
84
    name: 'Maxthon',
85
  },
86
  {
87
    test: /epiphany/i,
88
    name: 'Epiphany',
89
  },
90
  {
91
    test: /puffin/i,
92
    name: 'Puffin',
93
  },
94
  {
95
    test: /sleipnir/i,
96
    name: 'Sleipnir',
97
  },
98
  {
99
    test: /k-meleon/i,
100
    name: 'K-Meleon',
101
  },
102
  {
103
    test: /micromessenger/i,
104
    name: 'WeChat',
105
  },
106
  {
107
    test: /qqbrowser/i,
108
    name: (/qqbrowserlite/i).test(window.navigator.userAgent) ? 'QQ Browser Lite' : 'QQ Browser',
1!
109
  },
110
  {
111
    test: /msie|trident/i,
112
    name: 'Internet Explorer',
113
  },
114
  {
115
    test: /\sedg\//i,
116
    name: 'Microsoft Edge',
117
  },
118
  {
119
    test: /edg([ea]|ios)/i,
120
    name: 'Microsoft Edge',
121
  },
122
  {
123
    test: /vivaldi/i,
124
    name: 'Vivaldi',
125
  },
126
  {
127
    test: /seamonkey/i,
128
    name: 'SeaMonkey',
129
  },
130
  {
131
    test: /sailfish/i,
132
    name: 'Sailfish',
133
  },
134
  {
135
    test: /silk/i,
136
    name: 'Amazon Silk',
137
  },
138
  {
139
    test: /phantom/i,
140
    name: 'PhantomJS',
141
  },
142
  {
143
    test: /slimerjs/i,
144
    name: 'SlimerJS',
145
  },
146
  {
147
    test: /blackberry|\bbb\d+/i,
148
    name: 'BlackBerry',
149
  },
150
  {
151
    test: /(web|hpw)[o0]s/i,
152
    name: 'WebOS Browser',
153
  },
154
  {
155
    test: /bada/i,
156
    name: 'Bada',
157
  },
158
  {
159
    test: /tizen/i,
160
    name: 'Tizen',
161
  },
162
  {
163
    test: /qupzilla/i,
164
    name: 'QupZilla',
165
  },
166
  {
167
    test: /firefox|iceweasel|fxios/i,
168
    name: 'Firefox',
169
  },
170
  {
171
    test: /electron/i,
172
    name: 'Electron',
173
  },
174
  {
175
    test: /MiuiBrowser/i,
176
    name: 'Miui',
177
  },
178
  {
179
    test: /chromium/i,
180
    name: 'Chromium',
181
  },
182
  {
183
    test: /chrome|crios|crmo/i,
184
    name: 'Chrome',
185
  },
186
  {
187
    test: /GSA/i,
188
    name: 'Google Search',
189
  },
190

191
  /* Android Browser */
192
  {
193
    test: /android/i,
194
    name: 'Android Browser',
195
  },
196

197
  /* PlayStation 4 */
198
  {
199
    test: /playstation 4/i,
200
    name: 'PlayStation 4',
201
  },
202

203
  /* Safari */
204
  {
205
    test: /safari|applewebkit/i,
206
    name: 'Safari',
207
  },
208
];
209

210
const listOfSupportedBrowsers = ['Safari', 'Chrome', 'Firefox', 'Microsoft Edge'];
1✔
211

212
export function bidRequestedHandler(args) {
213
  const envelopeSourceCookieValue = storage.getCookie('_lr_env_src_ats');
11✔
214
  const envelopeSource = envelopeSourceCookieValue === 'true';
11✔
215
  let requests;
216
  requests = args.bids.map(function(bid) {
11✔
217
    return {
11✔
218
      envelope_source: envelopeSource,
219
      has_envelope: (function() {
220
        // Check userIdAsEids for Prebid v10.0+ compatibility
221
        if (bid.userIdAsEids && Array.isArray(bid.userIdAsEids)) {
11✔
222
          const liverampEid = bid.userIdAsEids.find(eid =>
7✔
223
            eid.source === 'liveramp.com'
7✔
224
          );
225
          if (liverampEid && liverampEid.uids && liverampEid.uids.length > 0) {
7✔
226
            return true;
2✔
227
          }
228
        }
229

230
        // Fallback for older versions (backward compatibility)
231
        if (bid.userId && bid.userId.idl_env) {
9✔
232
          return true;
2✔
233
        }
234

235
        return false;
7✔
236
      })(),
237
      bidder: bid.bidder,
238
      bid_id: bid.bidId,
239
      auction_id: args.auctionId,
240
      user_browser: parseBrowser(),
241
      user_platform: navigator.platform,
242
      auction_start: new Date(args.auctionStart).toJSON(),
243
      domain: window.location.hostname,
244
      pid: atsAnalyticsAdapter.context.pid,
245
      adapter_version: atsAnalyticsAdapterVersion,
246
      bid_won: false
247
    };
248
  });
249
  return requests;
11✔
250
}
251

252
function bidResponseHandler(args) {
253
  return {
1✔
254
    bid_id: args.requestId,
255
    response_time_stamp: new Date(args.responseTimestamp).toJSON(),
256
    currency: args.currency,
257
    cpm: args.cpm,
258
    net_revenue: args.netRevenue
259
  };
260
}
261

262
export function parseBrowser() {
263
  const ua = atsAnalyticsAdapter.getUserAgent();
17✔
264
  try {
17✔
265
    const result = browsersList.filter(function(obj) {
17✔
266
      return obj.test.test(ua);
714✔
267
    });
268
    const browserName = result && result.length ? result[0].name : '';
17✔
269
    return (listOfSupportedBrowsers.indexOf(browserName) >= 0) ? browserName : 'Unknown';
17✔
270
  } catch (err) {
UNCOV
271
    logError('ATS Analytics - Error while checking user browser!', err);
×
272
  }
273
}
274

275
function sendDataToAnalytic (events) {
276
  // send data to ats analytic endpoint
277
  try {
1✔
278
    const dataToSend = {'Data': events};
1✔
279
    const strJSON = JSON.stringify(dataToSend);
1✔
280
    logInfo('ATS Analytics - tried to send analytics data!');
1✔
281
    ajax(analyticsUrl, function () {
1✔
282
      logInfo('ATS Analytics - events sent successfully!');
×
283
    }, strJSON, {method: 'POST', contentType: 'application/json'});
284
  } catch (err) {
285
    logError('ATS Analytics - request encounter an error: ', err);
×
286
  }
287
}
288

289
// preflight request, to check did publisher have permission to send data to analytics endpoint
290
function preflightRequest (events) {
UNCOV
291
  logInfo('ATS Analytics - preflight request!');
×
UNCOV
292
  ajax(preflightUrl + atsAnalyticsAdapter.context.pid,
×
293
    {
294
      success: function (data) {
UNCOV
295
        const samplingRateObject = JSON.parse(data);
×
UNCOV
296
        logInfo('ATS Analytics - Sampling Rate: ', samplingRateObject);
×
UNCOV
297
        const samplingRate = samplingRateObject.samplingRate;
×
UNCOV
298
        atsAnalyticsAdapter.setSamplingCookie(samplingRate);
×
UNCOV
299
        const samplingRateNumber = Number(samplingRate);
×
UNCOV
300
        if (data && samplingRate && atsAnalyticsAdapter.shouldFireRequest(samplingRateNumber)) {
×
UNCOV
301
          logInfo('ATS Analytics - events to send: ', events);
×
UNCOV
302
          sendDataToAnalytic(events);
×
303
        }
304
      },
305
      error: function () {
UNCOV
306
        atsAnalyticsAdapter.setSamplingCookie(0);
×
UNCOV
307
        logInfo('ATS Analytics - Sampling Rate Request Error!');
×
308
      }
309
    }, undefined, {method: 'GET', crossOrigin: true});
310
}
311

312
const atsAnalyticsAdapter = Object.assign(adapter(
1✔
313
  {
314
    analyticsType
315
  }),
316
{
317
  track({eventType, args}) {
7✔
318
    if (typeof args !== 'undefined') {
7✔
319
      atsAnalyticsAdapter.callHandler(eventType, args);
7✔
320
    }
321
  }
322
});
323

324
// save the base class function
325
atsAnalyticsAdapter.originEnableAnalytics = atsAnalyticsAdapter.enableAnalytics;
1✔
326

327
// add check to not fire request every time, but instead to send 1/100
328
atsAnalyticsAdapter.shouldFireRequest = function (samplingRate) {
1✔
329
  if (samplingRate !== 0) {
4✔
330
    const shouldFireRequestValue = (Math.floor((Math.random() * 100 + 1)) === 100);
3✔
331
    logInfo('ATS Analytics - Should Fire Request: ', shouldFireRequestValue);
3✔
332
    return shouldFireRequestValue;
3✔
333
  } else {
334
    logInfo('ATS Analytics - Should Fire Request: ', false);
1✔
335
    return false;
1✔
336
  }
337
};
338

339
atsAnalyticsAdapter.getUserAgent = function () {
1✔
UNCOV
340
  return window.navigator.userAgent;
×
341
};
342

343
atsAnalyticsAdapter.setSamplingCookie = function (samplRate) {
1✔
344
  const now = new Date();
2✔
345
  now.setTime(now.getTime() + 604800000);
2✔
346
  storage.setCookie('_lr_sampling_rate', samplRate, now.toUTCString());
2✔
347
}
348

349
// override enableAnalytics so we can get access to the config passed in from the page
350
atsAnalyticsAdapter.enableAnalytics = function (config) {
1✔
351
  if (!config.options.pid) {
12✔
352
    logError('ATS Analytics - Publisher ID (pid) option is not defined. Analytics won\'t work');
1✔
353
    return;
1✔
354
  }
355
  atsAnalyticsAdapter.context = {
11✔
356
    events: [],
357
    pid: config.options.pid,
358
    bidWonTimeout: config.options.bidWonTimeout
359
  };
360
  logInfo('ATS Analytics - adapter enabled! ');
11✔
361
  atsAnalyticsAdapter.originEnableAnalytics(config);
11✔
362
};
363

364
atsAnalyticsAdapter.callHandler = function (evtype, args) {
1✔
365
  if (evtype === EVENTS.BID_REQUESTED) {
7✔
366
    handlerRequest = handlerRequest.concat(bidRequestedHandler(args));
1✔
367
  } else if (evtype === EVENTS.BID_RESPONSE) {
6✔
368
    handlerResponse.push(bidResponseHandler(args));
1✔
369
  }
370
  if (evtype === EVENTS.AUCTION_END) {
7✔
371
    const bidWonTimeout = atsAnalyticsAdapter.context.bidWonTimeout ? atsAnalyticsAdapter.context.bidWonTimeout : 2000;
1!
372
    let events = [];
1✔
373
    setTimeout(() => {
1✔
374
      const winningBids = getGlobal().getAllWinningBids();
1✔
375
      logInfo('ATS Analytics - winning bids: ', winningBids)
1✔
376
      // prepare format data for sending to analytics endpoint
377
      if (handlerRequest.length) {
1✔
378
        const wonEvent = {};
1✔
379
        if (handlerResponse.length) {
1!
380
          events = [];
1✔
381
          handlerRequest.forEach(request => {
1✔
382
            handlerResponse.forEach(function (response) {
1✔
383
              if (request.bid_id === response.bid_id) {
1✔
384
                Object.assign(request, response);
1✔
385
              }
386
            });
387
            events.push(request);
1✔
388
          });
389
          if (winningBids.length) {
1✔
390
            events = events.map(event => {
1✔
391
              winningBids.forEach(function (won) {
1✔
392
                wonEvent.bid_id = won.requestId;
1✔
393
                wonEvent.bid_won = true;
1✔
394
                if (event.bid_id === wonEvent.bid_id) {
1✔
395
                  Object.assign(event, wonEvent);
1✔
396
                }
397
              });
398
              return event;
1✔
399
            })
400
          }
401
        } else {
UNCOV
402
          events = handlerRequest;
×
403
        }
404
        // check should we send data to analytics or not, check first cookie value _lr_sampling_rate
405
        try {
1✔
406
          const samplingRateCookie = storage.getCookie('_lr_sampling_rate');
1✔
407
          if (!samplingRateCookie) {
1!
UNCOV
408
            preflightRequest(events);
×
409
          } else {
410
            if (atsAnalyticsAdapter.shouldFireRequest(parseInt(samplingRateCookie))) {
1✔
411
              logInfo('ATS Analytics - events to send: ', events);
1✔
412
              sendDataToAnalytic(events);
1✔
413
            }
414
          }
415
          // empty events array to not send duplicate events
416
          events = [];
1✔
417
        } catch (err) {
UNCOV
418
          logError('ATS Analytics - preflight request encounter an error: ', err);
×
419
        }
420
      }
421
    }, bidWonTimeout);
422
  }
423
}
424

425
adaptermanager.registerAnalyticsAdapter({
1✔
426
  adapter: atsAnalyticsAdapter,
427
  code: MODULE_CODE,
428
  gvlid: 97
429
});
430

431
export default atsAnalyticsAdapter;
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