Skip to content

Commit e28792e

Browse files
anand-venkatramanrobertrmartinez
authored andcommitted
PulsePoint adapter - Video support + userId module support (prebid#3937)
* ET-1691: Pulsepoint Analytics adapter for Prebid. (#1) * ET-1691: Adding pulsepoint analytics and tests for pulsepoint adapter * ET-1691: Adding pulsepoint analytics and tests for pulsepoint adapter * ET-1691: cleanup * ET-1691: minor * ET-1691: revert package.json change * Adding bidRequest to bidFactory.createBid method as per prebid#509 * ET-1765: Adding support for additional params in PulsePoint adapter (#2) * ET-1850: Fixing prebid#866 * Minor fix * Adding mandatory parameters to Bid * initial commit * Adding ortb params * Outstream fixes * Minor fixes * Test fixes * Minor refactor * Minor changes * Removing yarn lock file * battr fix and added test * PulsePoint adapter - user id module support (prebid#10) * Making user sync pixels https as well. * fixing review comment
1 parent 242d19f commit e28792e

File tree

3 files changed

+445
-32
lines changed

3 files changed

+445
-32
lines changed

modules/pulsepointBidAdapter.js

+131-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint dot-notation:0, quote-props:0 */
22
import * as utils from '../src/utils';
33
import { registerBidder } from '../src/adapters/bidderFactory';
4+
import { Renderer } from '../src/Renderer';
45

56
const NATIVE_DEFAULTS = {
67
TITLE_LEN: 100,
@@ -13,13 +14,14 @@ const NATIVE_DEFAULTS = {
1314
const DEFAULT_BID_TTL = 20;
1415
const DEFAULT_CURRENCY = 'USD';
1516
const DEFAULT_NET_REVENUE = true;
17+
const KNOWN_PARAMS = ['cp', 'ct', 'cf', 'video', 'battr', 'bcat', 'badv', 'bidfloor'];
1618

1719
/**
1820
* PulsePoint Bid Adapter.
1921
* Contact: [email protected]
2022
*
2123
* Aliases - pulseLite and pulsepointLite are supported for backwards compatibility.
22-
* Formats - Display/Native/Outstream formats supported.
24+
* Formats - Display/Native/Video formats supported.
2325
*
2426
*/
2527
export const spec = {
@@ -28,7 +30,7 @@ export const spec = {
2830

2931
aliases: ['pulseLite', 'pulsepointLite'],
3032

31-
supportedMediaTypes: ['banner', 'native'],
33+
supportedMediaTypes: ['banner', 'native', 'video'],
3234

3335
isBidRequestValid: bid => (
3436
!!(bid && bid.params && bid.params.cp && bid.params.ct)
@@ -41,12 +43,16 @@ export const spec = {
4143
site: site(bidRequests),
4244
app: app(bidRequests),
4345
device: device(),
46+
bcat: bidRequests[0].params.bcat,
47+
badv: bidRequests[0].params.badv,
48+
user: user(bidRequests[0], bidderRequest),
49+
regs: regs(bidderRequest),
4450
};
45-
applyGdpr(bidderRequest, request);
4651
return {
4752
method: 'POST',
48-
url: '//bid.contextweb.com/header/ortb',
49-
data: JSON.stringify(request),
53+
url: 'https://bid.contextweb.com/header/ortb?src=prebid',
54+
data: request,
55+
bidderRequest
5056
};
5157
},
5258

@@ -58,12 +64,12 @@ export const spec = {
5864
if (syncOptions.iframeEnabled) {
5965
return [{
6066
type: 'iframe',
61-
url: '//bh.contextweb.com/visitormatch'
67+
url: 'https://bh.contextweb.com/visitormatch'
6268
}];
6369
} else if (syncOptions.pixelEnabled) {
6470
return [{
6571
type: 'image',
66-
url: '//bh.contextweb.com/visitormatch/prebid'
72+
url: 'https://bh.contextweb.com/visitormatch/prebid'
6773
}];
6874
}
6975
},
@@ -79,12 +85,13 @@ export const spec = {
7985
/**
8086
* Callback for bids, after the call to PulsePoint completes.
8187
*/
82-
function bidResponseAvailable(bidRequest, bidResponse) {
88+
function bidResponseAvailable(request, response) {
8389
const idToImpMap = {};
8490
const idToBidMap = {};
85-
bidResponse = bidResponse.body
91+
const idToSlotConfig = {};
92+
const bidResponse = response.body
8693
// extract the request bids and the response bids, keyed by impr-id
87-
const ortbRequest = parse(bidRequest.data);
94+
const ortbRequest = request.data;
8895
ortbRequest.imp.forEach(imp => {
8996
idToImpMap[imp.id] = imp;
9097
});
@@ -93,6 +100,11 @@ function bidResponseAvailable(bidRequest, bidResponse) {
93100
idToBidMap[bid.impid] = bid;
94101
}));
95102
}
103+
if (request.bidderRequest) {
104+
request.bidderRequest.bids.forEach(bid => {
105+
idToSlotConfig[bid.bidId] = bid;
106+
});
107+
}
96108
const bids = [];
97109
Object.keys(idToImpMap).forEach(id => {
98110
if (idToBidMap[id]) {
@@ -109,6 +121,15 @@ function bidResponseAvailable(bidRequest, bidResponse) {
109121
if (idToImpMap[id]['native']) {
110122
bid['native'] = nativeResponse(idToImpMap[id], idToBidMap[id]);
111123
bid.mediaType = 'native';
124+
} else if (idToImpMap[id].video) {
125+
// for outstream, a renderer is specified
126+
if (idToSlotConfig[id] && utils.deepAccess(idToSlotConfig[id], 'mediaTypes.video.context') === 'outstream') {
127+
bid.renderer = outstreamRenderer(utils.deepAccess(idToSlotConfig[id], 'renderer.options'), utils.deepAccess(idToBidMap[id], 'ext.outstream'));
128+
}
129+
bid.vastXml = idToBidMap[id].adm;
130+
bid.mediaType = 'video';
131+
bid.width = idToBidMap[id].w;
132+
bid.height = idToBidMap[id].h;
112133
} else {
113134
bid.ad = idToBidMap[id].adm;
114135
bid.width = idToImpMap[id].banner.w;
@@ -138,6 +159,9 @@ function impression(slot) {
138159
banner: banner(slot),
139160
'native': nativeImpression(slot),
140161
tagid: slot.params.ct.toString(),
162+
video: video(slot),
163+
bidfloor: slot.params.bidfloor,
164+
ext: ext(slot),
141165
};
142166
}
143167

@@ -146,12 +170,66 @@ function impression(slot) {
146170
*/
147171
function banner(slot) {
148172
const size = adSize(slot);
149-
return slot.nativeParams ? null : {
173+
return (slot.nativeParams || slot.params.video) ? null : {
150174
w: size[0],
151175
h: size[1],
176+
battr: slot.params.battr,
152177
};
153178
}
154179

180+
/**
181+
* Produces an OpenRTB Video object for the slot given
182+
*/
183+
function video(slot) {
184+
if (slot.params.video) {
185+
return Object.assign({}, slot.params.video, {battr: slot.params.battr});
186+
}
187+
return null;
188+
}
189+
190+
/**
191+
* Unknown params are captured and sent on ext
192+
*/
193+
function ext(slot) {
194+
const ext = {};
195+
const knownParamsMap = {};
196+
KNOWN_PARAMS.forEach(value => knownParamsMap[value] = 1);
197+
Object.keys(slot.params).forEach(key => {
198+
if (!knownParamsMap[key]) {
199+
ext[key] = slot.params[key];
200+
}
201+
});
202+
return Object.keys(ext).length > 0 ? { prebid: ext } : null;
203+
}
204+
205+
/**
206+
* Sets up the renderer on the bid, for outstream bid responses.
207+
*/
208+
function outstreamRenderer(rendererOptions, outstreamExtOptions) {
209+
const renderer = Renderer.install({
210+
url: outstreamExtOptions.rendererUrl,
211+
config: {
212+
defaultOptions: outstreamExtOptions.config,
213+
rendererOptions,
214+
type: outstreamExtOptions.type
215+
},
216+
loaded: false,
217+
});
218+
renderer.setRender((bid) => {
219+
bid.renderer.push(() => {
220+
const config = bid.renderer.getConfig();
221+
new window.PulsePointOutstreamRenderer().render({
222+
adUnitCode: bid.adUnitCode,
223+
vastXml: bid.vastXml,
224+
type: config.type,
225+
defaultOptions: config.defaultOptions,
226+
rendererOptions
227+
});
228+
});
229+
});
230+
return renderer;
231+
}
232+
155233
/**
156234
* Produces an OpenRTB Native object for the slot given.
157235
*/
@@ -166,6 +244,7 @@ function nativeImpression(slot) {
166244
return {
167245
request: JSON.stringify({ assets }),
168246
ver: '1.1',
247+
battr: slot.params.battr,
169248
};
170249
}
171250
return null;
@@ -312,13 +391,50 @@ function adSize(slot) {
312391
}
313392

314393
/**
315-
* Applies GDPR parameters to request.
394+
* Handles the user level attributes and produces
395+
* an openrtb User object.
316396
*/
317-
function applyGdpr(bidderRequest, ortbRequest) {
397+
function user(bidRequest, bidderRequest) {
398+
var ext = {};
399+
if (bidderRequest) {
400+
if (bidderRequest.gdprConsent) {
401+
ext.consent = bidderRequest.gdprConsent.consentString;
402+
}
403+
}
404+
if (bidRequest) {
405+
if (bidRequest.userId) {
406+
ext.eids = [];
407+
addExternalUserId(ext.eids, bidRequest.userId.pubcid, 'pubcommon');
408+
addExternalUserId(ext.eids, bidRequest.userId.tdid, 'ttdid');
409+
addExternalUserId(ext.eids, utils.deepAccess(bidRequest.userId.digitrustid, 'data.id'), 'digitrust');
410+
addExternalUserId(ext.eids, bidRequest.userId.id5id, 'id5id');
411+
}
412+
}
413+
return { ext };
414+
}
415+
416+
/**
417+
* Produces external userid object in ortb 3.0 model.
418+
*/
419+
function addExternalUserId(eids, value, source) {
420+
if (value) {
421+
eids.push({
422+
source,
423+
uids: [{
424+
id: value
425+
}]
426+
});
427+
}
428+
}
429+
430+
/**
431+
* Produces the regulations ortb object
432+
*/
433+
function regs(bidderRequest) {
318434
if (bidderRequest && bidderRequest.gdprConsent) {
319-
ortbRequest.regs = { ext: { gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0 } };
320-
ortbRequest.user = { ext: { consent: bidderRequest.gdprConsent.consentString } };
435+
return { ext: { gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0 } };
321436
}
437+
return null;
322438
}
323439

324440
/**

modules/pulsepointBidAdapter.md

+53-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# Description
88

99
Connects to PulsePoint demand source to fetch bids.
10-
Banner, Outstream and Native formats are supported.
10+
Banner, Video and Native formats are supported.
1111
Please use ```pulsepoint``` as the bidder code.
1212
```pulseLite``` and ```pulsepointLite``` aliases also supported as well.
1313

@@ -40,5 +40,57 @@ Please use ```pulsepoint``` as the bidder code.
4040
ct: 505642
4141
}
4242
}]
43+
},{
44+
code: 'outstream-div',
45+
mediaTypes: {
46+
video: {
47+
playerSize: [640, 480],
48+
context: 'outstream'
49+
}
50+
},
51+
bids: [{
52+
bidder: 'pulsepoint',
53+
params: {
54+
cp: 512379,
55+
ct: 505642,
56+
video: {
57+
h: 300,
58+
w: 400,
59+
minduration: 1,
60+
maxduration: 210,
61+
linearity: 1,
62+
mimes: ["video/mp4", "video/ogg", "video/webm"],
63+
pos: 3
64+
}
65+
}
66+
}],
67+
renderer: {
68+
options: {
69+
text: "PulsePoint Outstream"
70+
}
71+
}
72+
},{
73+
code: 'instream',
74+
mediaTypes: {
75+
video: {
76+
playerSize: [640, 480],
77+
context: 'instream'
78+
}
79+
},
80+
bids: [{
81+
bidder: 'pulsepoint',
82+
params: {
83+
cp: 512379,
84+
ct: 694973,
85+
video: {
86+
battr: [1,3],
87+
h: 300,
88+
w: 400,
89+
minduration: 1,
90+
maxduration: 210,
91+
protocols: [2,3,5]
92+
}
93+
}
94+
}]
4395
}];
4496
```

0 commit comments

Comments
 (0)