prebid.js 6.7.0 → 6.11.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/.eslintrc.js +8 -1
- package/integrationExamples/gpt/{haloRtdProvider_example.html → hadronRtdProvider_example.html} +9 -9
- package/integrationExamples/gpt/idImportLibrary_example.html +2 -2
- package/integrationExamples/gpt/userId_example.html +2 -2
- package/integrationExamples/gpt/weboramaRtdProvider_example.html +154 -115
- package/integrationExamples/gpt/x-domain/creative.html +63 -29
- package/modules/.submodules.json +3 -0
- package/modules/adagioBidAdapter.js +0 -8
- package/modules/adagioBidAdapter.md +1 -1
- package/modules/adkernelBidAdapter.js +2 -1
- package/modules/adnuntiusRtdProvider.js +96 -0
- package/modules/adnuntiusRtdProvider.md +41 -0
- package/modules/adotBidAdapter.js +516 -567
- package/modules/adotBidAdapter.md +6 -44
- package/modules/adpod.js +12 -14
- package/modules/adyoulikeBidAdapter.js +2 -0
- package/modules/appnexusBidAdapter.js +14 -2
- package/modules/asealBidAdapter.js +58 -0
- package/modules/asealBidAdapter.md +52 -0
- package/modules/brandmetricsRtdProvider.js +168 -0
- package/modules/brandmetricsRtdProvider.md +40 -0
- package/modules/conversantBidAdapter.js +7 -0
- package/modules/criteoBidAdapter.js +9 -0
- package/modules/currency.js +27 -5
- package/modules/displayioBidAdapter.js +157 -0
- package/modules/displayioBidAdapter.md +148 -0
- package/modules/dspxBidAdapter.js +69 -29
- package/modules/dspxBidAdapter.md +2 -1
- package/modules/e_volutionBidAdapter.js +158 -0
- package/modules/gridBidAdapter.js +15 -1
- package/modules/gumgumBidAdapter.js +52 -38
- package/modules/hadronIdSystem.js +96 -0
- package/modules/hadronIdSystem.md +35 -0
- package/modules/hadronRtdProvider.js +254 -0
- package/modules/hadronRtdProvider.md +126 -0
- package/modules/haloIdSystem.md +4 -35
- package/modules/haloRtdProvider.md +3 -126
- package/modules/imRtdProvider.js +10 -0
- package/modules/improvedigitalBidAdapter.js +5 -0
- package/modules/interactiveOffersBidAdapter.js +9 -6
- package/modules/iqzoneBidAdapter.js +10 -3
- package/modules/iqzoneBidAdapter.md +16 -0
- package/modules/ixBidAdapter.js +2 -6
- package/modules/kubientBidAdapter.js +50 -19
- package/modules/lunamediahbBidAdapter.js +32 -4
- package/modules/malltvBidAdapter.js +7 -3
- package/modules/malltvBidAdapter.md +64 -51
- package/modules/mass.js +3 -5
- package/modules/mediakeysBidAdapter.js +0 -5
- package/modules/medianetAnalyticsAdapter.js +1 -1
- package/modules/mediasquareBidAdapter.js +9 -1
- package/modules/nextMillenniumBidAdapter.js +1 -0
- package/modules/oguryBidAdapter.js +7 -14
- package/modules/prebidServerBidAdapter/index.js +61 -39
- package/modules/priceFloors.js +20 -12
- package/modules/pubmaticBidAdapter.js +1 -1
- package/modules/richaudienceBidAdapter.js +8 -3
- package/modules/riseBidAdapter.js +17 -6
- package/modules/rtbhouseBidAdapter.js +2 -0
- package/modules/rubiconAnalyticsAdapter.js +5 -0
- package/modules/rubiconBidAdapter.js +2 -2
- package/modules/sizeMappingV2.js +1 -8
- package/modules/sortableAnalyticsAdapter.js +5 -4
- package/modules/sovrnBidAdapter.js +93 -18
- package/modules/sovrnBidAdapter.md +80 -2
- package/modules/sspBCBidAdapter.js +53 -20
- package/modules/telariaBidAdapter.js +22 -29
- package/modules/trustpidSystem.js +197 -0
- package/modules/trustpidSystem.md +45 -0
- package/modules/undertoneBidAdapter.js +17 -1
- package/modules/userId/eids.js +16 -1
- package/modules/userId/eids.md +10 -2
- package/modules/userId/userId.md +17 -2
- package/modules/vibrantmediaBidAdapter.js +220 -0
- package/modules/vibrantmediaBidAdapter.md +92 -0
- package/modules/vidoomyBidAdapter.js +8 -0
- package/modules/vidoomyBidAdapter.md +4 -2
- package/modules/weboramaRtdProvider.js +264 -34
- package/modules/weboramaRtdProvider.md +110 -40
- package/modules/yahoosspBidAdapter.js +3 -1
- package/modules/yieldoneBidAdapter.js +6 -0
- package/package.json +2 -1
- package/src/adRendering.js +38 -0
- package/src/adapterManager.js +24 -19
- package/src/adapters/bidderFactory.js +14 -11
- package/src/adloader.js +2 -1
- package/src/auction.js +138 -115
- package/src/auctionIndex.js +85 -0
- package/src/auctionManager.js +3 -0
- package/src/bidderSettings.js +69 -0
- package/src/bidfactory.js +18 -6
- package/src/native.js +29 -21
- package/src/prebid.js +3 -19
- package/src/secureCreatives.js +128 -45
- package/src/targeting.js +11 -2
- package/src/utils.js +14 -17
- package/src/video.js +10 -11
- package/src/videoCache.js +10 -9
- package/test/fixtures/fixtures.js +2 -1
- package/test/helpers/indexStub.js +28 -0
- package/test/helpers/syncPromise.js +71 -0
- package/test/spec/auctionmanager_spec.js +268 -89
- package/test/spec/config_spec.js +24 -1
- package/test/spec/modules/adagioBidAdapter_spec.js +0 -10
- package/test/spec/modules/adnuntiusRtdProvider_spec.js +145 -0
- package/test/spec/modules/adotBidAdapter_spec.js +294 -3124
- package/test/spec/modules/adpod_spec.js +91 -156
- package/test/spec/modules/adyoulikeBidAdapter_spec.js +4 -0
- package/test/spec/modules/appnexusBidAdapter_spec.js +27 -0
- package/test/spec/modules/asealBidAdapter_spec.js +144 -0
- package/test/spec/modules/brandmetricsRtdProvider_spec.js +191 -0
- package/test/spec/modules/conversantBidAdapter_spec.js +54 -2
- package/test/spec/modules/criteoBidAdapter_spec.js +21 -0
- package/test/spec/modules/currency_spec.js +36 -15
- package/test/spec/modules/displayioBidAdapter_spec.js +239 -0
- package/test/spec/modules/dspxBidAdapter_spec.js +20 -15
- package/test/spec/modules/e_volutionBidAdapter_spec.js +242 -0
- package/test/spec/modules/eids_spec.js +2 -2
- package/test/spec/modules/gridBidAdapter_spec.js +18 -0
- package/test/spec/modules/gumgumBidAdapter_spec.js +49 -3
- package/test/spec/modules/hadronIdSystem_spec.js +57 -0
- package/test/spec/modules/hadronRtdProvider_spec.js +762 -0
- package/test/spec/modules/imRtdProvider_spec.js +30 -1
- package/test/spec/modules/improvedigitalBidAdapter_spec.js +19 -0
- package/test/spec/modules/iqzoneBidAdapter_spec.js +1 -0
- package/test/spec/modules/ixBidAdapter_spec.js +1 -1
- package/test/spec/modules/kubientBidAdapter_spec.js +182 -84
- package/test/spec/modules/lunamediahbBidAdapter_spec.js +27 -1
- package/test/spec/modules/mass_spec.js +2 -14
- package/test/spec/modules/mediakeysBidAdapter_spec.js +9 -5
- package/test/spec/modules/mediasquareBidAdapter_spec.js +25 -1
- package/test/spec/modules/oguryBidAdapter_spec.js +63 -5
- package/test/spec/modules/prebidServerBidAdapter_spec.js +43 -6
- package/test/spec/modules/priceFloors_spec.js +83 -24
- package/test/spec/modules/pubmaticBidAdapter_spec.js +40 -0
- package/test/spec/modules/riseBidAdapter_spec.js +30 -4
- package/test/spec/modules/rubiconAnalyticsAdapter_spec.js +31 -1
- package/test/spec/modules/rubiconBidAdapter_spec.js +1 -1
- package/test/spec/modules/sortableAnalyticsAdapter_spec.js +2 -3
- package/test/spec/modules/sovrnBidAdapter_spec.js +413 -333
- package/test/spec/modules/sspBCBidAdapter_spec.js +7 -7
- package/test/spec/modules/telariaBidAdapter_spec.js +1 -3
- package/test/spec/modules/trustpidSystem_spec.js +232 -0
- package/test/spec/modules/undertoneBidAdapter_spec.js +55 -2
- package/test/spec/modules/userId_spec.js +39 -39
- package/test/spec/modules/vibrantmediaBidAdapter_spec.js +1237 -0
- package/test/spec/modules/vidoomyBidAdapter_spec.js +7 -1
- package/test/spec/modules/weboramaRtdProvider_spec.js +536 -20
- package/test/spec/modules/yahoosspBidAdapter_spec.js +10 -0
- package/test/spec/modules/yieldoneBidAdapter_spec.js +33 -0
- package/test/spec/native_spec.js +62 -40
- package/test/spec/unit/core/adapterManager_spec.js +22 -0
- package/test/spec/unit/core/auctionIndex_spec.js +129 -0
- package/test/spec/unit/core/bidderFactory_spec.js +65 -12
- package/test/spec/unit/core/bidderSettings_spec.js +123 -0
- package/test/spec/unit/core/targeting_spec.js +93 -0
- package/test/spec/unit/pbjs_api_spec.js +80 -42
- package/test/spec/unit/secureCreatives_spec.js +143 -24
- package/test/spec/videoCache_spec.js +18 -19
- package/test/spec/video_spec.js +51 -61
|
@@ -17,32 +17,48 @@ const TIME_TO_LIVE = 60
|
|
|
17
17
|
const DELAY_REQUEST_TIME = 1800000; // setting to 30 mins
|
|
18
18
|
|
|
19
19
|
let invalidRequestIds = {};
|
|
20
|
-
let browserParams = {};
|
|
21
20
|
let pageViewId = null;
|
|
22
21
|
|
|
23
22
|
// TODO: potential 0 values for browserParams sent to ad server
|
|
24
23
|
function _getBrowserParams(topWindowUrl) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
let
|
|
28
|
-
let
|
|
29
|
-
let
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
const paramRegex = paramName => new RegExp(`[?#&](${paramName}=(.*?))($|&)`, 'i');
|
|
25
|
+
|
|
26
|
+
let browserParams = {};
|
|
27
|
+
let topWindow;
|
|
28
|
+
let topScreen;
|
|
29
|
+
let topUrl;
|
|
30
|
+
let ggad;
|
|
31
|
+
let ggdeal;
|
|
32
|
+
let ns;
|
|
33
|
+
|
|
34
|
+
function getNetworkSpeed () {
|
|
35
|
+
const connection = window.navigator && (window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection);
|
|
36
|
+
const Mbps = connection && (connection.downlink || connection.bandwidth);
|
|
37
|
+
return Mbps ? Math.round(Mbps * 1024) : null;
|
|
34
38
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
|
|
40
|
+
function getOgURL () {
|
|
41
|
+
let ogURL = '';
|
|
42
|
+
const ogURLSelector = "meta[property='og:url']";
|
|
43
|
+
const head = document && document.getElementsByTagName('head')[0];
|
|
44
|
+
const ogURLElement = head.querySelector(ogURLSelector);
|
|
45
|
+
ogURL = ogURLElement ? ogURLElement.content : null;
|
|
46
|
+
return ogURL;
|
|
42
47
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
48
|
+
|
|
49
|
+
function stripGGParams (url) {
|
|
50
|
+
const params = [
|
|
51
|
+
'ggad',
|
|
52
|
+
'ggdeal'
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
return params.reduce((result, param) => {
|
|
56
|
+
const matches = url.match(paramRegex(param));
|
|
57
|
+
if (!matches) return result;
|
|
58
|
+
matches[1] && (result = result.replace(matches[1], ''));
|
|
59
|
+
matches[3] && (result = result.replace(matches[3], ''));
|
|
60
|
+
return result;
|
|
61
|
+
}, url);
|
|
46
62
|
}
|
|
47
63
|
|
|
48
64
|
try {
|
|
@@ -51,7 +67,7 @@ function _getBrowserParams(topWindowUrl) {
|
|
|
51
67
|
topUrl = topWindowUrl || '';
|
|
52
68
|
} catch (error) {
|
|
53
69
|
logError(error);
|
|
54
|
-
return browserParams
|
|
70
|
+
return browserParams;
|
|
55
71
|
}
|
|
56
72
|
|
|
57
73
|
browserParams = {
|
|
@@ -59,23 +75,25 @@ function _getBrowserParams(topWindowUrl) {
|
|
|
59
75
|
vh: topWindow.innerHeight,
|
|
60
76
|
sw: topScreen.width,
|
|
61
77
|
sh: topScreen.height,
|
|
62
|
-
pu: topUrl,
|
|
78
|
+
pu: stripGGParams(topUrl),
|
|
63
79
|
ce: storage.cookiesAreEnabled(),
|
|
64
80
|
dpr: topWindow.devicePixelRatio || 1,
|
|
65
81
|
jcsi: JSON.stringify(JCSI),
|
|
66
82
|
ogu: getOgURL()
|
|
67
|
-
}
|
|
83
|
+
};
|
|
68
84
|
|
|
69
|
-
ns = getNetworkSpeed()
|
|
85
|
+
ns = getNetworkSpeed();
|
|
70
86
|
if (ns) {
|
|
71
|
-
browserParams.ns = ns
|
|
87
|
+
browserParams.ns = ns;
|
|
72
88
|
}
|
|
73
89
|
|
|
74
|
-
ggad = (topUrl.match(
|
|
75
|
-
if (ggad)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
90
|
+
ggad = (topUrl.match(paramRegex('ggad')) || [0, 0, 0])[2];
|
|
91
|
+
if (ggad) browserParams[isNaN(ggad) ? 'eAdBuyId' : 'adBuyId'] = ggad;
|
|
92
|
+
|
|
93
|
+
ggdeal = (topUrl.match(paramRegex('ggdeal')) || [0, 0, 0])[2];
|
|
94
|
+
if (ggdeal) browserParams.ggdeal = ggdeal;
|
|
95
|
+
|
|
96
|
+
return browserParams;
|
|
79
97
|
}
|
|
80
98
|
|
|
81
99
|
function getWrapperCode(wrapper, data) {
|
|
@@ -291,9 +309,9 @@ function buildRequests(validBidRequests, bidderRequest) {
|
|
|
291
309
|
} = bidRequest;
|
|
292
310
|
const { currency, floor } = _getFloor(mediaTypes, params.bidfloor, bidRequest);
|
|
293
311
|
const eids = getEids(userId);
|
|
312
|
+
const gpid = deepAccess(ortb2Imp, 'ext.data.pbadslot') || deepAccess(ortb2Imp, 'ext.data.adserver.adslot');
|
|
294
313
|
let sizes = [1, 1];
|
|
295
314
|
let data = {};
|
|
296
|
-
let gpid = '';
|
|
297
315
|
|
|
298
316
|
const date = new Date();
|
|
299
317
|
const lt = date.getTime();
|
|
@@ -309,12 +327,8 @@ function buildRequests(validBidRequests, bidderRequest) {
|
|
|
309
327
|
// ADTS-134 Retrieve ID envelopes
|
|
310
328
|
for (const eid in eids) data[eid] = eids[eid];
|
|
311
329
|
|
|
312
|
-
// ADJS-1024 & ADSS-1297
|
|
313
|
-
|
|
314
|
-
gpid = deepAccess(ortb2Imp, 'ext.data.pbadslot')
|
|
315
|
-
} else if (deepAccess(ortb2Imp, 'ext.data.adserver.name')) {
|
|
316
|
-
gpid = ortb2Imp.ext.data.adserver.adslot
|
|
317
|
-
}
|
|
330
|
+
// ADJS-1024 & ADSS-1297 & ADTS-175
|
|
331
|
+
gpid && (data.gpid = gpid);
|
|
318
332
|
|
|
319
333
|
if (mediaTypes.banner) {
|
|
320
334
|
sizes = mediaTypes.banner.sizes;
|
|
@@ -384,7 +398,7 @@ function buildRequests(validBidRequests, bidderRequest) {
|
|
|
384
398
|
sizes,
|
|
385
399
|
url: BID_ENDPOINT,
|
|
386
400
|
method: 'GET',
|
|
387
|
-
data: Object.assign(data, _getBrowserParams(topWindowUrl), _getDigiTrustQueryParams(userId)
|
|
401
|
+
data: Object.assign(data, _getBrowserParams(topWindowUrl), _getDigiTrustQueryParams(userId))
|
|
388
402
|
})
|
|
389
403
|
});
|
|
390
404
|
return bids;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This module adds HadronID to the User ID module
|
|
3
|
+
* The {@link module:modules/userId} module is required
|
|
4
|
+
* @module modules/hadronIdSystem
|
|
5
|
+
* @requires module:modules/userId
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {ajax} from '../src/ajax.js';
|
|
9
|
+
import {getStorageManager} from '../src/storageManager.js';
|
|
10
|
+
import {submodule} from '../src/hook.js';
|
|
11
|
+
import { isFn, isStr, isPlainObject, logError } from '../src/utils.js';
|
|
12
|
+
|
|
13
|
+
const MODULE_NAME = 'hadronId';
|
|
14
|
+
const AU_GVLID = 561;
|
|
15
|
+
|
|
16
|
+
export const storage = getStorageManager(AU_GVLID, 'hadron');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Param or default.
|
|
20
|
+
* @param {String} param
|
|
21
|
+
* @param {String} defaultVal
|
|
22
|
+
*/
|
|
23
|
+
function paramOrDefault(param, defaultVal, arg) {
|
|
24
|
+
if (isFn(param)) {
|
|
25
|
+
return param(arg);
|
|
26
|
+
} else if (isStr(param)) {
|
|
27
|
+
return param;
|
|
28
|
+
}
|
|
29
|
+
return defaultVal;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** @type {Submodule} */
|
|
33
|
+
export const hadronIdSubmodule = {
|
|
34
|
+
/**
|
|
35
|
+
* used to link submodule with config
|
|
36
|
+
* @type {string}
|
|
37
|
+
*/
|
|
38
|
+
name: MODULE_NAME,
|
|
39
|
+
/**
|
|
40
|
+
* decode the stored id value for passing to bid requests
|
|
41
|
+
* @function
|
|
42
|
+
* @param {{value:string}} value
|
|
43
|
+
* @returns {{hadronId:Object}}
|
|
44
|
+
*/
|
|
45
|
+
decode(value) {
|
|
46
|
+
let hadronId = storage.getDataFromLocalStorage('auHadronId');
|
|
47
|
+
if (isStr(hadronId)) {
|
|
48
|
+
return {hadronId: hadronId};
|
|
49
|
+
}
|
|
50
|
+
return (value && typeof value['hadronId'] === 'string') ? { 'hadronId': value['hadronId'] } : undefined;
|
|
51
|
+
},
|
|
52
|
+
/**
|
|
53
|
+
* performs action to obtain id and return a value in the callback's response argument
|
|
54
|
+
* @function
|
|
55
|
+
* @param {SubmoduleConfig} [config]
|
|
56
|
+
* @returns {IdResponse|undefined}
|
|
57
|
+
*/
|
|
58
|
+
getId(config) {
|
|
59
|
+
if (!isPlainObject(config.params)) {
|
|
60
|
+
config.params = {};
|
|
61
|
+
}
|
|
62
|
+
const url = paramOrDefault(config.params.url,
|
|
63
|
+
`https://id.hadron.ad.gt/api/v1/pbhid`,
|
|
64
|
+
config.params.urlArg);
|
|
65
|
+
|
|
66
|
+
const resp = function (callback) {
|
|
67
|
+
let hadronId = storage.getDataFromLocalStorage('auHadronId');
|
|
68
|
+
if (isStr(hadronId)) {
|
|
69
|
+
const responseObj = {hadronId: hadronId};
|
|
70
|
+
callback(responseObj);
|
|
71
|
+
} else {
|
|
72
|
+
const callbacks = {
|
|
73
|
+
success: response => {
|
|
74
|
+
let responseObj;
|
|
75
|
+
if (response) {
|
|
76
|
+
try {
|
|
77
|
+
responseObj = JSON.parse(response);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
logError(error);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
callback(responseObj);
|
|
83
|
+
},
|
|
84
|
+
error: error => {
|
|
85
|
+
logError(`${MODULE_NAME}: ID fetch encountered an error`, error);
|
|
86
|
+
callback();
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
ajax(url, callbacks, undefined, {method: 'GET'});
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
return {callback: resp};
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
submodule('userId', hadronIdSubmodule);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
## Audigent Hadron User ID Submodule
|
|
2
|
+
|
|
3
|
+
Audigent Hadron ID Module. For assistance setting up your module please contact us at [prebid@audigent.com](prebid@audigent.com).
|
|
4
|
+
|
|
5
|
+
### Prebid Params
|
|
6
|
+
|
|
7
|
+
Individual params may be set for the Audigent Hadron ID Submodule. At least one identifier must be set in the params.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
pbjs.setConfig({
|
|
11
|
+
usersync: {
|
|
12
|
+
userIds: [{
|
|
13
|
+
name: 'hadronId',
|
|
14
|
+
storage: {
|
|
15
|
+
name: 'hadronId',
|
|
16
|
+
type: 'html5'
|
|
17
|
+
}
|
|
18
|
+
}]
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
## Parameter Descriptions for the `usersync` Configuration Section
|
|
23
|
+
The below parameters apply only to the HadronID User ID Module integration.
|
|
24
|
+
|
|
25
|
+
| Param under usersync.userIds[] | Scope | Type | Description | Example |
|
|
26
|
+
| --- | --- | --- | --- | --- |
|
|
27
|
+
| name | Required | String | ID value for the HadronID module - `"hadronId"` | `"hadronId"` |
|
|
28
|
+
| storage | Required | Object | The publisher must specify the local storage in which to store the results of the call to get the user ID. This can be either cookie or HTML5 storage. | |
|
|
29
|
+
| storage.type | Required | String | This is where the results of the user ID will be stored. The recommended method is `localStorage` by specifying `html5`. | `"html5"` |
|
|
30
|
+
| storage.name | Required | String | The name of the cookie or html5 local storage where the user ID will be stored. | `"hadronid"` |
|
|
31
|
+
| storage.expires | Optional | Integer | How long (in days) the user ID information will be stored. | `365` |
|
|
32
|
+
| value | Optional | Object | Used only if the page has a separate mechanism for storing the Hadron ID. The value is an object containing the values to be sent to the adapters. In this scenario, no URL is called and nothing is added to local storage | `{"hadronId": "eb33b0cb-8d35-4722-b9c0-1a31d4064888"}` |
|
|
33
|
+
| params | Optional | Object | Used to store params for the id system |
|
|
34
|
+
| params.url | Optional | String | Set an alternate GET url for HadronId with this parameter |
|
|
35
|
+
| params.urlArg | Optional | Object | Optional url parameter for params.url |
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This module adds the Audigent Hadron provider to the real time data module
|
|
3
|
+
* The {@link module:modules/realTimeData} module is required
|
|
4
|
+
* The module will fetch real-time data from Audigent
|
|
5
|
+
* @module modules/hadronRtdProvider
|
|
6
|
+
* @requires module:modules/realTimeData
|
|
7
|
+
*/
|
|
8
|
+
import {ajax} from '../src/ajax.js';
|
|
9
|
+
import {config} from '../src/config.js';
|
|
10
|
+
import {getGlobal} from '../src/prebidGlobal.js';
|
|
11
|
+
import {getStorageManager} from '../src/storageManager.js';
|
|
12
|
+
import {submodule} from '../src/hook.js';
|
|
13
|
+
import {isFn, isStr, isArray, deepEqual, isPlainObject, logError} from '../src/utils.js';
|
|
14
|
+
|
|
15
|
+
const MODULE_NAME = 'realTimeData';
|
|
16
|
+
const SUBMODULE_NAME = 'hadron';
|
|
17
|
+
const AU_GVLID = 561;
|
|
18
|
+
|
|
19
|
+
export const HALOID_LOCAL_NAME = 'auHadronId';
|
|
20
|
+
export const RTD_LOCAL_NAME = 'auHadronRtd';
|
|
21
|
+
export const storage = getStorageManager(AU_GVLID, SUBMODULE_NAME);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Deep set an object unless value present.
|
|
25
|
+
* @param {Object} obj
|
|
26
|
+
* @param {String} path
|
|
27
|
+
* @param {Object} val
|
|
28
|
+
*/
|
|
29
|
+
function set(obj, path, val) {
|
|
30
|
+
const keys = path.split('.');
|
|
31
|
+
const lastKey = keys.pop();
|
|
32
|
+
const lastObj = keys.reduce((obj, key) => obj[key] = obj[key] || {}, obj);
|
|
33
|
+
lastObj[lastKey] = lastObj[lastKey] || val;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Deep object merging with array deduplication.
|
|
38
|
+
* @param {Object} target
|
|
39
|
+
* @param {Object} sources
|
|
40
|
+
*/
|
|
41
|
+
function mergeDeep(target, ...sources) {
|
|
42
|
+
if (!sources.length) return target;
|
|
43
|
+
const source = sources.shift();
|
|
44
|
+
|
|
45
|
+
if (isPlainObject(target) && isPlainObject(source)) {
|
|
46
|
+
for (const key in source) {
|
|
47
|
+
if (isPlainObject(source[key])) {
|
|
48
|
+
if (!target[key]) Object.assign(target, { [key]: {} });
|
|
49
|
+
mergeDeep(target[key], source[key]);
|
|
50
|
+
} else if (isArray(source[key])) {
|
|
51
|
+
if (!target[key]) {
|
|
52
|
+
Object.assign(target, { [key]: source[key] });
|
|
53
|
+
} else if (isArray(target[key])) {
|
|
54
|
+
source[key].forEach(obj => {
|
|
55
|
+
let e = 1;
|
|
56
|
+
for (let i = 0; i < target[key].length; i++) {
|
|
57
|
+
if (deepEqual(target[key][i], obj)) {
|
|
58
|
+
e = 0;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (e) {
|
|
63
|
+
target[key].push(obj);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
Object.assign(target, { [key]: source[key] });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return mergeDeep(target, ...sources);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Lazy merge objects.
|
|
78
|
+
* @param {Object} target
|
|
79
|
+
* @param {Object} source
|
|
80
|
+
*/
|
|
81
|
+
function mergeLazy(target, source) {
|
|
82
|
+
if (!isPlainObject(target)) {
|
|
83
|
+
target = {};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!isPlainObject(source)) {
|
|
87
|
+
source = {};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return mergeDeep(target, source);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Param or default.
|
|
95
|
+
* @param {String} param
|
|
96
|
+
* @param {String} defaultVal
|
|
97
|
+
*/
|
|
98
|
+
function paramOrDefault(param, defaultVal, arg) {
|
|
99
|
+
if (isFn(param)) {
|
|
100
|
+
return param(arg);
|
|
101
|
+
} else if (isStr(param)) {
|
|
102
|
+
return param;
|
|
103
|
+
}
|
|
104
|
+
return defaultVal;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Add real-time data & merge segments.
|
|
109
|
+
* @param {Object} bidConfig
|
|
110
|
+
* @param {Object} rtd
|
|
111
|
+
* @param {Object} rtdConfig
|
|
112
|
+
*/
|
|
113
|
+
export function addRealTimeData(bidConfig, rtd, rtdConfig) {
|
|
114
|
+
if (rtdConfig.params && rtdConfig.params.handleRtd) {
|
|
115
|
+
rtdConfig.params.handleRtd(bidConfig, rtd, rtdConfig, config);
|
|
116
|
+
} else {
|
|
117
|
+
if (isPlainObject(rtd.ortb2)) {
|
|
118
|
+
let ortb2 = config.getConfig('ortb2') || {};
|
|
119
|
+
config.setConfig({ortb2: mergeLazy(ortb2, rtd.ortb2)});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (isPlainObject(rtd.ortb2b)) {
|
|
123
|
+
let bidderConfig = config.getBidderConfig();
|
|
124
|
+
|
|
125
|
+
Object.keys(rtd.ortb2b).forEach(bidder => {
|
|
126
|
+
let rtdOptions = rtd.ortb2b[bidder] || {};
|
|
127
|
+
|
|
128
|
+
let bidderOptions = {};
|
|
129
|
+
if (isPlainObject(bidderConfig[bidder])) {
|
|
130
|
+
bidderOptions = bidderConfig[bidder];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
config.setBidderConfig({
|
|
134
|
+
bidders: [bidder],
|
|
135
|
+
config: mergeLazy(bidderOptions, rtdOptions)
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Real-time data retrieval from Audigent
|
|
144
|
+
* @param {Object} reqBidsConfigObj
|
|
145
|
+
* @param {function} onDone
|
|
146
|
+
* @param {Object} rtdConfig
|
|
147
|
+
* @param {Object} userConsent
|
|
148
|
+
*/
|
|
149
|
+
export function getRealTimeData(bidConfig, onDone, rtdConfig, userConsent) {
|
|
150
|
+
if (rtdConfig && isPlainObject(rtdConfig.params) && rtdConfig.params.segmentCache) {
|
|
151
|
+
let jsonData = storage.getDataFromLocalStorage(RTD_LOCAL_NAME);
|
|
152
|
+
|
|
153
|
+
if (jsonData) {
|
|
154
|
+
let data = JSON.parse(jsonData);
|
|
155
|
+
|
|
156
|
+
if (data.rtd) {
|
|
157
|
+
addRealTimeData(bidConfig, data.rtd, rtdConfig);
|
|
158
|
+
onDone();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const userIds = (getGlobal()).getUserIds();
|
|
165
|
+
|
|
166
|
+
let hadronId = storage.getDataFromLocalStorage(HALOID_LOCAL_NAME);
|
|
167
|
+
if (isStr(hadronId)) {
|
|
168
|
+
(getGlobal()).refreshUserIds({submoduleNames: 'hadronId'});
|
|
169
|
+
userIds.hadronId = hadronId;
|
|
170
|
+
getRealTimeDataAsync(bidConfig, onDone, rtdConfig, userConsent, userIds);
|
|
171
|
+
} else {
|
|
172
|
+
var script = document.createElement('script');
|
|
173
|
+
script.type = 'text/javascript';
|
|
174
|
+
|
|
175
|
+
window.pubHadronCb = (hadronId) => {
|
|
176
|
+
userIds.hadronId = hadronId;
|
|
177
|
+
getRealTimeDataAsync(bidConfig, onDone, rtdConfig, userConsent, userIds);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const hadronIdUrl = rtdConfig.params && rtdConfig.params.hadronIdUrl;
|
|
181
|
+
script.src = paramOrDefault(hadronIdUrl, 'https://id.hadron.ad.gt/api/v1/hadronid', userIds);
|
|
182
|
+
document.getElementsByTagName('head')[0].appendChild(script);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Async rtd retrieval from Audigent
|
|
188
|
+
* @param {function} onDone
|
|
189
|
+
* @param {Object} rtdConfig
|
|
190
|
+
* @param {Object} userConsent
|
|
191
|
+
* @param {Object} userIds
|
|
192
|
+
*/
|
|
193
|
+
export function getRealTimeDataAsync(bidConfig, onDone, rtdConfig, userConsent, userIds) {
|
|
194
|
+
let reqParams = {};
|
|
195
|
+
|
|
196
|
+
if (isPlainObject(rtdConfig)) {
|
|
197
|
+
set(rtdConfig, 'params.requestParams.ortb2', config.getConfig('ortb2'));
|
|
198
|
+
reqParams = rtdConfig.params.requestParams;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (isPlainObject(window.pubHadronPm)) {
|
|
202
|
+
reqParams.pubHadronPm = window.pubHadronPm;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const url = `https://seg.hadron.ad.gt/api/v1/rtd`;
|
|
206
|
+
ajax(url, {
|
|
207
|
+
success: function (response, req) {
|
|
208
|
+
if (req.status === 200) {
|
|
209
|
+
try {
|
|
210
|
+
const data = JSON.parse(response);
|
|
211
|
+
if (data && data.rtd) {
|
|
212
|
+
addRealTimeData(bidConfig, data.rtd, rtdConfig);
|
|
213
|
+
onDone();
|
|
214
|
+
storage.setDataInLocalStorage(RTD_LOCAL_NAME, JSON.stringify(data));
|
|
215
|
+
} else {
|
|
216
|
+
onDone();
|
|
217
|
+
}
|
|
218
|
+
} catch (err) {
|
|
219
|
+
logError('unable to parse audigent segment data');
|
|
220
|
+
onDone();
|
|
221
|
+
}
|
|
222
|
+
} else if (req.status === 204) {
|
|
223
|
+
// unrecognized partner config
|
|
224
|
+
onDone();
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
error: function () {
|
|
228
|
+
onDone();
|
|
229
|
+
logError('unable to get audigent segment data');
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
JSON.stringify({'userIds': userIds, 'config': reqParams}),
|
|
233
|
+
{contentType: 'application/json'}
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Module init
|
|
239
|
+
* @param {Object} provider
|
|
240
|
+
* @param {Objkect} userConsent
|
|
241
|
+
* @return {boolean}
|
|
242
|
+
*/
|
|
243
|
+
function init(provider, userConsent) {
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** @type {RtdSubmodule} */
|
|
248
|
+
export const hadronSubmodule = {
|
|
249
|
+
name: SUBMODULE_NAME,
|
|
250
|
+
getBidRequestData: getRealTimeData,
|
|
251
|
+
init: init
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
submodule(MODULE_NAME, hadronSubmodule);
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
## Audigent Hadron Real-time Data Submodule
|
|
2
|
+
|
|
3
|
+
Audigent is a next-generation, 1st party data management platform and the
|
|
4
|
+
world’s first "data agency", powering the programmatic landscape and DTC
|
|
5
|
+
eCommerce with actionable 1st party audience and contextual data from the
|
|
6
|
+
world’s most influential retailers, lifestyle publishers, content creators,
|
|
7
|
+
athletes and artists.
|
|
8
|
+
|
|
9
|
+
The Hadron real-time data module in Prebid has been built so that publishers
|
|
10
|
+
can maximize the power of their first-party audiences and contextual data.
|
|
11
|
+
This module provides both an integrated cookieless Hadron identity with real-time
|
|
12
|
+
contextual and audience segmentation solution that seamlessly and easily
|
|
13
|
+
integrates into your existing Prebid deployment.
|
|
14
|
+
|
|
15
|
+
Users, devices, content, cohorts and other features are identified and utilized
|
|
16
|
+
to augment every bid request with targeted, 1st party data-derived segments
|
|
17
|
+
before being submitted to supply-side platforms. Enriching the bid request with
|
|
18
|
+
robust 1st party audience and contextual data, Audigent's Hadron RTD module
|
|
19
|
+
optimizes targeting, increases the number of bids, increases bid value,
|
|
20
|
+
and drives additional incremental revenue for publishers.
|
|
21
|
+
|
|
22
|
+
### Publisher Usage
|
|
23
|
+
|
|
24
|
+
Compile the Hadron RTD module into your Prebid build:
|
|
25
|
+
|
|
26
|
+
`gulp build --modules=userId,unifiedIdSystem,rtdModule,hadronRtdProvider,appnexusBidAdapter`
|
|
27
|
+
|
|
28
|
+
Add the Hadron RTD provider to your Prebid config. In this example we will configure
|
|
29
|
+
publisher 1234 to retrieve segments from Audigent. See the
|
|
30
|
+
"Parameter Descriptions" below for more detailed information of the
|
|
31
|
+
configuration parameters. Please work with your Audigent Prebid support team
|
|
32
|
+
(prebid@audigent.com) on which version of Prebid.js supports different bidder
|
|
33
|
+
and segment configurations.
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
pbjs.setConfig(
|
|
37
|
+
...
|
|
38
|
+
realTimeData: {
|
|
39
|
+
auctionDelay: 5000,
|
|
40
|
+
dataProviders: [
|
|
41
|
+
{
|
|
42
|
+
name: "hadron",
|
|
43
|
+
waitForIt: true,
|
|
44
|
+
params: {
|
|
45
|
+
segmentCache: false,
|
|
46
|
+
requestParams: {
|
|
47
|
+
publisherId: 1234
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
...
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Parameter Descriptions for the Hadron Configuration Section
|
|
58
|
+
|
|
59
|
+
| Name |Type | Description | Notes |
|
|
60
|
+
| :------------ | :------------ | :------------ |:------------ |
|
|
61
|
+
| name | String | Real time data module name | Always 'hadron' |
|
|
62
|
+
| waitForIt | Boolean | Required to ensure that the auction is delayed until prefetch is complete | Optional. Defaults to false |
|
|
63
|
+
| params | Object | | |
|
|
64
|
+
| params.handleRtd | Function | A passable RTD handler that allows custom adunit and ortb2 logic to be configured. The function signature is (bidConfig, rtd, rtdConfig, pbConfig) => {}. | Optional |
|
|
65
|
+
| params.segmentCache | Boolean | This parameter tells the Hadron RTD module to attempt reading segments from a local storage cache instead of always requesting them from the Audigent server. | Optional. Defaults to false. |
|
|
66
|
+
| params.requestParams | Object | Publisher partner specific configuration options, such as optional publisher id and other segment query related metadata to be submitted to Audigent's backend with each request. Contact prebid@audigent.com for more information. | Optional |
|
|
67
|
+
| params.hadronIdUrl | String | Parameter to specify alternate hadronid endpoint url. | Optional |
|
|
68
|
+
|
|
69
|
+
### Publisher Customized RTD Handling
|
|
70
|
+
As indicated above, it is possible to provide your own bid augmentation
|
|
71
|
+
functions rather than simply merging supplied data. This is useful if you
|
|
72
|
+
want to perform custom bid augmentation and logic with Hadron real-time data
|
|
73
|
+
prior to the bid request being sent. Simply add your custom logic to the
|
|
74
|
+
optional handleRtd parameter and provide your custom RTD handling logic there.
|
|
75
|
+
|
|
76
|
+
Please see the following example, which provides a function to modify bids for
|
|
77
|
+
a bid adapter called adBuzz and perform custom logic on bidder parameters.
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
pbjs.setConfig(
|
|
81
|
+
...
|
|
82
|
+
realTimeData: {
|
|
83
|
+
auctionDelay: auctionDelay,
|
|
84
|
+
dataProviders: [
|
|
85
|
+
{
|
|
86
|
+
name: "hadron",
|
|
87
|
+
waitForIt: true,
|
|
88
|
+
params: {
|
|
89
|
+
handleRtd: function(bidConfig, rtd, rtdConfig, pbConfig) {
|
|
90
|
+
var adUnits = bidConfig.adUnits;
|
|
91
|
+
for (var i = 0; i < adUnits.length; i++) {
|
|
92
|
+
var adUnit = adUnits[i];
|
|
93
|
+
for (var j = 0; j < adUnit.bids.length; j++) {
|
|
94
|
+
var bid = adUnit.bids[j];
|
|
95
|
+
if (bid.bidder == 'adBuzz' && rtd['adBuzz'][0].value != 'excludeSeg') {
|
|
96
|
+
bid.params.adBuzzCustomSegments.push(rtd['adBuzz'][0].id);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
segmentCache: false,
|
|
102
|
+
requestParams: {
|
|
103
|
+
publisherId: 1234
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
...
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The handleRtd function can also be used to configure custom ortb2 data
|
|
114
|
+
processing. Please see the examples available in the hadronRtdProvider_spec.js
|
|
115
|
+
tests and work with your Audigent Prebid integration team (prebid@audigent.com)
|
|
116
|
+
on how to best configure your own Hadron RTD & Open RTB data handlers.
|
|
117
|
+
|
|
118
|
+
### Testing
|
|
119
|
+
|
|
120
|
+
To view an example of available segments returned by Audigent's backends:
|
|
121
|
+
|
|
122
|
+
`gulp serve --modules=userId,unifiedIdSystem,rtdModule,hadronRtdProvider,appnexusBidAdapter`
|
|
123
|
+
|
|
124
|
+
and then point your browser at:
|
|
125
|
+
|
|
126
|
+
`http://localhost:9999/integrationExamples/gpt/hadronRtdProvider_example.html`
|