forked from prebid/Prebid.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbidViewabilityIO.js
91 lines (80 loc) · 3.63 KB
/
bidViewabilityIO.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import { logMessage } from '../src/utils.js';
import { config } from '../src/config.js';
import * as events from '../src/events.js';
import {EVENTS} from '../src/constants.js';
const MODULE_NAME = 'bidViewabilityIO';
const CONFIG_ENABLED = 'enabled';
// IAB numbers from: https://support.google.com/admanager/answer/4524488?hl=en
const IAB_VIEWABLE_DISPLAY_TIME = 1000;
const IAB_VIEWABLE_DISPLAY_LARGE_PX = 242000;
export const IAB_VIEWABLE_DISPLAY_THRESHOLD = 0.5
export const IAB_VIEWABLE_DISPLAY_LARGE_THRESHOLD = 0.3;
const CLIENT_SUPPORTS_IO = window.IntersectionObserver && window.IntersectionObserverEntry && window.IntersectionObserverEntry.prototype &&
'intersectionRatio' in window.IntersectionObserverEntry.prototype;
const supportedMediaTypes = [
'banner'
];
export let isSupportedMediaType = (bid) => {
return supportedMediaTypes.indexOf(bid.mediaType) > -1;
}
let _logMessage = (message) => {
return logMessage(`${MODULE_NAME}: ${message}`);
}
// returns options for the iO that detects if the ad is viewable
export let getViewableOptions = (bid) => {
if (bid.mediaType === 'banner') {
return {
root: null,
rootMargin: '0px',
threshold: bid.width * bid.height > IAB_VIEWABLE_DISPLAY_LARGE_PX ? IAB_VIEWABLE_DISPLAY_LARGE_THRESHOLD : IAB_VIEWABLE_DISPLAY_THRESHOLD
}
}
}
// markViewed returns a function what will be executed when an ad satisifes the viewable iO
export let markViewed = (bid, entry, observer) => {
return () => {
observer.unobserve(entry.target);
events.emit(EVENTS.BID_VIEWABLE, bid);
_logMessage(`id: ${entry.target.getAttribute('id')} code: ${bid.adUnitCode} was viewed`);
}
}
// viewCallbackFactory creates the callback used by the viewable IntersectionObserver.
// When an ad comes into view, it sets a timeout for a function to be executed
// when that ad would be considered viewed per the IAB specs. The bid that was rendered
// is passed into the factory, so it can pass it into markViewed, so that it can be included
// in the BID_VIEWABLE event data. If the ad leaves view before the timer goes off, the setTimeout
// is cancelled, an the bid will not be marked as viewed. There's probably some kind of race-ish
// thing going on between IO and setTimeout but this isn't going to be perfect, it's just going to
// be pretty good.
export let viewCallbackFactory = (bid) => {
return (entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
_logMessage(`viewable timer starting for id: ${entry.target.getAttribute('id')} code: ${bid.adUnitCode}`);
entry.target.view_tracker = setTimeout(markViewed(bid, entry, observer), IAB_VIEWABLE_DISPLAY_TIME);
} else {
_logMessage(`id: ${entry.target.getAttribute('id')} code: ${bid.adUnitCode} is out of view`);
if (entry.target.view_tracker) {
clearTimeout(entry.target.view_tracker);
_logMessage(`viewable timer stopped for id: ${entry.target.getAttribute('id')} code: ${bid.adUnitCode}`);
}
}
});
};
};
export let init = () => {
config.getConfig(MODULE_NAME, conf => {
if (conf[MODULE_NAME][CONFIG_ENABLED] && CLIENT_SUPPORTS_IO) {
// if the module is enabled and the browser supports Intersection Observer,
// then listen to AD_RENDER_SUCCEEDED to setup IO's for supported mediaTypes
events.on(EVENTS.AD_RENDER_SUCCEEDED, ({doc, bid, id}) => {
if (isSupportedMediaType(bid)) {
let viewable = new IntersectionObserver(viewCallbackFactory(bid), getViewableOptions(bid));
let element = document.getElementById(bid.adUnitCode);
viewable.observe(element);
}
});
}
});
}
init()