prebid.js 5.18.0 → 5.20.2
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/browsers.json +1 -0
- package/integrationExamples/gpt/akamaidap_segments_example.html +132 -0
- package/modules/.submodules.json +1 -0
- package/modules/adfBidAdapter.js +21 -16
- package/modules/adtelligentBidAdapter.js +2 -1
- package/modules/adxcgBidAdapter.js +311 -359
- package/modules/airgridRtdProvider.js +1 -1
- package/modules/akamaiDapRtdProvider.js +474 -0
- package/modules/akamaiDapRtdProvider.md +47 -0
- package/modules/appnexusBidAdapter.js +9 -3
- package/modules/atsAnalyticsAdapter.js +67 -46
- package/modules/atsAnalyticsAdapter.md +1 -0
- package/modules/betweenBidAdapter.js +20 -3
- package/modules/browsiRtdProvider.js +106 -18
- package/modules/cleanioRtdProvider.js +192 -0
- package/modules/cleanioRtdProvider.md +59 -0
- package/modules/codefuelBidAdapter.js +183 -0
- package/modules/codefuelBidAdapter.md +111 -0
- package/modules/connectIdSystem.js +104 -0
- package/modules/connectIdSystem.md +33 -0
- package/modules/deepintentBidAdapter.js +106 -9
- package/modules/deepintentBidAdapter.md +36 -1
- package/modules/deltaprojectsBidAdapter.js +252 -0
- package/modules/deltaprojectsBidAdapter.md +32 -0
- package/modules/engageyaBidAdapter.js +157 -0
- package/modules/gridBidAdapter.js +1 -0
- package/modules/gumgumBidAdapter.js +8 -0
- package/modules/inskinBidAdapter.js +7 -3
- package/modules/ipromBidAdapter.js +79 -0
- package/modules/ixBidAdapter.js +8 -1
- package/modules/jixieBidAdapter.js +8 -2
- package/modules/justpremiumBidAdapter.js +6 -1
- package/modules/kinessoIdSystem.js +1 -1
- package/modules/limelightDigitalBidAdapter.js +22 -2
- package/modules/livewrappedAnalyticsAdapter.js +49 -1
- package/modules/multibid/index.js +3 -3
- package/modules/nativoBidAdapter.js +5 -1
- package/modules/nextMillenniumBidAdapter.js +12 -3
- package/modules/oguryBidAdapter.js +14 -1
- package/modules/openxBidAdapter.js +34 -22
- package/modules/operaadsBidAdapter.js +21 -1
- package/modules/otmBidAdapter.js +146 -0
- package/modules/otmBidAdapter.md +27 -26
- package/modules/outbrainBidAdapter.js +5 -0
- package/modules/playwireBidAdapter.md +61 -0
- package/modules/publinkIdSystem.js +11 -6
- package/modules/rtdModule/index.js +2 -2
- package/modules/sonobiBidAdapter.js +7 -0
- package/modules/sortableBidAdapter.js +1 -0
- package/modules/teadsBidAdapter.js +3 -0
- package/modules/tripleliftBidAdapter.js +22 -5
- package/modules/trustxBidAdapter.js +8 -6
- package/modules/undertoneBidAdapter.js +9 -5
- package/modules/undertoneBidAdapter.md +5 -1
- package/modules/userId/eids.js +18 -0
- package/modules/userId/eids.md +7 -0
- package/modules/userId/userId.md +12 -0
- package/modules/ventesBidAdapter.js +370 -0
- package/modules/ventesBidAdapter.md +94 -0
- package/modules/videobyteBidAdapter.js +13 -6
- package/modules/videobyteBidAdapter.md +49 -0
- package/modules/yahoosspBidAdapter.js +6 -6
- package/modules/yieldmoSyntheticInventoryModule.js +46 -0
- package/modules/yieldmoSyntheticInventoryModule.md +68 -0
- package/package.json +1 -1
- package/src/adapterManager.js +5 -0
- package/src/adapters/bidderFactory.js +4 -3
- package/src/auction.js +11 -11
- package/src/constants.json +1 -0
- package/src/secureCreatives.js +6 -7
- package/src/targeting.js +11 -9
- package/test/spec/modules/adfBidAdapter_spec.js +83 -29
- package/test/spec/modules/adtelligentBidAdapter_spec.js +1 -0
- package/test/spec/modules/adxcgBidAdapter_spec.js +827 -571
- package/test/spec/modules/akamaiDapRtdProvider_spec.js +246 -0
- package/test/spec/modules/appnexusBidAdapter_spec.js +16 -1
- package/test/spec/modules/atsAnalyticsAdapter_spec.js +42 -9
- package/test/spec/modules/betweenBidAdapter_spec.js +41 -0
- package/test/spec/modules/browsiRtdProvider_spec.js +62 -7
- package/test/spec/modules/cleanioRtdProvider_spec.js +188 -0
- package/test/spec/modules/codefuelBidAdapter_spec.js +316 -0
- package/test/spec/modules/connectIdSystem_spec.js +189 -0
- package/test/spec/modules/deepintentBidAdapter_spec.js +153 -3
- package/test/spec/modules/deltaprojectsBidAdapter_spec.js +399 -0
- package/test/spec/modules/engageyaBidAdapter_spec.js +286 -0
- package/test/spec/modules/eplanningBidAdapter_spec.js +8 -8
- package/test/spec/modules/gumgumBidAdapter_spec.js +5 -1
- package/test/spec/modules/ipromBidAdapter_spec.js +195 -0
- package/test/spec/modules/ixBidAdapter_spec.js +13 -3
- package/test/spec/modules/jixieBidAdapter_spec.js +13 -11
- package/test/spec/modules/justpremiumBidAdapter_spec.js +9 -2
- package/test/spec/modules/limelightDigitalBidAdapter_spec.js +155 -1
- package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +52 -7
- package/test/spec/modules/multibid_spec.js +31 -31
- package/test/spec/modules/nextMillenniumBidAdapter_spec.js +13 -1
- package/test/spec/modules/oguryBidAdapter_spec.js +53 -12
- package/test/spec/modules/openxBidAdapter_spec.js +85 -13
- package/test/spec/modules/operaadsBidAdapter_spec.js +38 -6
- package/test/spec/modules/otmBidAdapter_spec.js +67 -0
- package/test/spec/modules/outbrainBidAdapter_spec.js +18 -0
- package/test/spec/modules/publinkIdSystem_spec.js +6 -6
- package/test/spec/modules/sonobiBidAdapter_spec.js +34 -1
- package/test/spec/modules/sortableBidAdapter_spec.js +11 -0
- package/test/spec/modules/teadsBidAdapter_spec.js +132 -0
- package/test/spec/modules/tripleliftBidAdapter_spec.js +128 -0
- package/test/spec/modules/trustxBidAdapter_spec.js +3 -3
- package/test/spec/modules/undertoneBidAdapter_spec.js +52 -0
- package/test/spec/modules/ventesBidAdapter_spec.js +845 -0
- package/test/spec/modules/videobyteBidAdapter_spec.js +2 -2
- package/test/spec/modules/yieldmoSyntheticInventoryModule_spec.js +89 -0
- package/test/spec/unit/core/adapterManager_spec.js +37 -2
- package/test/spec/unit/core/bidderFactory_spec.js +61 -1
- package/test/spec/unit/pbjs_api_spec.js +37 -2
- package/test/spec/unit/secureCreatives_spec.js +54 -25
|
@@ -33,7 +33,7 @@ export function attachScriptTagToDOM(rtdConfig) {
|
|
|
33
33
|
edktInitializor.load = function(e) {
|
|
34
34
|
var p = e || 'sdk';
|
|
35
35
|
var n = document.createElement('script');
|
|
36
|
-
n.type = '
|
|
36
|
+
n.type = 'module';
|
|
37
37
|
n.async = true;
|
|
38
38
|
n.src = 'https://cdn.edkt.io/' + p + '/edgekit.min.js';
|
|
39
39
|
document.getElementsByTagName('head')[0].appendChild(n);
|
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This module adds the Akamai DAP RTD 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 DAP
|
|
5
|
+
* @module modules/akamaiDapRtdProvider
|
|
6
|
+
* @requires module:modules/realTimeData
|
|
7
|
+
*/
|
|
8
|
+
import {ajax} from '../src/ajax.js';
|
|
9
|
+
import {config} from '../src/config.js';
|
|
10
|
+
import {getStorageManager} from '../src/storageManager.js';
|
|
11
|
+
import {submodule} from '../src/hook.js';
|
|
12
|
+
import {isPlainObject, mergeDeep, logMessage, logInfo, logError} from '../src/utils.js';
|
|
13
|
+
|
|
14
|
+
const MODULE_NAME = 'realTimeData';
|
|
15
|
+
const SUBMODULE_NAME = 'dap';
|
|
16
|
+
|
|
17
|
+
export const SEGMENTS_STORAGE_KEY = 'akamaiDapSegments';
|
|
18
|
+
export const storage = getStorageManager(null, SUBMODULE_NAME);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Lazy merge objects.
|
|
22
|
+
* @param {String} target
|
|
23
|
+
* @param {String} source
|
|
24
|
+
*/
|
|
25
|
+
function mergeLazy(target, source) {
|
|
26
|
+
if (!isPlainObject(target)) {
|
|
27
|
+
target = {};
|
|
28
|
+
}
|
|
29
|
+
if (!isPlainObject(source)) {
|
|
30
|
+
source = {};
|
|
31
|
+
}
|
|
32
|
+
return mergeDeep(target, source);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Add real-time data & merge segments.
|
|
37
|
+
* @param {Object} bidConfig
|
|
38
|
+
* @param {Object} rtd
|
|
39
|
+
* @param {Object} rtdConfig
|
|
40
|
+
*/
|
|
41
|
+
export function addRealTimeData(rtd) {
|
|
42
|
+
logInfo('DEBUG(addRealTimeData) - ENTER');
|
|
43
|
+
if (isPlainObject(rtd.ortb2)) {
|
|
44
|
+
let ortb2 = config.getConfig('ortb2') || {};
|
|
45
|
+
logMessage('DEBUG(addRealTimeData): merging original: ', ortb2);
|
|
46
|
+
logMessage('DEBUG(addRealTimeData): merging in: ', rtd.ortb2);
|
|
47
|
+
config.setConfig({ortb2: mergeLazy(ortb2, rtd.ortb2)});
|
|
48
|
+
}
|
|
49
|
+
logInfo('DEBUG(addRealTimeData) - EXIT');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Real-time data retrieval from Audigent
|
|
54
|
+
* @param {Object} reqBidsConfigObj
|
|
55
|
+
* @param {function} onDone
|
|
56
|
+
* @param {Object} rtdConfi
|
|
57
|
+
* @param {Object} userConsent
|
|
58
|
+
*/
|
|
59
|
+
export function getRealTimeData(bidConfig, onDone, rtdConfig, userConsent) {
|
|
60
|
+
logInfo('DEBUG(getRealTimeData) - ENTER');
|
|
61
|
+
logMessage(' - apiHostname: ' + rtdConfig.params.apiHostname);
|
|
62
|
+
logMessage(' - apiVersion: ' + rtdConfig.params.apiVersion);
|
|
63
|
+
let jsonData = storage.getDataFromLocalStorage(SEGMENTS_STORAGE_KEY);
|
|
64
|
+
if (jsonData) {
|
|
65
|
+
let data = JSON.parse(jsonData);
|
|
66
|
+
if (data.rtd) {
|
|
67
|
+
addRealTimeData(data.rtd);
|
|
68
|
+
onDone();
|
|
69
|
+
logInfo('DEBUG(getRealTimeData) - 1');
|
|
70
|
+
// Don't return - ensure the data is always fresh.
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (rtdConfig && isPlainObject(rtdConfig.params)) {
|
|
75
|
+
let config = {
|
|
76
|
+
api_hostname: rtdConfig.params.apiHostname,
|
|
77
|
+
api_version: rtdConfig.params.apiVersion,
|
|
78
|
+
domain: rtdConfig.params.domain,
|
|
79
|
+
segtax: rtdConfig.params.segtax
|
|
80
|
+
};
|
|
81
|
+
let identity = {
|
|
82
|
+
type: rtdConfig.params.identityType
|
|
83
|
+
};
|
|
84
|
+
let token = dapUtils.dapGetToken(config, identity, rtdConfig.params.tokenTtl);
|
|
85
|
+
if (token !== null) {
|
|
86
|
+
let membership = dapUtils.dapGetMembership(config, token);
|
|
87
|
+
let udSegment = dapUtils.dapMembershipToRtbSegment(membership, config);
|
|
88
|
+
logMessage('DEBUG(getRealTimeData) - token: ' + token + ', user.data.segment: ', udSegment);
|
|
89
|
+
let data = {
|
|
90
|
+
rtd: {
|
|
91
|
+
ortb2: {
|
|
92
|
+
user: {
|
|
93
|
+
data: [
|
|
94
|
+
udSegment
|
|
95
|
+
]
|
|
96
|
+
},
|
|
97
|
+
site: {
|
|
98
|
+
ext: {
|
|
99
|
+
data: {
|
|
100
|
+
dapSAID: membership.said
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
storage.setDataInLocalStorage(SEGMENTS_STORAGE_KEY, JSON.stringify(data));
|
|
108
|
+
onDone();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Module init
|
|
115
|
+
* @param {Object} provider
|
|
116
|
+
* @param {Object} userConsent
|
|
117
|
+
* @return {boolean}
|
|
118
|
+
*/
|
|
119
|
+
function init(provider, userConsent) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** @type {RtdSubmodule} */
|
|
124
|
+
export const akamaiDapRtdSubmodule = {
|
|
125
|
+
name: SUBMODULE_NAME,
|
|
126
|
+
getBidRequestData: getRealTimeData,
|
|
127
|
+
init: init
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
submodule(MODULE_NAME, akamaiDapRtdSubmodule);
|
|
131
|
+
|
|
132
|
+
export const dapUtils = {
|
|
133
|
+
|
|
134
|
+
dapGetToken: function(config, identity, ttl) {
|
|
135
|
+
let now = Math.round(Date.now() / 1000.0); // in seconds
|
|
136
|
+
let storageName = 'async_dap_token';
|
|
137
|
+
let token = null;
|
|
138
|
+
|
|
139
|
+
if (ttl == 0) {
|
|
140
|
+
localStorage.removeItem(storageName);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
let item = JSON.parse(localStorage.getItem(storageName));
|
|
144
|
+
if (item == null) {
|
|
145
|
+
item = {
|
|
146
|
+
expires_at: now - 1,
|
|
147
|
+
token: null
|
|
148
|
+
};
|
|
149
|
+
} else {
|
|
150
|
+
token = item.token;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (now > item.expires_at) {
|
|
154
|
+
dapUtils.dapLog('Token missing or expired, fetching a new one...');
|
|
155
|
+
// Trigger a refresh
|
|
156
|
+
let configAsync = {...config};
|
|
157
|
+
dapUtils.dapTokenize(configAsync, identity,
|
|
158
|
+
function(token, status, xhr) {
|
|
159
|
+
item.expires_at = now + ttl;
|
|
160
|
+
item.token = token;
|
|
161
|
+
localStorage.setItem(storageName, JSON.stringify(item));
|
|
162
|
+
dapUtils.dapLog('Successfully updated and stored token; expires in ' + ttl + ' seconds');
|
|
163
|
+
let deviceId100 = xhr.getResponseHeader('Akamai-DAP-100');
|
|
164
|
+
if (deviceId100 != null) {
|
|
165
|
+
localStorage.setItem('dap_deviceId100', deviceId100);
|
|
166
|
+
dapUtils.dapLog('Successfully stored DAP 100 Device ID: ' + deviceId100);
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
function(xhr, status, error) {
|
|
170
|
+
logError('ERROR(' + error + '): failed to retrieve token! ' + status);
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return token;
|
|
176
|
+
},
|
|
177
|
+
|
|
178
|
+
dapGetMembership: function(config, token) {
|
|
179
|
+
let now = Math.round(Date.now() / 1000.0); // in seconds
|
|
180
|
+
let storageName = 'async_dap_membership';
|
|
181
|
+
let maxTtl = 3600; // if the cached membership is older than this, return null
|
|
182
|
+
let membership = null;
|
|
183
|
+
let item = JSON.parse(localStorage.getItem(storageName));
|
|
184
|
+
if (item == null || (now - item.expires_at) > maxTtl) {
|
|
185
|
+
item = {
|
|
186
|
+
expires_at: now - 1,
|
|
187
|
+
said: null,
|
|
188
|
+
cohorts: null,
|
|
189
|
+
attributes: null
|
|
190
|
+
};
|
|
191
|
+
} else {
|
|
192
|
+
membership = {
|
|
193
|
+
said: item.said,
|
|
194
|
+
cohorts: item.cohorts,
|
|
195
|
+
attributes: null
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Always refresh the cached membership.
|
|
200
|
+
let configAsync = {...config};
|
|
201
|
+
dapUtils.dapMembership(configAsync, token,
|
|
202
|
+
function(membership, status, xhr) {
|
|
203
|
+
item.expires_at = now + maxTtl;
|
|
204
|
+
item.said = membership.said;
|
|
205
|
+
item.cohorts = membership.cohorts;
|
|
206
|
+
localStorage.setItem(storageName, JSON.stringify(item));
|
|
207
|
+
dapUtils.dapLog('Successfully updated and stored membership:');
|
|
208
|
+
dapUtils.dapLog(item);
|
|
209
|
+
},
|
|
210
|
+
function(xhr, status, error) {
|
|
211
|
+
logError('ERROR(' + error + '): failed to retrieve membership! ' + status);
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
return membership;
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* DESCRIPTION
|
|
220
|
+
*
|
|
221
|
+
* Convert a DAP membership response to an OpenRTB2 segment object suitable
|
|
222
|
+
* for insertion into user.data.segment or site.data.segment.
|
|
223
|
+
*/
|
|
224
|
+
dapMembershipToRtbSegment: function(membership, config) {
|
|
225
|
+
let segment = {
|
|
226
|
+
name: 'dap.akamai.com',
|
|
227
|
+
ext: {
|
|
228
|
+
'segtax': config.segtax
|
|
229
|
+
},
|
|
230
|
+
segment: []
|
|
231
|
+
};
|
|
232
|
+
if (membership != null) {
|
|
233
|
+
for (const i of membership.cohorts) {
|
|
234
|
+
segment.segment.push({ id: i });
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return segment;
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
dapLog: function(args) {
|
|
241
|
+
let css = '';
|
|
242
|
+
css += 'display: inline-block;';
|
|
243
|
+
css += 'color: #fff;';
|
|
244
|
+
css += 'background: #F28B20;';
|
|
245
|
+
css += 'padding: 1px 4px;';
|
|
246
|
+
css += 'border-radius: 3px';
|
|
247
|
+
|
|
248
|
+
logInfo('%cDAP Client', css, args);
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
/*******************************************************************************
|
|
252
|
+
*
|
|
253
|
+
* V2 (And Beyond) API
|
|
254
|
+
*
|
|
255
|
+
******************************************************************************/
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* SYNOPSIS
|
|
259
|
+
*
|
|
260
|
+
* dapTokenize( config, identity );
|
|
261
|
+
*
|
|
262
|
+
* DESCRIPTION
|
|
263
|
+
*
|
|
264
|
+
* Tokenize an identity into a secure, privacy safe pseudonymiziation.
|
|
265
|
+
*
|
|
266
|
+
* PARAMETERS
|
|
267
|
+
*
|
|
268
|
+
* config: an array of system configuration parameters
|
|
269
|
+
*
|
|
270
|
+
* identity: an array of identity parameters passed to the tokenizing system
|
|
271
|
+
*
|
|
272
|
+
* EXAMPLE
|
|
273
|
+
*
|
|
274
|
+
* config = {
|
|
275
|
+
* api_hostname: "prebid.dap.akadns.net", // required
|
|
276
|
+
* domain: "prebid.org", // required
|
|
277
|
+
* api_version: "x1", // optional, default "x1"
|
|
278
|
+
* };
|
|
279
|
+
*
|
|
280
|
+
* token = null;
|
|
281
|
+
* identity_email = {
|
|
282
|
+
* type: "email",
|
|
283
|
+
* identity: "obiwan@jedi.com"
|
|
284
|
+
* attributes: { cohorts: [ "100:1641013200", "101:1641013200", "102":3:1641013200" ] },
|
|
285
|
+
* };
|
|
286
|
+
* dap_x1_tokenize( config, identity_email,
|
|
287
|
+
* function( response, status, xhr ) { token = response; },
|
|
288
|
+
* function( xhr, status, error ) { ; } // handle error
|
|
289
|
+
*
|
|
290
|
+
* token = null;
|
|
291
|
+
* identity_signature = { type: "signature:1.0.0" };
|
|
292
|
+
* dap_x1_tokenize( config, identity_signature,
|
|
293
|
+
* function( response, status, xhr } { token = response; },
|
|
294
|
+
* function( xhr, status, error ) { ; } // handle error
|
|
295
|
+
*/
|
|
296
|
+
dapTokenize: function(config, identity, onSuccess = null, onError = null) {
|
|
297
|
+
if (onError == null) {
|
|
298
|
+
onError = function(xhr, status, error) {};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (config == null || typeof (config) == typeof (undefined)) {
|
|
302
|
+
onError(null, 'Invalid config object', 'ClientError');
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (typeof (config.domain) != 'string') {
|
|
307
|
+
onError(null, 'Invalid config.domain: must be a string', 'ClientError');
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (config.domain.length <= 0) {
|
|
312
|
+
onError(null, 'Invalid config.domain: must have non-zero length', 'ClientError');
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (!('api_version' in config) || (typeof (config.api_version) == 'string' && config.api_version.length == 0)) {
|
|
317
|
+
config.api_version = 'x1';
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (typeof (config.api_version) != 'string') {
|
|
321
|
+
onError(null, "Invalid api_version: must be a string like 'x1', etc.", 'ClientError');
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (!(('api_hostname') in config) || typeof (config.api_hostname) != 'string' || config.api_hostname.length == 0) {
|
|
326
|
+
onError(null, 'Invalid api_hostname: must be a non-empty string', 'ClientError');
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (identity == null || typeof (identity) == typeof (undefined)) {
|
|
331
|
+
onError(null, 'Invalid identity object', 'ClientError');
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (!('type' in identity) || typeof (identity.type) != 'string' || identity.type.length <= 0) {
|
|
336
|
+
onError(null, "Identity must contain a valid 'type' field", 'ClientError');
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
let apiParams = {
|
|
341
|
+
'type': identity.type,
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
if (typeof (identity.identity) != typeof (undefined)) {
|
|
345
|
+
apiParams.identity = identity.identity;
|
|
346
|
+
}
|
|
347
|
+
if (typeof (identity.attributes) != typeof (undefined)) {
|
|
348
|
+
apiParams.attributes = identity.attributes;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
let method;
|
|
352
|
+
let body;
|
|
353
|
+
let path;
|
|
354
|
+
switch (config.api_version) {
|
|
355
|
+
case 'x1':
|
|
356
|
+
case 'x1-dev':
|
|
357
|
+
method = 'POST';
|
|
358
|
+
path = '/data-activation/' + config.api_version + '/domain/' + config.domain + '/identity/tokenize';
|
|
359
|
+
body = JSON.stringify(apiParams);
|
|
360
|
+
break;
|
|
361
|
+
default:
|
|
362
|
+
onError(null, 'Invalid api_version: ' + config.api_version, 'ClientError');
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
let url = 'https://' + config.api_hostname + path;
|
|
367
|
+
let cb = {
|
|
368
|
+
success: (response, request) => {
|
|
369
|
+
let token = null;
|
|
370
|
+
switch (config.api_version) {
|
|
371
|
+
case 'x1':
|
|
372
|
+
case 'x1-dev':
|
|
373
|
+
token = request.getResponseHeader('Akamai-DAP-Token');
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
376
|
+
onSuccess(token, request.status, request);
|
|
377
|
+
},
|
|
378
|
+
error: (request, error) => {
|
|
379
|
+
onError(request, request.statusText, error);
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
ajax(url, cb, body, {
|
|
384
|
+
method: method,
|
|
385
|
+
customHeaders: {
|
|
386
|
+
'Content-Type': 'application/json',
|
|
387
|
+
'Pragma': 'akamai-x-cache-on'
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
},
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* SYNOPSIS
|
|
394
|
+
*
|
|
395
|
+
* dapMembership( config, token, onSuccess, onError );
|
|
396
|
+
*
|
|
397
|
+
* DESCRIPTION
|
|
398
|
+
*
|
|
399
|
+
* Return the audience segment membership along with a new Secure Advertising
|
|
400
|
+
* ID for this token.
|
|
401
|
+
*
|
|
402
|
+
* PARAMETERS
|
|
403
|
+
*
|
|
404
|
+
* config: an array of system configuration parameters
|
|
405
|
+
*
|
|
406
|
+
* token: the token previously returned from the tokenize API
|
|
407
|
+
*
|
|
408
|
+
* EXAMPLE
|
|
409
|
+
*
|
|
410
|
+
* config = {
|
|
411
|
+
* api_hostname: 'api.dap.akadns.net',
|
|
412
|
+
* };
|
|
413
|
+
*
|
|
414
|
+
* // token from dap_x1_tokenize
|
|
415
|
+
*
|
|
416
|
+
* dapMembership( config, token,
|
|
417
|
+
* function( membership, status, xhr ) {
|
|
418
|
+
* // Run auction with membership.segments and membership.said
|
|
419
|
+
* },
|
|
420
|
+
* function( xhr, status, error ) {
|
|
421
|
+
* // error
|
|
422
|
+
* } );
|
|
423
|
+
*
|
|
424
|
+
*/
|
|
425
|
+
dapMembership: function(config, token, onSuccess = null, onError = null) {
|
|
426
|
+
if (onError == null) {
|
|
427
|
+
onError = function(xhr, status, error) {};
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (config == null || typeof (config) == typeof (undefined)) {
|
|
431
|
+
onError(null, 'Invalid config object', 'ClientError');
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (!('api_version' in config) || (typeof (config.api_version) == 'string' && config.api_version.length == 0)) {
|
|
436
|
+
config.api_version = 'x1';
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (typeof (config.api_version) != 'string') {
|
|
440
|
+
onError(null, "Invalid api_version: must be a string like 'x1', etc.", 'ClientError');
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (!(('api_hostname') in config) || typeof (config.api_hostname) != 'string' || config.api_hostname.length == 0) {
|
|
445
|
+
onError(null, 'Invalid api_hostname: must be a non-empty string', 'ClientError');
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
if (token == null || typeof (token) != 'string') {
|
|
450
|
+
onError(null, 'Invalid token: must be a non-null string', 'ClientError');
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
let path = '/data-activation/' +
|
|
454
|
+
config.api_version +
|
|
455
|
+
'/token/' + token +
|
|
456
|
+
'/membership';
|
|
457
|
+
|
|
458
|
+
let url = 'https://' + config.api_hostname + path;
|
|
459
|
+
|
|
460
|
+
let cb = {
|
|
461
|
+
success: (response, request) => {
|
|
462
|
+
onSuccess(JSON.parse(response), request.status, request);
|
|
463
|
+
},
|
|
464
|
+
error: (error, request) => {
|
|
465
|
+
onError(request, request.status, error);
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
ajax(url, cb, undefined, {
|
|
470
|
+
method: 'GET',
|
|
471
|
+
customHeaders: {}
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
### Overview
|
|
2
|
+
|
|
3
|
+
Akamai DAP Real time data Provider automatically invokes the DAP APIs and submit audience segments and the SAID to the bid-stream.
|
|
4
|
+
|
|
5
|
+
### Integration
|
|
6
|
+
|
|
7
|
+
1) Build the akamaiDapRTD module into the Prebid.js package with:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
gulp build --modules=akamaiDapRtdProvider,...
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
2) Use `setConfig` to instruct Prebid.js to initilaize the akamaiDapRtdProvider module, as specified below.
|
|
14
|
+
|
|
15
|
+
### Configuration
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
pbjs.setConfig({
|
|
19
|
+
realTimeData: {
|
|
20
|
+
dataProviders: [
|
|
21
|
+
{
|
|
22
|
+
name: "dap",
|
|
23
|
+
waitForIt: true,
|
|
24
|
+
params: {
|
|
25
|
+
apiHostname: '<see your Akamai account rep>',
|
|
26
|
+
apiVersion: "x1",
|
|
27
|
+
domain: 'your-domain.com',
|
|
28
|
+
identityType: 'email' | 'mobile' | ... | 'dap-signature:1.0.0',
|
|
29
|
+
segtax: <Akamai_taxonomy_name>,
|
|
30
|
+
tokenTtl: 5,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Please reach out to your Akamai account representative(Prebid@akamai.com) to get provisioned on the DAP platform.
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### Testing
|
|
42
|
+
To view an example of available segments returned by dap:
|
|
43
|
+
```
|
|
44
|
+
‘gulp serve --modules=rtdModule,akamaiDapRtdProvider,appnexusBidAdapter,sovrnBidAdapter’
|
|
45
|
+
```
|
|
46
|
+
and then point your browser at:
|
|
47
|
+
"http://localhost:9999/integrationExamples/gpt/akamaidap_segments_example.html"
|
|
@@ -598,6 +598,10 @@ function newBid(serverBid, rtbBid, bidderRequest) {
|
|
|
598
598
|
bid.meta = Object.assign({}, bid.meta, { advertiserId: rtbBid.advertiser_id });
|
|
599
599
|
}
|
|
600
600
|
|
|
601
|
+
if (rtbBid.brand_id) {
|
|
602
|
+
bid.meta = Object.assign({}, bid.meta, { brandId: rtbBid.brand_id });
|
|
603
|
+
}
|
|
604
|
+
|
|
601
605
|
if (rtbBid.rtb.video) {
|
|
602
606
|
// shared video properties used for all 3 contexts
|
|
603
607
|
Object.assign(bid, {
|
|
@@ -696,9 +700,11 @@ function newBid(serverBid, rtbBid, bidderRequest) {
|
|
|
696
700
|
});
|
|
697
701
|
try {
|
|
698
702
|
if (rtbBid.rtb.trackers) {
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
703
|
+
for (let i = 0; i < rtbBid.rtb.trackers[0].impression_urls.length; i++) {
|
|
704
|
+
const url = rtbBid.rtb.trackers[0].impression_urls[i];
|
|
705
|
+
const tracker = createTrackPixelHtml(url);
|
|
706
|
+
bid.ad += tracker;
|
|
707
|
+
}
|
|
702
708
|
}
|
|
703
709
|
} catch (error) {
|
|
704
710
|
logError('Error appending tracking pixel', error);
|