Skip to content

Commit 388ddee

Browse files
alex-ylbkippsterr
andauthored
Yieldlab Bid Adapter: add support for native mediatype (prebid#7609)
* YL-3989: Accept NATIVE yieldprobe response (#2) * YL-3989: Accept NATIVE response * Fix: 'utils' is not defined no-undef * trigger GitHub actions * Add multi-format example to the Yieldlab bidder documentation * Reformat code * Fix: Object doesn't support 'find' Object doesn't support property or method 'find' in IE 11 * trigger GitHub actions * Chore:Replace `filter` by `find` from ..array/find.js * Fix typo Co-authored-by: Christoph <29540638+kippsterr@users.noreply.github.com>
1 parent 199eb7d commit 388ddee

3 files changed

Lines changed: 213 additions & 58 deletions

File tree

modules/yieldlabBidAdapter.js

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { _each, isPlainObject, isArray, deepAccess } from '../src/utils.js';
22
import { registerBidder } from '../src/adapters/bidderFactory.js'
33
import find from 'core-js-pure/features/array/find.js'
4-
import { VIDEO, BANNER } from '../src/mediaTypes.js'
4+
import { VIDEO, BANNER, NATIVE } from '../src/mediaTypes.js'
55
import { Renderer } from '../src/Renderer.js'
66
import { config } from '../src/config.js';
77

@@ -15,7 +15,7 @@ const GVLID = 70
1515
export const spec = {
1616
code: BIDDER_CODE,
1717
gvlid: GVLID,
18-
supportedMediaTypes: [VIDEO, BANNER],
18+
supportedMediaTypes: [VIDEO, BANNER, NATIVE],
1919

2020
isBidRequestValid: function (bid) {
2121
if (bid && bid.params && bid.params.adslotId && bid.params.supplyId) {
@@ -149,6 +149,27 @@ export const spec = {
149149
}
150150
}
151151

152+
if (isNative(bidRequest, adType)) {
153+
const url = `${ENDPOINT}/d/${matchedBid.id}/${bidRequest.params.supplyId}/?ts=${timestamp}${extId}${gdprApplies}${gdprConsent}${pvId}`
154+
bidResponse.adUrl = url
155+
bidResponse.mediaType = NATIVE
156+
const nativeImageAssetObj = find(matchedBid.native.assets, e => e.id === 2)
157+
const nativeImageAsset = nativeImageAssetObj ? nativeImageAssetObj.img : {url: '', w: 0, h: 0};
158+
const nativeTitleAsset = find(matchedBid.native.assets, e => e.id === 1)
159+
const nativeBodyAsset = find(matchedBid.native.assets, e => e.id === 3)
160+
bidResponse.native = {
161+
title: nativeTitleAsset ? nativeTitleAsset.title.text : '',
162+
body: nativeBodyAsset ? nativeBodyAsset.data.value : '',
163+
image: {
164+
url: nativeImageAsset.url,
165+
width: nativeImageAsset.w,
166+
height: nativeImageAsset.h,
167+
},
168+
clickUrl: matchedBid.native.link.url,
169+
impressionTrackers: matchedBid.native.imptrackers,
170+
};
171+
}
172+
152173
bidResponses.push(bidResponse)
153174
}
154175
})
@@ -162,16 +183,26 @@ export const spec = {
162183
* @param {String} adtype
163184
* @returns {Boolean}
164185
*/
165-
function isVideo (format, adtype) {
186+
function isVideo(format, adtype) {
166187
return deepAccess(format, 'mediaTypes.video') && adtype.toLowerCase() === 'video'
167188
}
168189

190+
/**
191+
* Is this a native format?
192+
* @param {Object} format
193+
* @param {String} adtype
194+
* @returns {Boolean}
195+
*/
196+
function isNative(format, adtype) {
197+
return deepAccess(format, 'mediaTypes.native') && adtype.toLowerCase() === 'native'
198+
}
199+
169200
/**
170201
* Is this an outstream context?
171202
* @param {Object} format
172203
* @returns {Boolean}
173204
*/
174-
function isOutstream (format) {
205+
function isOutstream(format) {
175206
let context = deepAccess(format, 'mediaTypes.video.context')
176207
return (context === 'outstream')
177208
}
@@ -181,7 +212,7 @@ function isOutstream (format) {
181212
* @param {Object} format
182213
* @returns {Array}
183214
*/
184-
function getPlayerSize (format) {
215+
function getPlayerSize(format) {
185216
let playerSize = deepAccess(format, 'mediaTypes.video.playerSize')
186217
return (playerSize && isArray(playerSize[0])) ? playerSize[0] : playerSize
187218
}
@@ -191,7 +222,7 @@ function getPlayerSize (format) {
191222
* @param {String} size
192223
* @returns {Array}
193224
*/
194-
function parseSize (size) {
225+
function parseSize(size) {
195226
return size.split('x').map(Number)
196227
}
197228

@@ -200,7 +231,7 @@ function parseSize (size) {
200231
* @param {Array} eids
201232
* @returns {String}
202233
*/
203-
function createUserIdString (eids) {
234+
function createUserIdString(eids) {
204235
let str = []
205236
for (let i = 0; i < eids.length; i++) {
206237
str.push(eids[i].source + ':' + eids[i].uids[0].id)
@@ -213,7 +244,7 @@ function createUserIdString (eids) {
213244
* @param {Object} obj
214245
* @returns {String}
215246
*/
216-
function createQueryString (obj) {
247+
function createQueryString(obj) {
217248
let str = []
218249
for (var p in obj) {
219250
if (obj.hasOwnProperty(p)) {
@@ -233,7 +264,7 @@ function createQueryString (obj) {
233264
* @param {Object} obj
234265
* @returns {String}
235266
*/
236-
function createTargetingString (obj) {
267+
function createTargetingString(obj) {
237268
let str = []
238269
for (var p in obj) {
239270
if (obj.hasOwnProperty(p)) {
@@ -250,7 +281,7 @@ function createTargetingString (obj) {
250281
* @param {Object} schain
251282
* @returns {String}
252283
*/
253-
function createSchainString (schain) {
284+
function createSchainString(schain) {
254285
const ver = schain.ver || ''
255286
const complete = (schain.complete === 1 || schain.complete === 0) ? schain.complete : ''
256287
const keys = ['asi', 'sid', 'hp', 'rid', 'name', 'domain', 'ext']

modules/yieldlabBidAdapter.md

Lines changed: 91 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -11,53 +11,96 @@ Maintainer: solutions@yieldlab.de
1111
Module that connects to Yieldlab's demand sources
1212

1313
# Test Parameters
14+
15+
```javascript
16+
const adUnits = [
17+
{
18+
code: 'banner',
19+
sizes: [ [ 728, 90 ] ],
20+
bids: [{
21+
bidder: 'yieldlab',
22+
params: {
23+
adslotId: '5220336',
24+
supplyId: '1381604',
25+
targeting: {
26+
key1: 'value1',
27+
key2: 'value2'
28+
},
29+
extId: 'abc',
30+
iabContent: {
31+
id: 'some_id',
32+
episode: '1',
33+
title: 'some title',
34+
series: 'some series',
35+
season: 's1',
36+
artist: 'John Doe',
37+
genre: 'some genre',
38+
isrc: 'CC-XXX-YY-NNNNN',
39+
url: 'http://foo_url.de',
40+
cat: [ 'IAB1-1', 'IAB1-2', 'IAB2-10' ],
41+
context: '7',
42+
keywords: ['k1', 'k2'],
43+
live: '0'
44+
}
45+
}
46+
}]
47+
},
48+
{
49+
code: 'video',
50+
sizes: [ [ 640, 480 ] ],
51+
mediaTypes: {
52+
video: {
53+
context: 'instream' // or 'outstream'
54+
}
55+
},
56+
bids: [{
57+
bidder: 'yieldlab',
58+
params: {
59+
adslotId: '5220339',
60+
supplyId: '1381604'
61+
}
62+
}]
63+
},
64+
{
65+
code: 'native',
66+
mediaTypes: {
67+
native: {
68+
// native config
69+
}
70+
},
71+
bids: [{
72+
bidder: 'yieldlab',
73+
params: {
74+
adslotId: '5220339',
75+
supplyId: '1381604'
76+
}
77+
}]
78+
}
79+
];
1480
```
15-
var adUnits = [
16-
{
17-
code: "banner",
18-
sizes: [[728, 90]],
19-
bids: [{
20-
bidder: "yieldlab",
21-
params: {
22-
adslotId: "5220336",
23-
supplyId: "1381604",
24-
targeting: {
25-
key1: "value1",
26-
key2: "value2"
27-
},
28-
extId: "abc",
29-
iabContent: {
30-
id: "some_id",
31-
episode: "1",
32-
title: "some title",
33-
series: "some series",
34-
season: "s1",
35-
artist: "John Doe",
36-
genre: "some genre",
37-
isrc: "CC-XXX-YY-NNNNN",
38-
url: "http://foo_url.de",
39-
cat: ["IAB1-1", "IAB1-2", "IAB2-10"],
40-
context: "7",
41-
keywords: ["k1", "k2"],
42-
live: "0"
43-
}
44-
}
45-
}]
46-
}, {
47-
code: "video",
48-
sizes: [[640, 480]],
49-
mediaTypes: {
50-
video: {
51-
context: "instream" // or "outstream"
52-
}
53-
},
54-
bids: [{
55-
bidder: "yieldlab",
56-
params: {
57-
adslotId: "5220339",
58-
supplyId: "1381604"
59-
}
60-
}]
61-
}
62-
];
81+
82+
# Multi-Format Setup
83+
84+
A general overview of how to set up multi-format ads can be found in the offical Prebid.js docs. See: [show multi-format ads](https://docs.prebid.org/dev-docs/show-multi-format-ads.html)
85+
86+
When setting up multi-format ads with Yieldlab make sure to always add at least one eligible Adslot per given media type in the ad unit configuration.
87+
88+
```javascript
89+
const adUnit = {
90+
code: 'multi-format-adslot',
91+
mediaTypes: {
92+
banner: {
93+
sizes: [ [ 728, 90 ] ]
94+
},
95+
native: {
96+
// native config
97+
}
98+
},
99+
bids: [
100+
// banner Adslot
101+
{ bidder: 'yieldlab', params: { adslotId: '1234', supplyId: '42' } },
102+
// native Adslot
103+
{ bidder: 'yieldlab', params: { adslotId: '2345', supplyId: '42' } }
104+
]
105+
};
63106
```

test/spec/modules/yieldlabBidAdapter_spec.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ const VIDEO_REQUEST = Object.assign({}, REQUEST, {
7373
}
7474
})
7575

76+
const NATIVE_REQUEST = Object.assign({}, REQUEST, {
77+
'mediaTypes': {
78+
'native': { }
79+
}
80+
})
81+
7682
const RESPONSE = {
7783
advertiser: 'yieldlab',
7884
curl: 'https://www.yieldlab.de',
@@ -84,6 +90,42 @@ const RESPONSE = {
8490
adtype: 'BANNER'
8591
}
8692

93+
const NATIVE_RESPONSE = Object.assign({}, RESPONSE, {
94+
'adtype': 'NATIVE',
95+
'native': {
96+
'link': {
97+
'url': 'https://www.yieldlab.de'
98+
},
99+
'assets': [
100+
{
101+
'id': 1,
102+
'title': {
103+
'text': 'This is a great headline'
104+
}
105+
},
106+
{
107+
'id': 2,
108+
'img': {
109+
'url': 'https://localhost:8080/yl-logo100x100.jpg',
110+
'w': 100,
111+
'h': 100
112+
}
113+
},
114+
{
115+
'id': 3,
116+
'data': {
117+
'value': 'Native body value'
118+
}
119+
}
120+
],
121+
'imptrackers': [
122+
'http://localhost:8080/ve?d=ODE9ZSY2MTI1MjAzNjMzMzYxPXN0JjA0NWUwZDk0NTY5Yi05M2FiLWUwZTQtOWFjNy1hYWY0MzFiZj1kaXQmMj12',
123+
'http://localhost:8080/md/1111/9efa4e76-2030-4f04-bb9f-322541f8d611?mdata=false&pvid=false&ids=x:1',
124+
'http://localhost:8080/imp?s=13216&d=2171514&a=12548955&ts=1633363025216&tid=fb134faa-7ca9-4e0e-ba39-b96549d0e540&l=0'
125+
]
126+
}
127+
})
128+
87129
const VIDEO_RESPONSE = Object.assign({}, RESPONSE, {
88130
'adtype': 'VIDEO'
89131
})
@@ -297,6 +339,45 @@ describe('yieldlabBidAdapter', function () {
297339
expect(result[0].vastUrl).to.include('&id=abc')
298340
})
299341

342+
it('should add adUrl and native assets when type is Native', function () {
343+
const result = spec.interpretResponse({body: [NATIVE_RESPONSE]}, {validBidRequests: [NATIVE_REQUEST], queryParams: REQPARAMS})
344+
345+
expect(result[0].requestId).to.equal('2d925f27f5079f')
346+
expect(result[0].cpm).to.equal(0.01)
347+
expect(result[0].mediaType).to.equal('native')
348+
expect(result[0].adUrl).to.include('https://ad.yieldlab.net/d/1111/2222/?ts=')
349+
expect(result[0].native.title).to.equal('This is a great headline')
350+
expect(result[0].native.body).to.equal('Native body value')
351+
expect(result[0].native.image.url).to.equal('https://localhost:8080/yl-logo100x100.jpg')
352+
expect(result[0].native.image.width).to.equal(100)
353+
expect(result[0].native.image.height).to.equal(100)
354+
expect(result[0].native.clickUrl).to.equal('https://www.yieldlab.de')
355+
expect(result[0].native.impressionTrackers.length).to.equal(3)
356+
})
357+
358+
it('should add adUrl and default native assets when type is Native', function () {
359+
const NATIVE_RESPONSE_2 = Object.assign({}, NATIVE_RESPONSE, {
360+
'native': {
361+
'link': {
362+
'url': 'https://www.yieldlab.de'
363+
},
364+
'assets': [],
365+
'imptrackers': []
366+
}
367+
})
368+
const result = spec.interpretResponse({body: [NATIVE_RESPONSE_2]}, {validBidRequests: [NATIVE_REQUEST], queryParams: REQPARAMS})
369+
370+
expect(result[0].requestId).to.equal('2d925f27f5079f')
371+
expect(result[0].cpm).to.equal(0.01)
372+
expect(result[0].mediaType).to.equal('native')
373+
expect(result[0].adUrl).to.include('https://ad.yieldlab.net/d/1111/2222/?ts=')
374+
expect(result[0].native.title).to.equal('')
375+
expect(result[0].native.body).to.equal('')
376+
expect(result[0].native.image.url).to.equal('')
377+
expect(result[0].native.image.width).to.equal(0)
378+
expect(result[0].native.image.height).to.equal(0)
379+
})
380+
300381
it('should append gdpr parameters to vastUrl', function () {
301382
const result = spec.interpretResponse({body: [VIDEO_RESPONSE]}, {validBidRequests: [VIDEO_REQUEST], queryParams: REQPARAMS_GDPR})
302383

0 commit comments

Comments
 (0)