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

prebid / Prebid.js / 19934292619

04 Dec 2025 03:28PM UTC coverage: 96.209%. Remained the same
19934292619

push

github

web-flow
fix tests path in CONTRIBUTING.md (#14235)

53792 of 65902 branches covered (81.62%)

205193 of 213279 relevant lines covered (96.21%)

71.92 hits per line

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

94.34
/modules/adqueryBidAdapter.js
1
import {registerBidder} from '../src/adapters/bidderFactory.js';
1✔
2
import {BANNER, VIDEO} from '../src/mediaTypes.js';
3
import {
4
  buildUrl,
5
  logInfo,
6
  logMessage,
7
  parseSizesInput,
8
  triggerPixel,
9
  deepSetValue
10
} from '../src/utils.js';
11

12
/**
13
 * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
14
 * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
15
 * @typedef {import('../src/adapters/bidderFactory.js').ServerRequest} ServerRequest
16
 * @typedef {import('../src/adapters/bidderFactory.js').BidderSpec} BidderSpec
17
 * @typedef {import('../src/adapters/bidderFactory.js').TimedOutBid} TimedOutBid
18
 */
19

20
const ADQUERY_GVLID = 902;
1✔
21
const ADQUERY_BIDDER_CODE = 'adquery';
1✔
22
const ADQUERY_BIDDER_DOMAIN_PROTOCOL = 'https';
1✔
23
const ADQUERY_BIDDER_DOMAIN = 'bidder.adquery.io';
1✔
24
const ADQUERY_STATIC_DOMAIN_PROTOCOL = 'https';
1✔
25
const ADQUERY_STATIC_DOMAIN = 'api.adquery.io';
1✔
26
const ADQUERY_USER_SYNC_DOMAIN = ADQUERY_BIDDER_DOMAIN;
1✔
27
const ADQUERY_DEFAULT_CURRENCY = 'PLN';
1✔
28
const ADQUERY_NET_REVENUE = true;
1✔
29
const ADQUERY_TTL = 360;
1✔
30

31
/** @type {BidderSpec} */
32
export const spec = {
1✔
33
  code: ADQUERY_BIDDER_CODE,
34
  gvlid: ADQUERY_GVLID,
35
  supportedMediaTypes: [BANNER, VIDEO],
36

37
  /**
38
   * @param {object} bid
39
   * @return {boolean}
40
   */
41
  isBidRequestValid: (bid) => {
42
    const video = bid.mediaTypes && bid.mediaTypes.video;
7✔
43
    if (video) {
7✔
44
      return !!(video.playerSize && video.context === 'outstream');// Focus on outstream
4✔
45
    }
46

47
    return !!(bid && bid.params && bid.params.placementId && bid.mediaTypes.banner.sizes)
3✔
48
  },
49

50
  /**
51
   * @param {BidRequest[]} bidRequests
52
   * @param {*} bidderRequest
53
   * @return {ServerRequest}
54
   */
55
  buildRequests: (bidRequests, bidderRequest) => {
56
    const requests = [];
3✔
57

58
    const adqueryRequestUrl = buildUrl({
3✔
59
      protocol: ADQUERY_BIDDER_DOMAIN_PROTOCOL,
60
      hostname: ADQUERY_BIDDER_DOMAIN,
61
      pathname: '/prebid/bid',
62
    });
63

64
    for (let i = 0, len = bidRequests.length; i < len; i++) {
3✔
65
      const bid = bidRequests[i];
3✔
66
      const isVideo = bid.mediaTypes && bid.mediaTypes.video && bid.mediaTypes.video.context === 'outstream';
3✔
67

68
      let requestUrl = adqueryRequestUrl;
3✔
69

70
      if (isVideo) {
3✔
71
        requestUrl = buildUrl({
2✔
72
          protocol: ADQUERY_BIDDER_DOMAIN_PROTOCOL,
73
          hostname: ADQUERY_BIDDER_DOMAIN,
74
          pathname: '/openrtb2/auction2',
75
        });
76
      }
77

78
      const request = {
3✔
79
        method: 'POST',
80
        url: requestUrl,
81
        data: buildRequest(bid, bidderRequest, isVideo),
82
        options: {
83
          withCredentials: false,
84
          crossOrigin: true
85
        },
86
        bidId: bid.bidId
87
      };
88

89
      requests.push(request);
3✔
90
    }
91
    return requests;
3✔
92
  },
93

94
  /**
95
   * @param {*} response
96
   * @param {ServerRequest} request
97
   * @return {Bid[]}
98
   */
99
  interpretResponse: (response, request) => {
100
    const bidResponses = [];
5✔
101

102
    if (response?.body?.seatbid) {
5✔
103
      response.body.seatbid.forEach(seat => {
2✔
104
        seat.bid.forEach(bid => {
2✔
105
          logMessage('bidObj', bid);
2✔
106

107
          const bidResponse = {
2✔
108
            requestId: bid.impid,
109
            mediaType: 'video',
110
            cpm: bid.price,
111
            currency: response.body.cur || 'USD',
2!
112
            ttl: 3600, // video żyje dłużej
113
            creativeId: bid.crid || bid.id,
4✔
114
            netRevenue: true,
115
            dealId: bid.dealid || undefined,
4✔
116
            nurl: bid.nurl || undefined,
2!
117

118
            // VAST – priority: inline XML > admurl > nurl as a wrapper
119
            vastXml: bid.adm || null,
2!
120
            vastUrl: bid.admurl || null,
4✔
121

122
            width: bid.w || 640,
4✔
123
            height: bid.h || 360,
4✔
124

125
            meta: {
126
              advertiserDomains: bid.adomain && bid.adomain.length ? bid.adomain : [],
4!
127
              networkName: seat.seat || undefined,
2!
128
              mediaType: 'video'
129
            }
130
          };
131

132
          bidResponses.push(bidResponse);
2✔
133
        });
134
      });
135
    }
136

137
    const res = response && response.body && response.body.data;
5✔
138

139
    if (!res) {
5✔
140
      return bidResponses;
3✔
141
    }
142

143
    const bidResponse = {
2✔
144
      requestId: res.requestId,
145
      cpm: res.cpm,
146
      width: res.mediaType.width,
147
      height: res.mediaType.height,
148
      creativeId: res.creationId,
149
      dealId: res.dealid || '',
4✔
150
      currency: res.currency || ADQUERY_DEFAULT_CURRENCY,
2!
151
      netRevenue: ADQUERY_NET_REVENUE,
152
      ttl: ADQUERY_TTL,
153
      referrer: '',
154
      ad: '<script src="' + res.adqLib + '"></script>' + res.tag,
155
      mediaType: res.mediaType.name || 'banner',
2!
156
      meta: {
157
        advertiserDomains: res.adDomains && res.adDomains.length ? res.adDomains : [],
6!
158
        mediaType: res.mediaType.name || 'banner',
2!
159
      }
160
    };
161
    bidResponses.push(bidResponse);
2✔
162
    logInfo('bidResponses', bidResponses);
2✔
163

164
    return bidResponses;
2✔
165
  },
166

167
  /**
168
   * @param {TimedOutBid} timeoutData
169
   */
170
  onTimeout: (timeoutData) => {
171
    if (timeoutData == null) {
1!
172
      return;
×
173
    }
174
    logInfo('onTimeout ', timeoutData);
1✔
175
    const params = {
1✔
176
      bidder: timeoutData.bidder,
177
      bId: timeoutData.bidId,
178
      adUnitCode: timeoutData.adUnitCode,
179
      timeout: timeoutData.timeout,
180
      auctionId: timeoutData.auctionId,
181
    };
182
    const adqueryRequestUrl = buildUrl({
1✔
183
      protocol: ADQUERY_BIDDER_DOMAIN_PROTOCOL,
184
      hostname: ADQUERY_BIDDER_DOMAIN,
185
      pathname: '/prebid/eventTimeout',
186
      search: params
187
    });
188
    triggerPixel(adqueryRequestUrl);
1✔
189
  },
190

191
  /**
192
   * @param {Bid} bid
193
   */
194
  onBidWon: (bid) => {
195
    logInfo('onBidWon', bid);
2✔
196

197
    if (bid.nurl) {
2✔
198
      triggerPixel(bid.nurl)
1✔
199
      return
1✔
200
    }
201

202
    const copyOfBid = { ...bid }
1✔
203
    delete copyOfBid.ad
1✔
204
    const shortBidString = JSON.stringify(copyOfBid);
1✔
205
    const encodedBuf = window.btoa(shortBidString);
1✔
206

207
    const params = {
1✔
208
      q: encodedBuf,
209
    };
210
    const adqueryRequestUrl = buildUrl({
1✔
211
      protocol: ADQUERY_BIDDER_DOMAIN_PROTOCOL,
212
      hostname: ADQUERY_BIDDER_DOMAIN,
213
      pathname: '/prebid/eventBidWon',
214
      search: params
215
    });
216
    triggerPixel(adqueryRequestUrl);
1✔
217
  },
218

219
  /**
220
   * @param {Bid} bid
221
   */
222
  onSetTargeting: (bid) => {
223
    logInfo('onSetTargeting', bid);
×
224

225
    const params = {
×
226
      bidder: bid.bidder,
227
      width: bid.width,
228
      height: bid.height,
229
      bid: bid.adId,
230
      mediaType: bid.mediaType,
231
      cpm: bid.cpm,
232
      requestId: bid.requestId,
233
      adUnitCode: bid.adUnitCode
234
    };
235

236
    const adqueryRequestUrl = buildUrl({
×
237
      protocol: ADQUERY_BIDDER_DOMAIN_PROTOCOL,
238
      hostname: ADQUERY_BIDDER_DOMAIN,
239
      pathname: '/prebid/eventSetTargeting',
240
      search: params
241
    });
242
    triggerPixel(adqueryRequestUrl);
×
243
  },
244
  /**
245
   * Retrieves user synchronization URLs based on provided options and consents.
246
   *
247
   * @param {object} syncOptions - Options for synchronization.
248
   * @param {object[]} serverResponses - Array of server responses.
249
   * @param {object} gdprConsent - GDPR consent object.
250
   * @param {object} uspConsent - USP consent object.
251
   * @returns {object[]} - Array of synchronization URLs.
252
   */
253
  getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => {
254
    logMessage('getUserSyncs', syncOptions, serverResponses, gdprConsent, uspConsent);
3✔
255
    const syncData = {
3✔
256
      'gdpr': gdprConsent && gdprConsent.gdprApplies ? 1 : 0,
9!
257
      'gdpr_consent': gdprConsent && gdprConsent.consentString ? gdprConsent.consentString : '',
9!
258
      'ccpa_consent': uspConsent && uspConsent.uspConsent ? uspConsent.uspConsent : '',
9!
259
    };
260

261
    if (window.qid) { // only for new users (new qid)
3✔
262
      syncData.qid = window.qid;
3✔
263
    }
264

265
    const syncUrlObject = {
3✔
266
      protocol: ADQUERY_BIDDER_DOMAIN_PROTOCOL,
267
      hostname: ADQUERY_USER_SYNC_DOMAIN,
268
      pathname: '/prebid/userSync',
269
      search: syncData
270
    };
271

272
    if (syncOptions.iframeEnabled) {
3✔
273
      syncUrlObject.protocol = ADQUERY_STATIC_DOMAIN_PROTOCOL;
1✔
274
      syncUrlObject.hostname = ADQUERY_STATIC_DOMAIN;
1✔
275
      syncUrlObject.pathname = '/user-sync-iframe.html';
1✔
276

277
      return [{
1✔
278
        type: 'iframe',
279
        url: buildUrl(syncUrlObject)
280
      }];
281
    }
282

283
    return [{
2✔
284
      type: 'image',
285
      url: buildUrl(syncUrlObject)
286
    }];
287
  }
288
};
289

290
function buildRequest(bid, bidderRequest, isVideo = false) {
3✔
291
  let userId = null;
3✔
292
  if (window.qid) {
3✔
293
    userId = window.qid;
2✔
294
  }
295

296
  if (bid.userId && bid.userId.qid) {
3!
297
    userId = bid.userId.qid
×
298
  }
299

300
  if (!userId) {
3✔
301
    userId = bid.ortb2?.user.ext.eids.find(eid => eid.source === "adquery.io")?.uids[0]?.id;
1!
302
  }
303

304
  if (!userId) {
3✔
305
    // onetime User ID
306
    const ramdomValues = Array.from(window.crypto.getRandomValues(new Uint32Array(4)));
1✔
307
    userId = ramdomValues.map(val => val.toString(36)).join('').substring(0, 20);
4✔
308
    logMessage('generated onetime User ID: ', userId);
1✔
309
    window.qid = userId;
1✔
310
  }
311

312
  let pageUrl = '';
3✔
313
  if (bidderRequest && bidderRequest.refererInfo) {
3✔
314
    pageUrl = bidderRequest.refererInfo.page || '';
3✔
315
  }
316

317
  if (isVideo) {
3✔
318
    let baseRequest = bid.ortb2
2✔
319
    let videoRequest = {
2✔
320
      ...baseRequest,
321
      imp: [{
322
        id: bid.bidId,
323
        video: bid.ortb2Imp?.video || {},
8!
324
      }]
325
    }
326

327
    deepSetValue(videoRequest, 'site.ext.bidder', bid.params);
2✔
328
    videoRequest.id = bid.bidId
2✔
329

330
    let currency = bid?.ortb2?.ext?.prebid?.adServerCurrency || "PLN";
2!
331
    videoRequest.cur = [ currency ]
2✔
332

333
    let floorInfo;
334
    if (typeof bid.getFloor === 'function') {
2✔
335
      floorInfo = bid.getFloor({
1✔
336
        currency: currency,
337
        mediaType: "video",
338
        size: "*"
339
      });
340
    }
341
    const bidfloor = floorInfo?.floor;
2✔
342
    const bidfloorcur = floorInfo?.currency;
2✔
343

344
    if (bidfloor && bidfloorcur) {
2✔
345
      videoRequest.imp[0].video.bidfloor = bidfloor
1✔
346
      videoRequest.imp[0].video.bidfloorcur = bidfloorcur
1✔
347
    }
348

349
    return videoRequest
2✔
350
  }
351

352
  return {
1✔
353
    v: '$prebid.version$',
354
    placementCode: bid.params.placementId,
355
    auctionId: null,
356
    type: bid.params.type,
357
    adUnitCode: bid.adUnitCode,
358
    bidQid: userId,
359
    bidId: bid.bidId,
360
    bidder: bid.bidder,
361
    bidPageUrl: pageUrl,
362
    bidderRequestId: bid.bidderRequestId,
363
    bidRequestsCount: bid.bidRequestsCount,
364
    bidderRequestsCount: bid.bidderRequestsCount,
365
    sizes: parseSizesInput(bid.mediaTypes.banner.sizes).toString(),
366
  };
367
}
368

369
registerBidder(spec);
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