Skip to content

Bid Viewability Module #6206

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 86 commits into from
Feb 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
33762d1
added support for pubcommon, digitrust, id5id
pm-harshad-mane Sep 12, 2019
0722354
added support for IdentityLink
pm-harshad-mane Sep 13, 2019
f2c32c0
changed the source for id5
pm-harshad-mane Sep 13, 2019
37163d1
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Sep 13, 2019
eaed987
added unit test cases
pm-harshad-mane Sep 13, 2019
602ee7e
changed source param for identityLink
pm-harshad-mane Sep 16, 2019
b6fcd36
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Sep 23, 2019
58381f3
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Sep 26, 2019
c9fb11b
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Oct 10, 2019
8ece7fd
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Oct 16, 2019
28d12a0
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Oct 16, 2019
05a55e1
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Oct 31, 2019
e8b10d5
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Nov 5, 2019
870085f
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Nov 12, 2019
844ce4e
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Nov 12, 2019
704eca3
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Nov 13, 2019
2565cb9
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Dec 4, 2019
1d75bd4
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Dec 4, 2019
6adde1e
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Dec 6, 2019
477c98a
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Dec 9, 2019
cef5422
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Dec 10, 2019
c110a7d
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Jan 9, 2020
e8fb062
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Feb 5, 2020
d77cd71
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Feb 17, 2020
817ce3f
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Feb 24, 2020
cda825e
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Feb 26, 2020
f34a3ec
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Feb 27, 2020
f106dc8
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Mar 4, 2020
1f6937e
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Mar 6, 2020
06ffe84
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Mar 6, 2020
5448ceb
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Mar 6, 2020
e9b90fe
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Mar 11, 2020
a7a1d12
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Mar 11, 2020
30b72df
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Mar 26, 2020
76adbc9
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Mar 30, 2020
50e13bc
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Mar 30, 2020
a1c7ca1
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Mar 30, 2020
96fbadc
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Apr 1, 2020
4b026e2
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Apr 9, 2020
38740bc
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Apr 10, 2020
9daf778
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Apr 20, 2020
eff8828
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Apr 21, 2020
ede95de
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Apr 21, 2020
c98f1a1
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Apr 23, 2020
312da6d
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane May 18, 2020
d92972c
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Jun 1, 2020
fd4fb2e
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Jun 26, 2020
e551136
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Jun 30, 2020
cfdca3c
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Jul 7, 2020
22505ff
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Jul 28, 2020
795a54a
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Aug 10, 2020
433c98b
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Sep 3, 2020
a0521ac
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Sep 24, 2020
635fe74
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Sep 25, 2020
2759212
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Oct 12, 2020
84737d8
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Dec 2, 2020
df5fada
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Dec 2, 2020
9ab7840
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Dec 2, 2020
ed4b566
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Jan 8, 2021
f57d220
Merge remote-tracking branch 'upstream/master'
pm-harshad-mane Jan 20, 2021
4229ba1
introducing a new event, bidViewable
pm-harshad-mane Jan 21, 2021
144915d
new module: bidViewability
pm-harshad-mane Jan 21, 2021
eb87255
Rename bidviewability.md to bidViewability.md
pm-harshad-mane Jan 21, 2021
f07d6ab
indentation
pm-harshad-mane Jan 21, 2021
8b2be41
using utils.triggerPixel to fire pixel
pm-harshad-mane Jan 25, 2021
4fe5a9a
split the code in smaller functions
pm-harshad-mane Jan 25, 2021
0782e15
adding unit test cases
pm-harshad-mane Jan 25, 2021
18abcb2
avoiding return
pm-harshad-mane Jan 25, 2021
18d2166
a mremoved white space
pm-harshad-mane Jan 25, 2021
f46a002
a minor chnage in function name and args
pm-harshad-mane Jan 25, 2021
f71742d
lots of unit test cases
pm-harshad-mane Jan 25, 2021
e5bff7d
added support to pass GDPR and USP params in vurls
pm-harshad-mane Jan 25, 2021
f6d55ef
removed log
pm-harshad-mane Jan 25, 2021
a41b9cb
IE find fix
pm-harshad-mane Jan 25, 2021
7e77c10
Updated readme
pm-harshad-mane Jan 26, 2021
9b0ce1b
correction
pm-harshad-mane Jan 26, 2021
36bc67d
added some details in md and fixed typo in function name
pm-harshad-mane Jan 28, 2021
c0e7273
added adapterManager.callBidViewableBidder method
pm-harshad-mane Jan 29, 2021
20ae056
added unit test cases for bidder.onBidViewable trigger
pm-harshad-mane Jan 29, 2021
25fcf90
updated md file for bidder.onBidViewable
pm-harshad-mane Jan 29, 2021
886423a
spec for callBidViewableBidder / bidder.onBidViewable
pm-harshad-mane Jan 29, 2021
3a20584
using bidder instead of bidderCode
pm-harshad-mane Jan 29, 2021
5ed61e6
add ? in URLs if not present
pm-harshad-mane Feb 3, 2021
f50b64e
Merge remote-tracking branch 'upstream/master' into imp_viewable
pm-harshad-mane Feb 3, 2021
ad2e8f8
added module-config.enabled flag
pm-harshad-mane Feb 3, 2021
3850fd3
indent
pm-harshad-mane Feb 3, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions modules/bidViewability.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// This module, when included, will trigger a BID_VIEWABLE event which can be consumed by Bidders and Analytics adapters
// GPT API is used to find when a bid is viewable, https://developers.google.com/publisher-tag/reference#googletag.events.impressionviewableevent
// Does not work with other than GPT integration

