prebid.js 7.46.0 → 7.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/33acrossBidAdapter.js +1 -1
- package/dist/33acrossIdSystem.js +1 -1
- package/dist/ablidaBidAdapter.js +1 -1
- package/dist/adagioBidAdapter.js +1 -1
- package/dist/adbookpspBidAdapter.js +1 -1
- package/dist/adgenerationBidAdapter.js +1 -1
- package/dist/admaticBidAdapter.js +1 -1
- package/dist/adrelevantisBidAdapter.js +1 -1
- package/dist/adrinoBidAdapter.js +1 -1
- package/dist/adtrgtmeBidAdapter.js +1 -1
- package/dist/adxcgBidAdapter.js +1 -1
- package/dist/adyoulikeBidAdapter.js +1 -1
- package/dist/ajaBidAdapter.js +1 -1
- package/dist/amxBidAdapter.js +1 -1
- package/dist/amxIdSystem.js +1 -1
- package/dist/appierAnalyticsAdapter.js +1 -1
- package/dist/appnexusBidAdapter.js +1 -1
- package/dist/asoBidAdapter.js +1 -1
- package/dist/axonixBidAdapter.js +1 -1
- package/dist/bidglassBidAdapter.js +1 -1
- package/dist/big-richmediaBidAdapter.js +1 -1
- package/dist/bridgewellBidAdapter.js +1 -1
- package/dist/brightMountainMediaBidAdapter.js +1 -1
- package/dist/carodaBidAdapter.js +1 -1
- package/dist/chtnwBidAdapter.js +1 -1
- package/dist/concertBidAdapter.js +1 -1
- package/dist/connectIdSystem.js +1 -1
- package/dist/connectadBidAdapter.js +1 -1
- package/dist/consumableBidAdapter.js +1 -1
- package/dist/conversantAnalyticsAdapter.js +1 -1
- package/dist/conversantBidAdapter.js +1 -1
- package/dist/craftBidAdapter.js +1 -1
- package/dist/criteoBidAdapter.js +1 -1
- package/dist/criteoIdSystem.js +1 -1
- package/dist/cwireBidAdapter.js +1 -1
- package/dist/dependencies.json +4 -0
- package/dist/dspxBidAdapter.js +1 -1
- package/dist/emtvBidAdapter.js +1 -0
- package/dist/eplanningBidAdapter.js +1 -1
- package/dist/feedadBidAdapter.js +1 -1
- package/dist/finativeBidAdapter.js +1 -1
- package/dist/freewheel-sspBidAdapter.js +1 -1
- package/dist/glimpseBidAdapter.js +1 -1
- package/dist/gmosspBidAdapter.js +1 -1
- package/dist/goldbachBidAdapter.js +1 -1
- package/dist/greenbidsAnalyticsAdapter.js +1 -1
- package/dist/greenbidsRtdProvider.js +1 -0
- package/dist/gridBidAdapter.js +1 -1
- package/dist/gumgumBidAdapter.js +1 -1
- package/dist/h12mediaBidAdapter.js +1 -1
- package/dist/id5IdSystem.js +1 -1
- package/dist/impactifyBidAdapter.js +1 -1
- package/dist/improvedigitalBidAdapter.js +1 -1
- package/dist/inmarBidAdapter.js +1 -1
- package/dist/insticatorBidAdapter.js +1 -1
- package/dist/iqmBidAdapter.js +1 -1
- package/dist/ixBidAdapter.js +1 -1
- package/dist/justpremiumBidAdapter.js +1 -1
- package/dist/kargoBidAdapter.js +1 -1
- package/dist/konduitAnalyticsAdapter.js +1 -1
- package/dist/kueezBidAdapter.js +1 -1
- package/dist/kueezRtbBidAdapter.js +1 -1
- package/dist/kulturemediaBidAdapter.js +1 -1
- package/dist/lassoBidAdapter.js +1 -1
- package/dist/lifestreetBidAdapter.js +1 -1
- package/dist/liveyieldAnalyticsAdapter.js +1 -1
- package/dist/logicadBidAdapter.js +1 -1
- package/dist/loglyliftBidAdapter.js +1 -1
- package/dist/magniteAnalyticsAdapter.js +1 -1
- package/dist/malltvAnalyticsAdapter.js +1 -1
- package/dist/marsmediaBidAdapter.js +1 -1
- package/dist/mediafuseBidAdapter.js +1 -1
- package/dist/mediasquareBidAdapter.js +1 -1
- package/dist/mgidBidAdapter.js +1 -1
- package/dist/minutemediaBidAdapter.js +1 -1
- package/dist/minutemediaplusBidAdapter.js +1 -1
- package/dist/missenaBidAdapter.js +1 -1
- package/dist/nextMillenniumBidAdapter.js +1 -1
- package/dist/nexx360BidAdapter.js +1 -1
- package/dist/not-for-prod/prebid.js +142 -139
- package/dist/oguryBidAdapter.js +1 -1
- package/dist/onetagBidAdapter.js +1 -1
- package/dist/ooloAnalyticsAdapter.js +1 -1
- package/dist/optidigitalBidAdapter.js +1 -1
- package/dist/orbitsoftBidAdapter.js +1 -1
- package/dist/outbrainBidAdapter.js +1 -1
- package/dist/parrableIdSystem.js +1 -1
- package/dist/pixfutureBidAdapter.js +1 -1
- package/dist/prebid-core.js +1 -1
- package/dist/publinkIdSystem.js +1 -1
- package/dist/pubmaticBidAdapter.js +1 -1
- package/dist/pubwiseAnalyticsAdapter.js +1 -1
- package/dist/pxyzBidAdapter.js +1 -1
- package/dist/quantcastBidAdapter.js +1 -1
- package/dist/radsBidAdapter.js +1 -1
- package/dist/readpeakBidAdapter.js +1 -1
- package/dist/relaidoBidAdapter.js +1 -1
- package/dist/relevantdigitalBidAdapter.js +1 -0
- package/dist/rhythmoneBidAdapter.js +1 -1
- package/dist/riseBidAdapter.js +1 -1
- package/dist/rtbhouseBidAdapter.js +1 -1
- package/dist/rubiconAnalyticsAdapter.js +1 -1
- package/dist/rubiconBidAdapter.js +1 -1
- package/dist/seedingAllianceBidAdapter.js +1 -1
- package/dist/seedtagBidAdapter.js +1 -1
- package/dist/sharethroughAnalyticsAdapter.js +1 -1
- package/dist/sharethroughBidAdapter.js +1 -1
- package/dist/shinezBidAdapter.js +1 -1
- package/dist/smaatoBidAdapter.js +1 -1
- package/dist/smartadserverBidAdapter.js +1 -1
- package/dist/smartxBidAdapter.js +1 -1
- package/dist/smilewantedBidAdapter.js +1 -1
- package/dist/sonobiBidAdapter.js +1 -1
- package/dist/sovrnAnalyticsAdapter.js +1 -1
- package/dist/sovrnBidAdapter.js +1 -1
- package/dist/sspBCBidAdapter.js +1 -1
- package/dist/stvBidAdapter.js +1 -1
- package/dist/sublimeBidAdapter.js +1 -1
- package/dist/synacormediaBidAdapter.js +1 -1
- package/dist/targetVideoBidAdapter.js +1 -1
- package/dist/teadsBidAdapter.js +1 -1
- package/dist/trionBidAdapter.js +1 -1
- package/dist/tripleliftBidAdapter.js +1 -1
- package/dist/ttdBidAdapter.js +1 -1
- package/dist/ucfunnelAnalyticsAdapter.js +1 -1
- package/dist/uid2IdSystem.js +1 -1
- package/dist/underdogmediaBidAdapter.js +1 -1
- package/dist/undertoneBidAdapter.js +1 -1
- package/dist/userId.js +1 -1
- package/dist/vdoaiBidAdapter.js +1 -1
- package/dist/vidazooBidAdapter.js +1 -1
- package/dist/videobyteBidAdapter.js +1 -1
- package/dist/vidoomyBidAdapter.js +1 -1
- package/dist/visxBidAdapter.js +1 -1
- package/dist/vuukleBidAdapter.js +1 -1
- package/dist/widespaceBidAdapter.js +1 -1
- package/dist/winrBidAdapter.js +1 -1
- package/dist/wipesBidAdapter.js +1 -1
- package/dist/yahoosspBidAdapter.js +1 -1
- package/dist/yieldmoBidAdapter.js +1 -1
- package/dist/yieldoneAnalyticsAdapter.js +1 -1
- package/dist/yieldoneBidAdapter.js +1 -1
- package/modules/ablidaBidAdapter.js +4 -5
- package/modules/admaticBidAdapter.js +32 -5
- package/modules/adrinoBidAdapter.js +11 -4
- package/modules/axonixBidAdapter.js +6 -6
- package/modules/connectIdSystem.js +5 -2
- package/modules/criteoBidAdapter.js +3 -5
- package/modules/criteoIdSystem.js +27 -14
- package/modules/dspxBidAdapter.js +2 -3
- package/modules/emtvBidAdapter.js +211 -0
- package/modules/emtvBidAdapter.md +79 -0
- package/modules/freewheel-sspBidAdapter.js +32 -7
- package/modules/greenbidsRtdProvider.js +110 -0
- package/modules/greenbidsRtdProvider.md +65 -0
- package/modules/impactifyBidAdapter.js +0 -1
- package/modules/iqmBidAdapter.js +1 -2
- package/modules/missenaBidAdapter.js +1 -1
- package/modules/nextMillenniumBidAdapter.js +2 -0
- package/modules/orbitsoftBidAdapter.js +1 -2
- package/modules/radsBidAdapter.js +3 -4
- package/modules/relevantdigitalBidAdapter.js +198 -0
- package/modules/relevantdigitalBidAdapter.md +117 -0
- package/modules/rtbhouseBidAdapter.js +9 -12
- package/modules/sovrnBidAdapter.js +4 -0
- package/modules/stvBidAdapter.js +4 -5
- package/modules/tripleliftBidAdapter.js +14 -3
- package/modules/ttdBidAdapter.js +73 -71
- package/modules/underdogmediaBidAdapter.js +9 -12
- package/modules/userId/index.js +1 -1
- package/modules/vdoaiBidAdapter.js +2 -3
- package/modules/vidoomyBidAdapter.js +19 -6
- package/modules/vidoomyBidAdapter.md +12 -2
- package/modules/wipesBidAdapter.js +2 -3
- package/modules/yieldmoBidAdapter.js +2 -2
- package/modules/yieldoneBidAdapter.js +3 -4
- package/package.json +1 -1
- package/test/spec/modules/adlooxAdServerVideo_spec.js +18 -35
- package/test/spec/modules/admaticBidAdapter_spec.js +164 -11
- package/test/spec/modules/adrinoBidAdapter_spec.js +50 -2
- package/test/spec/modules/connectIdSystem_spec.js +4 -4
- package/test/spec/modules/criteoBidAdapter_spec.js +56 -0
- package/test/spec/modules/criteoIdSystem_spec.js +99 -9
- package/test/spec/modules/emtvBidAdapter_spec.js +400 -0
- package/test/spec/modules/freewheel-sspBidAdapter_spec.js +31 -2
- package/test/spec/modules/greenbidsRtdProvider_spec.js +210 -0
- package/test/spec/modules/relevantdigitalBidAdapter_spec.js +295 -0
- package/test/spec/modules/rtbhouseBidAdapter_spec.js +24 -2
- package/test/spec/modules/sovrnBidAdapter_spec.js +65 -0
- package/test/spec/modules/tripleliftBidAdapter_spec.js +53 -8
- package/test/spec/modules/ttdBidAdapter_spec.js +20 -0
- package/test/spec/modules/vidoomyBidAdapter_spec.js +49 -0
- package/test/spec/modules/yieldmoBidAdapter_spec.js +2 -2
- package/test/spec/ortbConverter/userId_spec.js +12 -0
- package/test/spec/modules/realvuAnalyticsAdapter_spec.js +0 -189
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import {registerBidder} from '../src/adapters/bidderFactory.js';
|
|
2
|
+
import {ortbConverter} from '../libraries/ortbConverter/converter.js'
|
|
3
|
+
import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js';
|
|
4
|
+
import {config} from '../src/config.js';
|
|
5
|
+
import {pbsExtensions} from '../libraries/pbsExtensions/pbsExtensions.js'
|
|
6
|
+
import {deepSetValue, isEmpty, deepClone, shuffle, triggerPixel, deepAccess} from '../src/utils.js';
|
|
7
|
+
|
|
8
|
+
const BIDDER_CODE = 'relevantdigital';
|
|
9
|
+
|
|
10
|
+
/** Global settings per bidder-code for this adapter (which might be > 1 if using aliasing) */
|
|
11
|
+
let configByBidder = {};
|
|
12
|
+
|
|
13
|
+
/** Used by the tests */
|
|
14
|
+
export const resetBidderConfigs = () => {
|
|
15
|
+
configByBidder = {};
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/** Settings ber bidder-code. checkParams === true means that it can optionally be set in bid-params */
|
|
19
|
+
const FIELDS = [
|
|
20
|
+
{ name: 'pbsHost', checkParams: true, required: true },
|
|
21
|
+
{ name: 'accountId', checkParams: true, required: true },
|
|
22
|
+
{ name: 'pbsBufferMs', checkParams: false, required: false, default: 250 },
|
|
23
|
+
{ name: 'useSourceBidderCode', checkParams: false, required: false, default: false },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const SYNC_HTML = 'https://cdn.relevant-digital.com/resources/load-cookie.html';
|
|
27
|
+
const MAX_SYNC_COUNT = 10; // Max server-side bidder to sync at once via the iframe
|
|
28
|
+
|
|
29
|
+
/** Get settings for a bidder-code via config and, if needed, bid parameters */
|
|
30
|
+
const getBidderConfig = (bids) => {
|
|
31
|
+
const { bidder } = bids[0];
|
|
32
|
+
const cfg = configByBidder[bidder] || {
|
|
33
|
+
...Object.fromEntries(FIELDS.filter((f) => 'default' in f).map((f) => [f.name, f.default])),
|
|
34
|
+
syncedBidders: {}, // To keep track of S2S-bidders we already (started to) synced
|
|
35
|
+
};
|
|
36
|
+
if (cfg.complete) {
|
|
37
|
+
return cfg; // Most common case, we already have the settings we need (and we won't re-read them)
|
|
38
|
+
}
|
|
39
|
+
configByBidder[bidder] = cfg;
|
|
40
|
+
const bidderConfiguration = config.getConfig(bidder) || {};
|
|
41
|
+
|
|
42
|
+
// Read settings set by setConfig({ [bidder]: { ... }}) and if not available - from bid params
|
|
43
|
+
FIELDS.forEach(({ name, checkParams }) => {
|
|
44
|
+
cfg[name] = bidderConfiguration[name] || cfg[name];
|
|
45
|
+
if (!cfg[name] && checkParams) {
|
|
46
|
+
bids.forEach((bid) => {
|
|
47
|
+
cfg[name] = cfg[name] || bid.params?.[name];
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
cfg.complete = FIELDS.every((field) => !field.required || cfg[field.name]);
|
|
52
|
+
if (cfg.complete) {
|
|
53
|
+
cfg.pbsHost = cfg.pbsHost.trim().replace('http://', 'https://');
|
|
54
|
+
if (cfg.pbsHost.indexOf('https://') < 0) {
|
|
55
|
+
cfg.pbsHost = `https://${cfg.pbsHost}`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return cfg;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const converter = ortbConverter({
|
|
62
|
+
context: {
|
|
63
|
+
netRevenue: true,
|
|
64
|
+
ttl: 300
|
|
65
|
+
},
|
|
66
|
+
processors: pbsExtensions,
|
|
67
|
+
imp(buildImp, bidRequest, context) {
|
|
68
|
+
// Set stored request id from placementId
|
|
69
|
+
const imp = buildImp(bidRequest, context);
|
|
70
|
+
const { placementId } = bidRequest.params;
|
|
71
|
+
deepSetValue(imp, 'ext.prebid.storedrequest.id', placementId);
|
|
72
|
+
delete imp.ext.prebid.bidder;
|
|
73
|
+
return imp;
|
|
74
|
+
},
|
|
75
|
+
overrides: {
|
|
76
|
+
bidResponse: {
|
|
77
|
+
bidderCode(orig, bidResponse, bid, { bidRequest }) {
|
|
78
|
+
const { bidder, params = {} } = bidRequest || {};
|
|
79
|
+
let useSourceBidderCode = configByBidder[bidder]?.useSourceBidderCode;
|
|
80
|
+
if ('useSourceBidderCode' in params) {
|
|
81
|
+
useSourceBidderCode = params.useSourceBidderCode;
|
|
82
|
+
}
|
|
83
|
+
// Only use the orignal function when useSourceBidderCode is true, else our own bidder code will be used
|
|
84
|
+
if (useSourceBidderCode) {
|
|
85
|
+
orig.apply(this, [...arguments].slice(1));
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export const spec = {
|
|
93
|
+
code: BIDDER_CODE,
|
|
94
|
+
gvlid: 1100,
|
|
95
|
+
supportedMediaTypes: [BANNER, VIDEO, NATIVE],
|
|
96
|
+
|
|
97
|
+
/** We need both params.placementId + a complete configuration (pbsHost + accountId) to continue **/
|
|
98
|
+
isBidRequestValid: (bid) => bid.params?.placementId && getBidderConfig([bid]).complete,
|
|
99
|
+
|
|
100
|
+
/** Trigger impression-pixel */
|
|
101
|
+
onBidWon: ({pbsWurl}) => pbsWurl && triggerPixel(pbsWurl),
|
|
102
|
+
|
|
103
|
+
/** Build BidRequest for PBS */
|
|
104
|
+
buildRequests(bidRequests, bidderRequest) {
|
|
105
|
+
const { bidder } = bidRequests[0];
|
|
106
|
+
const cfg = getBidderConfig(bidRequests);
|
|
107
|
+
const data = converter.toORTB({bidRequests, bidderRequest});
|
|
108
|
+
|
|
109
|
+
/** Set tmax, in general this will be timeout - pbsBufferMs */
|
|
110
|
+
const pbjsTimeout = bidderRequest.timeout || 1000;
|
|
111
|
+
data.tmax = Math.min(Math.max(pbjsTimeout - cfg.pbsBufferMs, cfg.pbsBufferMs), pbjsTimeout);
|
|
112
|
+
|
|
113
|
+
delete data.ext?.prebid?.aliases; // We don't need/want to send aliases to PBS
|
|
114
|
+
deepSetValue(data, 'ext.relevant', {
|
|
115
|
+
...data.ext?.relevant,
|
|
116
|
+
adapter: true, // For internal analytics
|
|
117
|
+
});
|
|
118
|
+
deepSetValue(data, 'ext.prebid.storedrequest.id', cfg.accountId);
|
|
119
|
+
data.ext.prebid.passthrough = {
|
|
120
|
+
...data.ext.prebid.passthrough,
|
|
121
|
+
relevant: { bidder }, // to find config for the right bidder-code in interpretResponse / getUserSyncs
|
|
122
|
+
};
|
|
123
|
+
return [{
|
|
124
|
+
method: 'POST',
|
|
125
|
+
url: `${cfg.pbsHost}/openrtb2/auction`,
|
|
126
|
+
data
|
|
127
|
+
}];
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
/** Read BidResponse from PBS and make necessary adjustments to not make it appear to come from unknown bidders */
|
|
131
|
+
interpretResponse(response, request) {
|
|
132
|
+
const resp = deepClone(response.body);
|
|
133
|
+
const { bidder } = request.data.ext.prebid.passthrough.relevant;
|
|
134
|
+
|
|
135
|
+
// Modify response times / errors for actual PBS bidders into a single value
|
|
136
|
+
const MODIFIERS = {
|
|
137
|
+
responsetimemillis: (values) => Math.max(...values),
|
|
138
|
+
errors: (values) => [].concat(...values),
|
|
139
|
+
};
|
|
140
|
+
Object.entries(MODIFIERS).forEach(([field, combineFn]) => {
|
|
141
|
+
const obj = resp.ext?.[field];
|
|
142
|
+
if (!isEmpty(obj)) {
|
|
143
|
+
resp.ext[field] = {[bidder]: combineFn(Object.values(obj))};
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const bids = converter.fromORTB({response: resp, request: request.data}).bids;
|
|
148
|
+
return bids;
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
/** Do syncing, but avoid running the sync > 1 time for S2S bidders */
|
|
152
|
+
getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) {
|
|
153
|
+
if (!syncOptions.iframeEnabled && !syncOptions.pixelEnabled) {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
const syncs = [];
|
|
157
|
+
serverResponses.forEach(({ body }) => {
|
|
158
|
+
const { pbsHost, syncedBidders } = configByBidder[body.ext.prebid.passthrough.relevant.bidder] || {};
|
|
159
|
+
if (!pbsHost) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const { gdprApplies, consentString } = gdprConsent || {};
|
|
163
|
+
let bidders = Object.keys(body.ext?.responsetimemillis || {});
|
|
164
|
+
bidders = bidders.reduce((acc, curr) => {
|
|
165
|
+
if (!syncedBidders[curr]) {
|
|
166
|
+
acc.push(curr);
|
|
167
|
+
syncedBidders[curr] = true;
|
|
168
|
+
}
|
|
169
|
+
return acc;
|
|
170
|
+
}, []);
|
|
171
|
+
bidders = shuffle(bidders).slice(0, MAX_SYNC_COUNT); // Shuffle to not always leave out the same bidders
|
|
172
|
+
if (!bidders.length) {
|
|
173
|
+
return; // All bidders already synced
|
|
174
|
+
}
|
|
175
|
+
if (syncOptions.iframeEnabled) {
|
|
176
|
+
const params = {
|
|
177
|
+
endpoint: `${pbsHost}/cookie_sync`,
|
|
178
|
+
max_sync_count: bidders.length,
|
|
179
|
+
gdpr: gdprApplies ? 1 : 0,
|
|
180
|
+
gdpr_consent: consentString,
|
|
181
|
+
us_privacy: uspConsent,
|
|
182
|
+
bidders: bidders.join(','),
|
|
183
|
+
};
|
|
184
|
+
const qs = Object.entries(params)
|
|
185
|
+
.filter(([k, v]) => ![null, undefined, ''].includes(v))
|
|
186
|
+
.map(([k, v]) => `${k}=${encodeURIComponent(v.toString())}`)
|
|
187
|
+
.join('&');
|
|
188
|
+
syncs.push({ type: 'iframe', url: `${SYNC_HTML}?${qs}` });
|
|
189
|
+
} else { // Else, try to pixel-sync (for future-compatibility)
|
|
190
|
+
const pixels = deepAccess(body, `ext.relevant.sync`, []).filter(({ type }) => type === 'redirect');
|
|
191
|
+
syncs.push(...pixels.map(({ url }) => ({ type: 'image', url })));
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
return syncs;
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
registerBidder(spec);
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Overview
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
Module Name: Relevant Digital Bid Adapter
|
|
5
|
+
Module Type: Bidder Adapter
|
|
6
|
+
Maintainer: support@relevant-digital.com
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
# Description
|
|
10
|
+
|
|
11
|
+
This adapter is used for integration with providers using the **[Relevant Yield](https://www.relevant-digital.com/relevantyield)** platform. The provider will supply the necessary **pbsHost** and **accountId** settings along with the **placementId** bid parameters per ad unit.
|
|
12
|
+
|
|
13
|
+
# Example setup using pbjs.setConfig()
|
|
14
|
+
This is the recommended method to set the global configuration parameters.
|
|
15
|
+
```javascript
|
|
16
|
+
pbjs.setConfig({
|
|
17
|
+
relevantdigital: {
|
|
18
|
+
pbsHost: 'pbs-example.relevant-digital.com',
|
|
19
|
+
accountId: '6204e5fa70e3ad10821b84ff',
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
var adUnits = [
|
|
24
|
+
{
|
|
25
|
+
code: 'test-div',
|
|
26
|
+
mediaTypes: { banner: { sizes: [[300, 250], [320, 320]] }},
|
|
27
|
+
bids: [
|
|
28
|
+
{
|
|
29
|
+
bidder: 'relevantdigital',
|
|
30
|
+
params: {
|
|
31
|
+
placementId: '6204e83a077c5825441b8508_620f9e8e4fe67c1f87cd30ed',
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
}
|
|
36
|
+
];
|
|
37
|
+
```
|
|
38
|
+
# Example setup using only bid params
|
|
39
|
+
This method to set the global configuration parameters (like **pbsHost**) in **params** could simplify integration of a provider for some publishers. Setting different global config-parameters on different bids is not supported in general*, as the first settings found will be used and any subsequent global settings will be ignored.
|
|
40
|
+
|
|
41
|
+
* _The exception is `useSourceBidderCode` which can be overriden individually per ad unit._
|
|
42
|
+
```javascript
|
|
43
|
+
var adUnits = [
|
|
44
|
+
{
|
|
45
|
+
code: 'test-div',
|
|
46
|
+
mediaTypes: { banner: { sizes: [[300, 250], [320, 320]] }},
|
|
47
|
+
bids: [
|
|
48
|
+
{
|
|
49
|
+
bidder: 'relevantdigital',
|
|
50
|
+
params: {
|
|
51
|
+
placementId: '6204e83a077c5825441b8508_620f9e8e4fe67c1f87cd30ed',
|
|
52
|
+
pbsHost: 'pbs-example.relevant-digital.com',
|
|
53
|
+
accountId: '6204e5fa70e3ad10821b84ff',
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
}
|
|
58
|
+
];
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
# Example setup with multiple providers
|
|
62
|
+
**Notice:** Placements below are _not_ live test placements
|
|
63
|
+
```javascript
|
|
64
|
+
|
|
65
|
+
pbjs.aliasBidder('relevantdigital', 'providerA');
|
|
66
|
+
pbjs.aliasBidder('relevantdigital', 'providerB');
|
|
67
|
+
|
|
68
|
+
pbjs.setConfig({
|
|
69
|
+
providerA: {
|
|
70
|
+
pbsHost: 'pbs-example-a.relevant-digital.com',
|
|
71
|
+
accountId: '620533ae7f5bbe1691bbb815',
|
|
72
|
+
},
|
|
73
|
+
providerB: {
|
|
74
|
+
pbsHost: 'pbs-example-b.relevant-digital.com',
|
|
75
|
+
accountId: '990533ae7f5bbe1691bbb815',
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
var adUnits = [
|
|
80
|
+
{
|
|
81
|
+
code: 'test-div',
|
|
82
|
+
mediaTypes: { banner: { sizes: [[300, 250], [320, 320]] }},
|
|
83
|
+
bids: [
|
|
84
|
+
{
|
|
85
|
+
bidder: 'providerA',
|
|
86
|
+
params: {
|
|
87
|
+
placementId: '610525862d7517bfd4bbb81e_620523b7d1dbed6b0fbbb817',
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
bidder: 'providerB',
|
|
92
|
+
params: {
|
|
93
|
+
placementId: '990525862d7517bfd4bbb81e_770523b7d1dbed6b0fbbb817',
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
}
|
|
98
|
+
];
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
# Bid Parameters
|
|
102
|
+
|
|
103
|
+
| Name | Scope | Description | Example | Type |
|
|
104
|
+
|---------------|----------|---------------------------------------------------------|----------------------------|--------------|
|
|
105
|
+
| `placementId` | required | The placement id. | `'6204e83a077c5825441b8508_620f9e8e4fe67c1f87cd30ed'` | `String` |
|
|
106
|
+
| `pbsHost` | required if not set in config | Host name of the server. | `'pbs-example.relevant-digital.com'` | `String` |
|
|
107
|
+
| `accountId` | required if not set in config | The account id. | `'6204e5fa70e3ad10821b84ff'` | `String` |
|
|
108
|
+
| `useSourceBidderCode` | optional | Set to `true` in order to use the bidder code of the actual server-side bidder in bid responses. You **MUST** also use `allowAlternateBidderCodes: true` in `bidderSettings` if you enabled this - as otherwise the bids will be rejected.| `true` | `Boolean` |
|
|
109
|
+
|
|
110
|
+
# Config Parameters
|
|
111
|
+
|
|
112
|
+
| Name | Scope | Description | Example | Type |
|
|
113
|
+
|---------------|----------|---------------------------------------------------------|----------------------------|--------------|
|
|
114
|
+
| `pbsHost` | required if not set in bid parameters | Host name of the server. | `'pbs-example.relevant-digital.com'` | `String` |
|
|
115
|
+
| `accountId` | required if not set in bid parameters | The account id. | `'6204e5fa70e3ad10821b84ff'` | `String` |
|
|
116
|
+
| `pbsBufferMs` | optional | How much less in *milliseconds* the server's internal timeout should be compared to the normal Prebid timeout. Default is *250*. To be increased in cases of frequent timeouts. | `250` | `Integer` |
|
|
117
|
+
| `useSourceBidderCode` | optional | Set to `true` in order to use the bidder code of the actual server-side bidder in bid responses. You **MUST** also use `allowAlternateBidderCodes: true` in `bidderSettings` if you enabled this - as otherwise the bids will be rejected.| `true` | `Boolean` |
|
|
@@ -85,15 +85,12 @@ export const spec = {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
const ortb2Params = bidderRequest?.ortb2 || {};
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
if (ortb2Params.device) {
|
|
95
|
-
mergeDeep(request, { device: ortb2Params.device });
|
|
96
|
-
}
|
|
88
|
+
['site', 'user', 'device', 'bcat', 'badv'].forEach(entry => {
|
|
89
|
+
const ortb2Param = ortb2Params[entry];
|
|
90
|
+
if (ortb2Param) {
|
|
91
|
+
mergeDeep(request, { [entry]: ortb2Param });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
97
94
|
|
|
98
95
|
let computedEndpointUrl = ENDPOINT_URL;
|
|
99
96
|
|
|
@@ -479,7 +476,7 @@ function interpretNativeBid(serverBid) {
|
|
|
479
476
|
function interpretNativeAd(adm) {
|
|
480
477
|
const native = JSON.parse(adm).native;
|
|
481
478
|
const result = {
|
|
482
|
-
clickUrl:
|
|
479
|
+
clickUrl: encodeURI(native.link.url),
|
|
483
480
|
impressionTrackers: native.imptrackers
|
|
484
481
|
};
|
|
485
482
|
native.assets.forEach(asset => {
|
|
@@ -489,14 +486,14 @@ function interpretNativeAd(adm) {
|
|
|
489
486
|
break;
|
|
490
487
|
case OPENRTB.NATIVE.ASSET_ID.IMAGE:
|
|
491
488
|
result.image = {
|
|
492
|
-
url:
|
|
489
|
+
url: encodeURI(asset.img.url),
|
|
493
490
|
width: asset.img.w,
|
|
494
491
|
height: asset.img.h
|
|
495
492
|
};
|
|
496
493
|
break;
|
|
497
494
|
case OPENRTB.NATIVE.ASSET_ID.ICON:
|
|
498
495
|
result.icon = {
|
|
499
|
-
url:
|
|
496
|
+
url: encodeURI(asset.img.url),
|
|
500
497
|
width: asset.img.w,
|
|
501
498
|
height: asset.img.h
|
|
502
499
|
};
|
|
@@ -173,6 +173,10 @@ export const spec = {
|
|
|
173
173
|
if (bidderRequest.uspConsent) {
|
|
174
174
|
deepSetValue(sovrnBidReq, 'regs.ext.us_privacy', bidderRequest.uspConsent);
|
|
175
175
|
}
|
|
176
|
+
if (bidderRequest.gppConsent) {
|
|
177
|
+
deepSetValue(sovrnBidReq, 'regs.gpp', bidderRequest.gppConsent.gppString);
|
|
178
|
+
deepSetValue(sovrnBidReq, 'regs.gpp_sid', bidderRequest.gppConsent.applicableSections);
|
|
179
|
+
}
|
|
176
180
|
|
|
177
181
|
if (eids) {
|
|
178
182
|
deepSetValue(sovrnBidReq, 'user.ext.eids', eids)
|
package/modules/stvBidAdapter.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { BANNER, VIDEO } from '../src/mediaTypes.js';
|
|
1
|
+
import {deepAccess} from '../src/utils.js';
|
|
2
|
+
import {registerBidder} from '../src/adapters/bidderFactory.js';
|
|
3
|
+
import {BANNER, VIDEO} from '../src/mediaTypes.js';
|
|
5
4
|
import {includes} from '../src/polyfill.js';
|
|
6
5
|
|
|
7
6
|
const BIDDER_CODE = 'stv';
|
|
@@ -128,7 +127,7 @@ export const spec = {
|
|
|
128
127
|
dealId: dealId,
|
|
129
128
|
currency: currency,
|
|
130
129
|
netRevenue: netRevenue,
|
|
131
|
-
ttl:
|
|
130
|
+
ttl: 60,
|
|
132
131
|
meta: {
|
|
133
132
|
advertiserDomains: response.adomain || []
|
|
134
133
|
}
|
|
@@ -9,7 +9,7 @@ const BIDDER_CODE = 'triplelift';
|
|
|
9
9
|
const STR_ENDPOINT = 'https://tlx.3lift.com/header/auction?';
|
|
10
10
|
const BANNER_TIME_TO_LIVE = 300;
|
|
11
11
|
const VIDEO_TIME_TO_LIVE = 3600;
|
|
12
|
-
let gdprApplies =
|
|
12
|
+
let gdprApplies = null;
|
|
13
13
|
let consentString = null;
|
|
14
14
|
export const storage = getStorageManager({bidderCode: BIDDER_CODE});
|
|
15
15
|
|
|
@@ -40,8 +40,12 @@ export const tripleliftAdapterSpec = {
|
|
|
40
40
|
if (bidderRequest && bidderRequest.gdprConsent) {
|
|
41
41
|
if (typeof bidderRequest.gdprConsent.gdprApplies !== 'undefined') {
|
|
42
42
|
gdprApplies = bidderRequest.gdprConsent.gdprApplies;
|
|
43
|
-
|
|
43
|
+
} else {
|
|
44
|
+
gdprApplies = true;
|
|
44
45
|
}
|
|
46
|
+
|
|
47
|
+
tlCall = tryAppendQueryString(tlCall, 'gdpr', gdprApplies.toString());
|
|
48
|
+
|
|
45
49
|
if (typeof bidderRequest.gdprConsent.consentString !== 'undefined') {
|
|
46
50
|
consentString = bidderRequest.gdprConsent.consentString;
|
|
47
51
|
tlCall = tryAppendQueryString(tlCall, 'cmp_cs', consentString);
|
|
@@ -87,7 +91,7 @@ export const tripleliftAdapterSpec = {
|
|
|
87
91
|
syncEndpoint = tryAppendQueryString(syncEndpoint, 'src', 'prebid');
|
|
88
92
|
}
|
|
89
93
|
|
|
90
|
-
if (consentString !== null) {
|
|
94
|
+
if (consentString !== null || gdprApplies) {
|
|
91
95
|
syncEndpoint = tryAppendQueryString(syncEndpoint, 'gdpr', gdprApplies);
|
|
92
96
|
syncEndpoint = tryAppendQueryString(syncEndpoint, 'cmp_cs', consentString);
|
|
93
97
|
}
|
|
@@ -130,8 +134,15 @@ function _buildPostBody(bidRequests, bidderRequest) {
|
|
|
130
134
|
}
|
|
131
135
|
|
|
132
136
|
if (!isEmpty(bidRequest.ortb2Imp)) {
|
|
137
|
+
// legacy method for extracting ortb2Imp.ext
|
|
133
138
|
imp.fpd = _getAdUnitFpd(bidRequest.ortb2Imp);
|
|
139
|
+
|
|
140
|
+
// preferred method for extracting ortb2Imp.ext
|
|
141
|
+
if (!isEmpty(bidRequest.ortb2Imp.ext)) {
|
|
142
|
+
imp.ext = { ...bidRequest.ortb2Imp.ext };
|
|
143
|
+
}
|
|
134
144
|
}
|
|
145
|
+
|
|
135
146
|
return imp;
|
|
136
147
|
});
|
|
137
148
|
|
package/modules/ttdBidAdapter.js
CHANGED
|
@@ -185,7 +185,7 @@ function getImpression(bidRequest) {
|
|
|
185
185
|
if (mediaTypesBanner) {
|
|
186
186
|
mediaTypes[BANNER] = banner(bidRequest);
|
|
187
187
|
}
|
|
188
|
-
if (mediaTypesVideo) {
|
|
188
|
+
if (FEATURES.VIDEO && mediaTypesVideo) {
|
|
189
189
|
mediaTypes[VIDEO] = video(bidRequest);
|
|
190
190
|
}
|
|
191
191
|
|
|
@@ -248,79 +248,81 @@ function banner(bid) {
|
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
function video(bid) {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
minduration
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
251
|
+
if (FEATURES.VIDEO) {
|
|
252
|
+
let minduration = utils.deepAccess(bid, 'mediaTypes.video.minduration');
|
|
253
|
+
const maxduration = utils.deepAccess(bid, 'mediaTypes.video.maxduration');
|
|
254
|
+
const playerSize = utils.deepAccess(bid, 'mediaTypes.video.playerSize');
|
|
255
|
+
const api = utils.deepAccess(bid, 'mediaTypes.video.api');
|
|
256
|
+
const mimes = utils.deepAccess(bid, 'mediaTypes.video.mimes');
|
|
257
|
+
const placement = utils.deepAccess(bid, 'mediaTypes.video.placement');
|
|
258
|
+
const plcmt = utils.deepAccess(bid, 'mediaTypes.video.plcmt');
|
|
259
|
+
const protocols = utils.deepAccess(bid, 'mediaTypes.video.protocols');
|
|
260
|
+
const playbackmethod = utils.deepAccess(bid, 'mediaTypes.video.playbackmethod');
|
|
261
|
+
const pos = utils.deepAccess(bid, 'mediaTypes.video.pos');
|
|
262
|
+
const startdelay = utils.deepAccess(bid, 'mediaTypes.video.startdelay');
|
|
263
|
+
const skip = utils.deepAccess(bid, 'mediaTypes.video.skip');
|
|
264
|
+
const skipmin = utils.deepAccess(bid, 'mediaTypes.video.skipmin');
|
|
265
|
+
const skipafter = utils.deepAccess(bid, 'mediaTypes.video.skipafter');
|
|
266
|
+
const minbitrate = utils.deepAccess(bid, 'mediaTypes.video.minbitrate');
|
|
267
|
+
const maxbitrate = utils.deepAccess(bid, 'mediaTypes.video.maxbitrate');
|
|
268
|
+
|
|
269
|
+
if (!minduration || !utils.isInteger(minduration)) {
|
|
270
|
+
minduration = 0;
|
|
271
|
+
}
|
|
272
|
+
let video = {
|
|
273
|
+
minduration: minduration,
|
|
274
|
+
maxduration: maxduration,
|
|
275
|
+
api: api,
|
|
276
|
+
mimes: mimes,
|
|
277
|
+
placement: placement,
|
|
278
|
+
protocols: protocols
|
|
279
|
+
};
|
|
279
280
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
281
|
+
if (typeof playerSize !== 'undefined') {
|
|
282
|
+
if (utils.isArray(playerSize[0])) {
|
|
283
|
+
video.w = parseInt(playerSize[0][0]);
|
|
284
|
+
video.h = parseInt(playerSize[0][1]);
|
|
285
|
+
} else if (utils.isNumber(playerSize[0])) {
|
|
286
|
+
video.w = parseInt(playerSize[0]);
|
|
287
|
+
video.h = parseInt(playerSize[1]);
|
|
288
|
+
}
|
|
287
289
|
}
|
|
288
|
-
}
|
|
289
290
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
291
|
+
if (playbackmethod) {
|
|
292
|
+
video.playbackmethod = playbackmethod;
|
|
293
|
+
}
|
|
294
|
+
if (plcmt) {
|
|
295
|
+
video.plcmt = plcmt;
|
|
296
|
+
}
|
|
297
|
+
if (pos) {
|
|
298
|
+
video.pos = pos;
|
|
299
|
+
}
|
|
300
|
+
if (startdelay && utils.isInteger(startdelay)) {
|
|
301
|
+
video.startdelay = startdelay;
|
|
302
|
+
}
|
|
303
|
+
if (skip && (skip === 0 || skip === 1)) {
|
|
304
|
+
video.skip = skip;
|
|
305
|
+
}
|
|
306
|
+
if (skipmin && utils.isInteger(skipmin)) {
|
|
307
|
+
video.skipmin = skipmin;
|
|
308
|
+
}
|
|
309
|
+
if (skipafter && utils.isInteger(skipafter)) {
|
|
310
|
+
video.skipafter = skipafter;
|
|
311
|
+
}
|
|
312
|
+
if (minbitrate && utils.isInteger(minbitrate)) {
|
|
313
|
+
video.minbitrate = minbitrate;
|
|
314
|
+
}
|
|
315
|
+
if (maxbitrate && utils.isInteger(maxbitrate)) {
|
|
316
|
+
video.maxbitrate = maxbitrate;
|
|
317
|
+
}
|
|
317
318
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
319
|
+
const battr = utils.deepAccess(bid, 'ortb2Imp.battr');
|
|
320
|
+
if (battr) {
|
|
321
|
+
video.battr = battr;
|
|
322
|
+
}
|
|
322
323
|
|
|
323
|
-
|
|
324
|
+
return video;
|
|
325
|
+
}
|
|
324
326
|
}
|
|
325
327
|
|
|
326
328
|
export const spec = {
|
|
@@ -379,7 +381,7 @@ export const spec = {
|
|
|
379
381
|
return false;
|
|
380
382
|
}
|
|
381
383
|
|
|
382
|
-
if (mediaTypesVideo) {
|
|
384
|
+
if (FEATURES.VIDEO && mediaTypesVideo) {
|
|
383
385
|
if (!mediaTypesVideo.maxduration || !utils.isInteger(mediaTypesVideo.maxduration)) {
|
|
384
386
|
utils.logWarn(BIDDER_CODE + ': mediaTypes.video.maxduration must be set to the maximum video ad duration in seconds');
|
|
385
387
|
return false;
|
|
@@ -506,7 +508,7 @@ export const spec = {
|
|
|
506
508
|
mediaType: BANNER
|
|
507
509
|
}
|
|
508
510
|
);
|
|
509
|
-
} else if (bid.ext.mediatype === MEDIA_TYPE.VIDEO) {
|
|
511
|
+
} else if (FEATURES.VIDEO && bid.ext.mediatype === MEDIA_TYPE.VIDEO) {
|
|
510
512
|
Object.assign(
|
|
511
513
|
bidResponse,
|
|
512
514
|
{
|
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
deepAccess,
|
|
3
3
|
flatten,
|
|
4
|
-
|
|
4
|
+
getWindowSelf,
|
|
5
|
+
getWindowTop,
|
|
5
6
|
isGptPubadsDefined,
|
|
6
7
|
isSlotMatchingAdUnitCode,
|
|
7
8
|
logInfo,
|
|
9
|
+
logMessage,
|
|
8
10
|
logWarn,
|
|
9
|
-
|
|
10
|
-
getWindowTop,
|
|
11
|
-
deepAccess
|
|
11
|
+
parseSizesInput
|
|
12
12
|
} from '../src/utils.js';
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import {
|
|
17
|
-
registerBidder
|
|
18
|
-
} from '../src/adapters/bidderFactory.js';
|
|
13
|
+
import {config} from '../src/config.js';
|
|
14
|
+
import {registerBidder} from '../src/adapters/bidderFactory.js';
|
|
15
|
+
|
|
19
16
|
const BIDDER_CODE = 'underdogmedia';
|
|
20
17
|
const UDM_ADAPTER_VERSION = '7.30V';
|
|
21
18
|
const UDM_VENDOR_ID = '159';
|
|
@@ -377,7 +374,7 @@ function makeNotification(bid, mid, bidParam) {
|
|
|
377
374
|
url += `;version=${UDM_ADAPTER_VERSION}`;
|
|
378
375
|
url += ';cb=' + Math.random();
|
|
379
376
|
url += ';qqq=' + (1 / bid.cpm);
|
|
380
|
-
url += ';hbt=' + config.getConfig('
|
|
377
|
+
url += ';hbt=' + config.getConfig('bidderTimeout');
|
|
381
378
|
url += ';style=adapter';
|
|
382
379
|
url += ';vis=' + encodeURIComponent(document.visibilityState);
|
|
383
380
|
|
package/modules/userId/index.js
CHANGED
|
@@ -1085,7 +1085,7 @@ module('userId', attachIdSystem);
|
|
|
1085
1085
|
|
|
1086
1086
|
export function setOrtbUserExtEids(ortbRequest, bidderRequest, context) {
|
|
1087
1087
|
const eids = deepAccess(context, 'bidRequests.0.userIdAsEids');
|
|
1088
|
-
if (eids) {
|
|
1088
|
+
if (eids && Object.keys(eids).length > 0) {
|
|
1089
1089
|
deepSetValue(ortbRequest, 'user.ext.eids', eids);
|
|
1090
1090
|
}
|
|
1091
1091
|
}
|