@@ -26,28 +26,174 @@ const adapterConfig = {
26
26
} ,
27
27
28
28
/**
29
- * Function used to extract placement/adUnitCode (depending on prebid version).
29
+ * Function used to extract placement/adUnitCode (depending on prebid
30
+ * version).
30
31
*
31
32
* The extracted value will be passed to the `getAdUnitName()` for mapping into
32
33
* human friendly value.
33
34
*/
34
35
getPlacementOrAdUnitCode : function ( bid , version ) {
35
36
return version [ 0 ] === '0' ? bid . placementCode : bid . adUnitCode ;
37
+ } ,
38
+
39
+ /**
40
+ * Optional reference to Google Publisher Tag (gpt)
41
+ */
42
+ googlePublisherTag : false ,
43
+
44
+ /**
45
+ * Do not override unless instructed. Useful for testing. Allows to redefined
46
+ * the event that triggers the ad impression event.
47
+ */
48
+ wireGooglePublisherTag : function ( gpt , cb ) {
49
+ gpt . pubads ( ) . addEventListener ( 'slotRenderEnded' , function ( event ) {
50
+ cb ( event . slot ) ;
51
+ } ) ;
52
+ } ,
53
+
54
+ /**
55
+ * Map which keeps BID_WON events. Keyed by adId property.
56
+ */
57
+ prebidWinnersCache : { } ,
58
+
59
+ /**
60
+ * Map which keeps all BID_RESPONSE events. Keyed by adId property.
61
+ */
62
+ prebidBidResponsesCache : { } ,
63
+
64
+ /**
65
+ * Decides if the GPT slot contains prebid ad impression or not.
66
+ *
67
+ * When BID_WON event is emitted adid is added to prebidWinnersCache,
68
+ * then we check if prebidWinnersCache contains slot.hb_adid.
69
+ *
70
+ * This function is optional and used only when googlePublisherTag is provided.
71
+ *
72
+ * Default implementation uses slot's `hb_adid` targeting parameter.
73
+ *
74
+ * @param slot the gpt slot
75
+ */
76
+ isPrebidAdImpression : function ( slot ) {
77
+ const hbAdIdTargeting = slot . getTargeting ( 'hb_adid' ) ;
78
+ if ( hbAdIdTargeting . length > 0 ) {
79
+ const hbAdId = hbAdIdTargeting [ 0 ] ;
80
+ return typeof this . prebidWinnersCache [ hbAdId ] !== 'undefined' ;
81
+ }
82
+ return false ;
83
+ } ,
84
+
85
+ /**
86
+ * If isPrebidAdImpression decides that slot contain prebid ad impression,
87
+ * this function should return prebids highest ad impression partner for that
88
+ * slot.
89
+ *
90
+ * Default implementation uses slot's `hb_adid` targeting value to find
91
+ * highest bid response and when present then returns `bidder`.
92
+ *
93
+ * @param instanceConfig merged analytics adapter instance configuration
94
+ * @param slot the gpt slot for which the name of the highest bidder shall be
95
+ * returned
96
+ * @param version the version of the prebid.js library
97
+ */
98
+ getHighestPrebidAdImpressionPartner : function ( instanceConfig , slot , version ) {
99
+ const bid = getHighestPrebidBidResponseBySlotTargeting (
100
+ instanceConfig ,
101
+ slot ,
102
+ version
103
+ ) ;
104
+
105
+ // this is bid response event has `bidder` while bid won has bidderCode property
106
+ return bid ? bid . bidderCode || bid . bidder : null ;
107
+ } ,
108
+
109
+ /**
110
+ * If isPrebidAdImpression decides that slot contain prebid ad impression,
111
+ * this function should return prebids highest ad impression value for that
112
+ * slot.
113
+ *
114
+ * Default implementation uses slot's `hb_adid` targeting value to find
115
+ * highest bid response and when present then returns `cpm`.
116
+ *
117
+ * @param instanceConfig merged analytics adapter instance configuration
118
+ * @param slot the gpt slot for which the highest ad impression value shall be
119
+ * returned
120
+ * @param version the version of the prebid.js library
121
+ */
122
+ getHighestPrebidAdImpressionValue : function ( instanceConfig , slot , version ) {
123
+ const bid = getHighestPrebidBidResponseBySlotTargeting (
124
+ instanceConfig ,
125
+ slot ,
126
+ version
127
+ ) ;
128
+
129
+ return bid ? bid . cpm : null ;
130
+ } ,
131
+
132
+ /**
133
+ * This function should return proper ad unit name for slot given as a
134
+ * parameter. Unit names returned by this function should be meaningful, for
135
+ * example 'FOO_728x90_TOP'. The values returned shall be inline with
136
+ * `getAdUnitName`.
137
+ *
138
+ * Required when googlePublisherTag is defined.
139
+ *
140
+ * @param slot the gpt slot to translate into friendly name
141
+ * @param version the version of the prebid.js library
142
+ */
143
+ getAdUnitNameByGooglePublisherTagSlot : ( slot , version ) => {
144
+ throw 'Required when googlePublisherTag is defined.' ;
145
+ } ,
146
+
147
+ /**
148
+ * Function used to prepare and return parameters provided to rta.
149
+ * More information will be in docs given by LiveYield team.
150
+ *
151
+ * When googlePublisherTag is not provided, second parameter(slot) will always
152
+ * equal null.
153
+ *
154
+ * @param resolution the original ad impression details
155
+ * @param slot gpt slot, will be empty in pure Prebid.js-case (when
156
+ * googlePublisherTag is not provided)
157
+ * @param hbPartner the name of the highest bidding partner
158
+ * @param hbValue the value of the highest bid
159
+ * @param version version of the prebid.js library
160
+ */
161
+ postProcessResolution : ( resolution , slot , hbPartner , hbValue , version ) => {
162
+ return resolution ;
36
163
}
37
164
} ;
38
165
39
166
const cpmToMicroUSD = v => ( isNaN ( v ) ? 0 : Math . round ( v * 1000 ) ) ;
40
167
168
+ const getHighestPrebidBidResponseBySlotTargeting = function (
169
+ instanceConfig ,
170
+ slot ,
171
+ version
172
+ ) {
173
+ const hbAdIdTargeting = slot . getTargeting ( 'hb_adid' ) ;
174
+ if ( hbAdIdTargeting . length > 0 ) {
175
+ const hbAdId = hbAdIdTargeting [ 0 ] ;
176
+ return (
177
+ instanceConfig . prebidWinnersCache [ hbAdId ] ||
178
+ instanceConfig . prebidBidResponsesCache [ hbAdId ]
179
+ ) ;
180
+ }
181
+ return null ;
182
+ } ;
183
+
41
184
const liveyield = Object . assign ( adapter ( { analyticsType : 'bundle' } ) , {
42
185
track ( { eventType, args } ) {
43
186
switch ( eventType ) {
44
187
case BID_REQUESTED :
45
188
args . bids . forEach ( function ( b ) {
46
189
try {
47
- window [ adapterConfig . rtaFunctionName ] (
190
+ window [ liveyield . instanceConfig . rtaFunctionName ] (
48
191
'bidRequested' ,
49
- adapterConfig . getAdUnitName (
50
- adapterConfig . getPlacementOrAdUnitCode ( b , prebidVersion )
192
+ liveyield . instanceConfig . getAdUnitName (
193
+ liveyield . instanceConfig . getPlacementOrAdUnitCode (
194
+ b ,
195
+ prebidVersion
196
+ )
51
197
) ,
52
198
args . bidderCode
53
199
) ;
@@ -57,52 +203,82 @@ const liveyield = Object.assign(adapter({ analyticsType: 'bundle' }), {
57
203
} ) ;
58
204
break ;
59
205
case BID_RESPONSE :
206
+ liveyield . instanceConfig . prebidBidResponsesCache [ args . adId ] = args ;
60
207
var cpm = args . statusMessage === 'Bid available' ? args . cpm : null ;
61
208
try {
62
- window [ adapterConfig . rtaFunctionName ] (
209
+ window [ liveyield . instanceConfig . rtaFunctionName ] (
63
210
'addBid' ,
64
- adapterConfig . getAdUnitName (
65
- adapterConfig . getPlacementOrAdUnitCode ( args , prebidVersion )
211
+ liveyield . instanceConfig . getAdUnitName (
212
+ liveyield . instanceConfig . getPlacementOrAdUnitCode (
213
+ args ,
214
+ prebidVersion
215
+ )
66
216
) ,
67
217
args . bidder || 'unknown' ,
68
218
cpmToMicroUSD ( cpm ) ,
69
219
typeof args . bidder === 'undefined' ,
70
220
args . statusMessage !== 'Bid available'
71
- )
221
+ ) ;
72
222
} catch ( e ) {
73
223
utils . logError ( e ) ;
74
224
}
75
225
break ;
76
226
case BID_TIMEOUT :
77
- window [ adapterConfig . rtaFunctionName ] ( 'biddersTimeout' , args ) ;
227
+ window [ liveyield . instanceConfig . rtaFunctionName ] (
228
+ 'biddersTimeout' ,
229
+ args
230
+ ) ;
78
231
break ;
79
232
case BID_WON :
233
+ liveyield . instanceConfig . prebidWinnersCache [ args . adId ] = args ;
234
+ if ( liveyield . instanceConfig . googlePublisherTag ) {
235
+ break ;
236
+ }
237
+
80
238
try {
81
- const ad = adapterConfig . getAdUnitName (
82
- adapterConfig . getPlacementOrAdUnitCode ( args , prebidVersion )
239
+ const ad = liveyield . instanceConfig . getAdUnitName (
240
+ liveyield . instanceConfig . getPlacementOrAdUnitCode (
241
+ args ,
242
+ prebidVersion
243
+ )
83
244
) ;
84
245
if ( ! ad ) {
85
- utils . logError ( 'Cannot find ad by unit name: ' +
86
- adapterConfig . getAdUnitName (
87
- adapterConfig . getPlacementOrAdUnitCode ( args , prebidVersion )
88
- ) ) ;
246
+ utils . logError (
247
+ 'Cannot find ad by unit name: ' +
248
+ liveyield . instanceConfig . getAdUnitName (
249
+ liveyield . instanceConfig . getPlacementOrAdUnitCode (
250
+ args ,
251
+ prebidVersion
252
+ )
253
+ )
254
+ ) ;
89
255
break ;
90
256
}
91
257
if ( ! args . bidderCode || ! args . cpm ) {
92
258
utils . logError ( 'Bidder code or cpm is not valid' ) ;
93
259
break ;
94
260
}
95
- window [ adapterConfig . rtaFunctionName ] (
261
+ const resolution = { targetings : [ ] } ;
262
+ resolution . prebidWon = true ;
263
+ resolution . prebidPartner = args . bidderCode ;
264
+ resolution . prebidValue = cpmToMicroUSD ( parseFloat ( args . cpm ) ) ;
265
+ const resolutionToUse = liveyield . instanceConfig . postProcessResolution (
266
+ resolution ,
267
+ null ,
268
+ resolution . prebidPartner ,
269
+ resolution . prebidValue ,
270
+ prebidVersion
271
+ ) ;
272
+ window [ liveyield . instanceConfig . rtaFunctionName ] (
96
273
'resolveSlot' ,
97
- adapterConfig . getAdUnitName (
98
- adapterConfig . getPlacementOrAdUnitCode ( args , prebidVersion )
274
+ liveyield . instanceConfig . getAdUnitName (
275
+ liveyield . instanceConfig . getPlacementOrAdUnitCode (
276
+ args ,
277
+ prebidVersion
278
+ )
99
279
) ,
100
- {
101
- prebidWon : true ,
102
- prebidPartner : args . bidderCode ,
103
- prebidValue : cpmToMicroUSD ( args . cpm )
104
- }
105
- )
280
+ resolutionToUse
281
+ ) ;
106
282
} catch ( e ) {
107
283
utils . logError ( e ) ;
108
284
}
@@ -157,12 +333,25 @@ liveyield.enableAnalytics = function(config) {
157
333
utils . logError ( 'options.sessionTimezoneOffset is required' ) ;
158
334
return ;
159
335
}
160
- Object . assign ( adapterConfig , config . options ) ;
161
- if ( typeof window [ adapterConfig . rtaFunctionName ] !== 'function' ) {
162
- utils . logError ( `Function ${ adapterConfig . rtaFunctionName } is not defined.` +
163
- `Make sure that LiveYield snippet in included before the Prebid Analytics configuration.` ) ;
336
+ liveyield . instanceConfig = Object . assign (
337
+ { prebidWinnersCache : { } , prebidBidResponsesCache : { } } ,
338
+ adapterConfig ,
339
+ config . options
340
+ ) ;
341
+
342
+ if ( typeof window [ liveyield . instanceConfig . rtaFunctionName ] !== 'function' ) {
343
+ utils . logError (
344
+ `Function ${ liveyield . instanceConfig . rtaFunctionName } is not defined.` +
345
+ `Make sure that LiveYield snippet in included before the Prebid Analytics configuration.`
346
+ ) ;
164
347
return ;
165
348
}
349
+ if ( liveyield . instanceConfig . googlePublisherTag ) {
350
+ liveyield . instanceConfig . wireGooglePublisherTag (
351
+ liveyield . instanceConfig . googlePublisherTag ,
352
+ onSlotRenderEnded ( liveyield . instanceConfig )
353
+ ) ;
354
+ }
166
355
167
356
const additionalParams = {
168
357
customerTimezone : config . options . customerTimezone ,
@@ -192,18 +381,71 @@ liveyield.enableAnalytics = function(config) {
192
381
key => additionalParams [ key ] == null && delete additionalParams [ key ]
193
382
) ;
194
383
195
- window [ adapterConfig . rtaFunctionName ] (
384
+ window [ liveyield . instanceConfig . rtaFunctionName ] (
196
385
'create' ,
197
386
config . options . customerId ,
198
387
config . options . customerName ,
199
388
config . options . customerSite ,
200
389
config . options . sessionTimezoneOffset ,
201
390
additionalParams
202
391
) ;
203
-
204
392
liveyield . originEnableAnalytics ( config ) ;
205
393
} ;
206
394
395
+ const onSlotRenderEnded = function ( instanceConfig ) {
396
+ const addDfpDetails = ( resolution , slot ) => {
397
+ const responseInformation = slot . getResponseInformation ( ) ;
398
+ if ( responseInformation ) {
399
+ resolution . dfpAdvertiserId = responseInformation . advertiserId ;
400
+ resolution . dfpLineItemId = responseInformation . sourceAgnosticLineItemId ;
401
+ resolution . dfpCreativeId = responseInformation . creativeId ;
402
+ }
403
+ } ;
404
+
405
+ const addPrebidDetails = ( resolution , slot ) => {
406
+ if ( instanceConfig . isPrebidAdImpression ( slot ) ) {
407
+ resolution . prebidWon = true ;
408
+ }
409
+ const highestPrebidAdImpPartner = instanceConfig . getHighestPrebidAdImpressionPartner (
410
+ instanceConfig ,
411
+ slot ,
412
+ prebidVersion
413
+ ) ;
414
+ const highestPrebidAdImpValue = instanceConfig . getHighestPrebidAdImpressionValue (
415
+ instanceConfig ,
416
+ slot ,
417
+ prebidVersion
418
+ ) ;
419
+ if ( highestPrebidAdImpPartner ) {
420
+ resolution . prebidPartner = highestPrebidAdImpPartner ;
421
+ }
422
+ if ( highestPrebidAdImpValue ) {
423
+ resolution . prebidValue = cpmToMicroUSD (
424
+ parseFloat ( highestPrebidAdImpValue )
425
+ ) ;
426
+ }
427
+ } ;
428
+ return slot => {
429
+ const resolution = { targetings : [ ] } ;
430
+
431
+ addDfpDetails ( resolution , slot ) ;
432
+ addPrebidDetails ( resolution , slot ) ;
433
+
434
+ const resolutionToUse = instanceConfig . postProcessResolution (
435
+ resolution ,
436
+ slot ,
437
+ resolution . highestPrebidAdImpPartner ,
438
+ resolution . highestPrebidAdImpValue ,
439
+ prebidVersion
440
+ ) ;
441
+ window [ instanceConfig . rtaFunctionName ] (
442
+ 'resolveSlot' ,
443
+ instanceConfig . getAdUnitNameByGooglePublisherTagSlot ( slot , prebidVersion ) ,
444
+ resolutionToUse
445
+ ) ;
446
+ } ;
447
+ } ;
448
+
207
449
adapterManager . registerAnalyticsAdapter ( {
208
450
adapter : liveyield ,
209
451
code : 'liveyield'
0 commit comments