import { config } from '../src/config.js';
import * as events from '../src/events.js';
import { EVENTS } from '../src/constants.json';
import { logWarn, isFn, triggerPixel } from '../src/utils.js';
import { getGlobal } from '../src/prebidGlobal.js';
import adapterManager, { gdprDataHandler, uspDataHandler } from '../src/adapterManager.js';
import find from 'core-js-pure/features/array/find.js';

const MODULE_NAME = 'bidViewability';
const CONFIG_ENABLED = 'enabled';
const CONFIG_FIRE_PIXELS = 'firePixels';
const CONFIG_CUSTOM_MATCH = 'customMatchFunction';
const BID_VURL_ARRAY = 'vurls';
const GPT_IMPRESSION_VIEWABLE_EVENT = 'impressionViewable';

export let isBidAdUnitCodeMatchingSlot = (bid, slot) => {
return (slot.getAdUnitPath() === bid.adUnitCode || slot.getSlotElementId() === bid.adUnitCode);
}

export let getMatchingWinningBidForGPTSlot = (globalModuleConfig, slot) => {
return find(getGlobal().getAllWinningBids(),
// supports custom match function from config
bid => isFn(globalModuleConfig[CONFIG_CUSTOM_MATCH])
? globalModuleConfig[CONFIG_CUSTOM_MATCH](bid, slot)
: isBidAdUnitCodeMatchingSlot(bid, slot)
) || null;
};

export let fireViewabilityPixels = (globalModuleConfig, bid) => {
if (globalModuleConfig[CONFIG_FIRE_PIXELS] === true && bid.hasOwnProperty(BID_VURL_ARRAY)) {
let queryParams = {};

const gdprConsent = gdprDataHandler.getConsentData();
if (gdprConsent) {
if (typeof gdprConsent.gdprApplies === 'boolean') { queryParams.gdpr = Number(gdprConsent.gdprApplies); }
if (gdprConsent.consentString) { queryParams.gdpr_consent = gdprConsent.consentString; }
if (gdprConsent.addtlConsent) { queryParams.addtl_consent = gdprConsent.addtlConsent; }
}

const uspConsent = uspDataHandler.getConsentData();
if (uspConsent) { queryParams.us_privacy = uspConsent; }

bid[BID_VURL_ARRAY].forEach(url => {
// add '?' if not present in URL
if (Object.keys(queryParams).length > 0 && url.indexOf('?') === -1) {
url += '?';
}
// append all query params, `&key=urlEncoded(value)`
url += Object.keys(queryParams).reduce((prev, key) => prev += `&${key}=${encodeURIComponent(queryParams[key])}`, '');
triggerPixel(url)
});
}
};

export let logWinningBidNotFound = (slot) => {
logWarn(`bid details could not be found for ${slot.getSlotElementId()}, probable reasons: a non-prebid bid is served OR check the prebid.AdUnit.code to GPT.AdSlot relation.`);
};

export let impressionViewableHandler = (globalModuleConfig, slot, event) => {
let respectiveBid = getMatchingWinningBidForGPTSlot(globalModuleConfig, slot);
if (respectiveBid === null) {
logWinningBidNotFound(slot);
} else {
// if config is enabled AND VURL array is present then execute each pixel
fireViewabilityPixels(globalModuleConfig, respectiveBid);
// trigger respective bidder's onBidViewable handler
adapterManager.callBidViewableBidder(respectiveBid.bidder, respectiveBid);
// emit the BID_VIEWABLE event with bid details, this event can be consumed by bidders and analytics pixels
events.emit(EVENTS.BID_VIEWABLE, respectiveBid);
}
};

