Skip to content

Commit db2fdfa

Browse files
SuprPhatAnonjaiminpanchal27
authored andcommitted
SomoAudience Adapter Enhancements (#2986)
* Support additional targeting options, support video, support GDPR, and implement usersync pixels More work cleaning up tests and making sure this stuff actually worked Documentation Updates * Trying to fix Mac-only errors * Squashing more bugs that cropped up * Added additional parameter for userip * Delete package-lock.json * Fix accidently deleting a file
1 parent 014fffe commit db2fdfa

File tree

3 files changed

+636
-109
lines changed

3 files changed

+636
-109
lines changed

modules/somoaudienceBidAdapter.js

Lines changed: 168 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
1-
import {getTopWindowReferrer, getTopWindowLocation} from 'src/utils';
1+
import * as utils from 'src/utils';
22
import { registerBidder } from 'src/adapters/bidderFactory';
3+
import includes from 'core-js/library/fn/array/includes';
4+
import {BANNER, VIDEO} from 'src/mediaTypes';
5+
6+
const VIDEO_TARGETING = ['mimes', 'minduration', 'maxduration', 'protocols',
7+
'startdelay', 'linearity', 'skip', 'delivery',
8+
'pos', 'api', 'ext', 'battr'];
9+
const BANNER_TARGETING = ['battr', 'btype', 'pos', 'mimes', 'ext'];
10+
11+
const SITE_TARGETING = ['name', 'domain', 'cat', 'keywords', 'content']
12+
const APP_TARGETING = ['name', 'bundle', 'domain', 'storeUrl', 'cat', 'ver', 'keywords', 'content']
313

414
export const spec = {
515

616
code: 'somoaudience',
717

18+
supportedMediaTypes: [BANNER, VIDEO],
819
aliases: ['somo'],
920

1021
isBidRequestValid: bid => (
1122
!!(bid && bid.params && bid.params.placementId)
1223
),
1324

14-
buildRequests: function(bidRequests) {
25+
buildRequests: function(bidRequests, bidderRequest) {
1526
return bidRequests.map(bidRequest => {
16-
let da = openRtbRequest(bidRequest);
27+
let da = openRtbRequest(bidRequest, bidderRequest);
1728
if (window.top1 && window.top1.realvu_aa) {
1829
let a = window.top1.realvu_aa.check({
1930
unit_id: bidRequest.adUnitCode,
@@ -48,51 +59,135 @@ export const spec = {
4859

4960
interpretResponse(response, request) {
5061
return bidResponseAvailable(request, response);
62+
},
63+
64+
getUserSyncs: (syncOptions, serverResponses, gdprConsent) => {
65+
const syncs = [];
66+
var url = '//publisher-east.mobileadtrading.com/usersync';
67+
68+
if (syncOptions.pixelEnabled) {
69+
if (gdprConsent && typeof gdprConsent.consentString === 'string') {
70+
// add 'gdpr' only if 'gdprApplies' is defined
71+
if (typeof gdprConsent.gdprApplies === 'boolean') {
72+
url += `?gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`;
73+
}
74+
}
75+
syncs.push({
76+
type: 'image',
77+
url: url
78+
});
79+
}
80+
return syncs;
5181
}
5282
};
5383

5484
function bidResponseAvailable(bidRequest, bidResponse) {
5585
let bidResponses = [];
56-
let bidId = 1;
57-
if (typeof bidRequest != 'undefined' && typeof bidRequest.bidRequest != 'undefined' && typeof bidRequest.bidRequest.bidId != 'undefined') {
58-
bidId = bidRequest.bidRequest.bidId;
59-
}
6086
if (bidResponse.body) {
6187
let bidData = bidResponse.body.seatbid[0].bid[0];
6288
const bid = {
63-
requestId: bidId,
89+
requestId: bidData.impid,
6490
cpm: bidData.price,
6591
width: bidData.w,
6692
height: bidData.h,
6793
ad: bidData.adm,
6894
ttl: 360,
6995
creativeId: bidData.crid,
70-
adId: bidId,
96+
adId: bidData.impid,
7197
netRevenue: false,
7298
currency: 'USD',
7399
};
100+
if (isVideo(bidRequest.bidRequest)) {
101+
bid.vastXml = bidData.adm;
102+
bid.mediaType = 'video';
103+
} else {
104+
bid.ad = bidData.adm;
105+
bid.mediaType = 'banner';
106+
}
74107
bidResponses.push(bid);
75108
}
76109
return bidResponses;
77110
}
78111

79-
function openRtbRequest(bidRequest) {
80-
return {
112+
function openRtbRequest(bidRequest, bidderRequest) {
113+
var openRtbRequest = {
81114
id: bidRequest.bidderRequestId,
82115
imp: [openRtbImpression(bidRequest)],
83116
at: 1,
84117
tmax: 400,
85118
site: openRtbSite(bidRequest),
86119
app: openRtbApp(bidRequest),
87-
device: openRtbDevice()
120+
device: openRtbDevice(),
121+
bcat: openRtbBCat(bidRequest),
122+
badv: openRtbBAdv(bidRequest),
123+
ext: {
124+
prebid: '$prebid.version$',
125+
},
88126
};
127+
if (bidderRequest != undefined) {
128+
openRtbRequest = populateOpenRtbGdpr(bidderRequest.gdprConsent, openRtbRequest);
129+
}
130+
131+
return openRtbRequest;
132+
}
133+
134+
function populateOpenRtbGdpr(gdpr, bidRequest) {
135+
if (gdpr && bidRequest && 'gdprApplies' in gdpr) {
136+
if (!('reqs' in bidRequest)) {
137+
bidRequest.reqs = {};
138+
}
139+
if (!('ext' in bidRequest.reqs)) {
140+
bidRequest.reqs.ext = {};
141+
}
142+
bidRequest.reqs.ext.gdpr = gdpr.gdprApplies;
143+
144+
if ('consentString' in gdpr) {
145+
if (!('user' in bidRequest)) {
146+
bidRequest.user = {};
147+
}
148+
if (!('ext' in bidRequest.user)) {
149+
bidRequest.user.ext = {};
150+
}
151+
bidRequest.user.ext.consent = gdpr.consentString;
152+
}
153+
}
154+
155+
return bidRequest;
89156
}
90157

91158
function openRtbImpression(bidRequest) {
92-
return {
93-
id: bidRequest.bidId,
94-
banner: {}
159+
const imp = {
160+
'id': bidRequest.bidId,
161+
bidfloor: bidRequest.params.bidfloor || 0,
95162
};
163+
if (isVideo(bidRequest)) {
164+
imp.video = {};
165+
if (bidRequest.sizes) {
166+
const sizes = getSizes(bidRequest.sizes);
167+
imp.video.w = sizes[0];
168+
imp.video.h = sizes[1];
169+
}
170+
if (bidRequest.params.video) {
171+
Object.keys(bidRequest.params.video)
172+
.filter(param => includes(VIDEO_TARGETING, param))
173+
.forEach(param => imp.video[param] = bidRequest.params.video[param]);
174+
}
175+
} else {
176+
imp.banner = {
177+
topframe: 0
178+
};
179+
if (bidRequest.sizes) {
180+
const sizes = getSizes(bidRequest.sizes);
181+
imp.banner.w = sizes[0];
182+
imp.banner.h = sizes[1];
183+
}
184+
if (bidRequest.params.banner) {
185+
Object.keys(bidRequest.params.banner)
186+
.filter(param => includes(BANNER_TARGETING, param))
187+
.forEach(param => imp.banner[param] = bidRequest.params.banner[param]);
188+
}
189+
}
190+
return imp;
96191
}
97192

98193
function isApp(bidRequest) {
@@ -105,37 +200,83 @@ function isApp(bidRequest) {
105200

106201
function openRtbSite(bidRequest) {
107202
if (!isApp(bidRequest)) {
108-
const pageUrl = getTopWindowLocation().href;
109-
const domain = getTopWindowLocation().hostname;
110-
return {
111-
ref: getTopWindowReferrer(),
112-
page: pageUrl,
113-
domain: domain
203+
const site = {
204+
ref: utils.getTopWindowReferrer(),
205+
page: utils.getTopWindowLocation().href
206+
};
207+
if (bidRequest.params.site) {
208+
Object.keys(bidRequest.params.site)
209+
.filter(param => includes(SITE_TARGETING, param))
210+
.forEach(param => site[param] = bidRequest.params.site[param]);
211+
}
212+
if (site.domain == undefined) {
213+
site.domain = utils.getTopWindowLocation().hostname;
114214
}
215+
216+
return site;
115217
} else {
116218
return null;
117219
}
118220
}
119221

120222
function openRtbApp(bidRequest) {
121223
if (isApp(bidRequest)) {
122-
const appParams = bidRequest.params.app;
123-
return {
124-
bundle: appParams.bundle ? appParams.bundle : null,
125-
storeurl: appParams.storeUrl ? appParams.storeUrl : null,
126-
domain: appParams.domain ? appParams.domain : null,
127-
name: appParams.name ? appParams.name : null,
224+
const app = {
225+
128226
}
227+
Object.keys(bidRequest.params.app)
228+
.filter(param => includes(APP_TARGETING, param))
229+
.forEach(param => app[param] = bidRequest.params.app[param]);
230+
231+
return app;
129232
} else {
130233
return null;
131234
}
132235
}
133236

134237
function openRtbDevice() {
135238
return {
239+
ip: 'check',
136240
ua: navigator.userAgent,
137241
language: (navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage),
138242
};
139243
}
140244

245+
function openRtbBCat(bidRequest) {
246+
if (utils.isArray(bidRequest.params.bcat)) {
247+
return bidRequest.params.bcat;
248+
}
249+
return [];
250+
}
251+
252+
function openRtbBAdv(bidRequest) {
253+
if (utils.isArray(bidRequest.params.badv)) {
254+
return bidRequest.params.badv;
255+
}
256+
return [];
257+
}
258+
259+
function isVideo (format) {
260+
return utils.deepAccess(format, 'mediaTypes.video') || format.mediaType == 'video';
261+
}
262+
263+
/* Turn bid request sizes into compatible format */
264+
function getSizes(requestSizes) {
265+
let width = 0;
266+
let height = 0;
267+
if (utils.isArray(requestSizes) && requestSizes.length === 2 &&
268+
!utils.isArray(requestSizes[0])) {
269+
width = parseInt(requestSizes[0], 10);
270+
height = parseInt(requestSizes[1], 10);
271+
} else if (typeof requestSizes === 'object') {
272+
for (let i = 0; i < requestSizes.length; i++) {
273+
let size = requestSizes[i];
274+
width = parseInt(size[0], 10);
275+
height = parseInt(size[1], 10);
276+
break;
277+
}
278+
}
279+
return [width, height];
280+
}
281+
141282
registerBidder(spec);

modules/somoaudienceBidAdapter.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
# Description
77
Connects to Somo Audience demand source.
88
Please use ```somoaudience``` as the bidder code.
9+
10+
For video integration, somoAudience returns content as vastXML and requires the publisher to define the cache url in config passed to Prebid for it to be valid in the auction
911
# Test Site Parameters
1012
```
1113
var adUnits = [{

0 commit comments

Comments
 (0)