export let init = () => {
events.on(EVENTS.AUCTION_INIT, () => {
// read the config for the module
const globalModuleConfig = config.getConfig(MODULE_NAME) || {};
// do nothing if module-config.enabled is not set to true
// this way we are adding a way for bidders to know (using pbjs.getConfig('bidViewability').enabled === true) whether this module is added in build and is enabled
if (globalModuleConfig[CONFIG_ENABLED] !== true) {
return;
}
// add the GPT event listener
window.googletag = window.googletag || {};
window.googletag.cmd = window.googletag.cmd || [];
window.googletag.cmd.push(() => {
window.googletag.pubads().addEventListener(GPT_IMPRESSION_VIEWABLE_EVENT, function(event) {
impressionViewableHandler(globalModuleConfig, event.slot, event);
});
});
});
}

init()
49 changes: 49 additions & 0 deletions modules/bidViewability.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Overview

Module Name: bidViewability

Purpose: Track when a bid is viewable

Maintainer: [email protected]

# Description
- This module, when included, will trigger a BID_VIEWABLE event which can be consumed by Analytics adapters, bidders will need to implement `onBidViewable` method to capture this event
- Bidderes can check if this module is part of the final build and whether it is enabled or not by accessing ```pbjs.getConfig('bidViewability')```
- GPT API is used to find when a bid is viewable, https://developers.google.com/publisher-tag/reference#googletag.events.impressionviewableevent . This event is fired when an impression becomes viewable, according to the Active View criteria.
Refer: https://support.google.com/admanager/answer/4524488
- The module does not work with adserver other than GAM with GPT integration
- Logic used to find a matching pbjs-bid for a GPT slot is ``` (slot.getAdUnitPath() === bid.adUnitCode || slot.getSlotElementId() === bid.adUnitCode) ``` this logic can be changed by using param ```customMatchFunction```
- When a rendered PBJS bid is viewable the module will trigger BID_VIEWABLE event, which can be consumed by bidders and analytics adapters
- For the viewable bid if ```bid.vurls type array``` param is and module config ``` firePixels: true ``` is set then the URLs mentioned in bid.vurls will be executed. Please note that GDPR and USP related parameters will be added to the given URLs

# Params
- enabled [required] [type: boolean, default: false], when set to true, the module will emit BID_VIEWABLE when applicable
- firePixels [optional] [type: boolean], when set to true, will fire the urls mentioned in bid.vurls which should be array of urls
- customMatchFunction [optional] [type: function(bid, slot)], when passed this function will be used to `find` the matching winning bid for the GPT slot. Default value is ` (bid, slot) => (slot.getAdUnitPath() === bid.adUnitCode || slot.getSlotElementId() === bid.adUnitCode) `

# Example of consuming BID_VIEWABLE event
```
pbjs.onEvent('bidViewable', function(bid){
console.log('got bid details in bidViewable event', bid);
});

```

# Example of using config
```
pbjs.setConfig({
bidViewability: {
enabled: true,
firePixels: true,
customMatchFunction: function(bid, slot){
console.log('using custom match function....');
return bid.adUnitCode === slot.getAdUnitPath();
}
}
});
```

# Please Note:
- Doesn't seems to work with Instream Video, https://docs.prebid.org/dev-docs/examples/instream-banner-mix.html as GPT's impressionViewable event is not triggered for instream-video-creative
- Works with Banner, Outsteam, Native creatives

4 changes: 4 additions & 0 deletions src/adapterManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -606,4 +606,8 @@ adapterManager.callSetTargetingBidder = function(bidder, bid) {
tryCallBidderMethod(bidder, 'onSetTargeting', bid);
};

adapterManager.callBidViewableBidder = function(bidder, bid) {
tryCallBidderMethod(bidder, 'onBidViewable', bid);
};

export default adapterManager;
3 changes: 2 additions & 1 deletion src/constants.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
"ADD_AD_UNITS": "addAdUnits",
"AD_RENDER_FAILED": "adRenderFailed",
"TCF2_ENFORCEMENT": "tcf2Enforcement",
"AUCTION_DEBUG": "auctionDebug"
"AUCTION_DEBUG": "auctionDebug",
"BID_VIEWABLE": "bidViewable"
},
"AD_RENDER_FAILED_REASON" : {
"PREVENT_WRITING_ON_MAIN_DOCUMENT": "preventWritingOnMainDocument",
Expand Down
Loading