-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add Permutive RTD module * set demo data in LS for test page * fix linter issues * reduce timeout on example page * decrease sample timeouts * rename targeting to segments
- Loading branch information
Showing
4 changed files
with
775 additions
and
0 deletions.
There are no files selected for viewing
223 changes: 223 additions & 0 deletions
223
integrationExamples/gpt/permutiveRtdProvider_example.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
<html> | ||
|
||
<head> | ||
<link rel="icon" type="image/png" href="/favicon.png"> | ||
<script async src="//www.googletagservices.com/tag/js/gpt.js"></script> | ||
<script src="../../build/dev/prebid.js" async></script> | ||
<script> | ||
window.permutive = {}; | ||
window.permutive.ready = () => {}; | ||
|
||
function setLocalStorageData () { | ||
const data = { | ||
_pdfps: ['gam1', 'gam2'], | ||
_prubicons: ['rubicon1', 'rubicon2'], | ||
_papns: ['appnexus1', 'appnexus2'], | ||
_psegs: ['1234', '1000001', '1000002'], | ||
_ppam: ['ppam1', 'ppam2'], | ||
_pcrprs: ['pcrprs1', 'pcrprs2'] | ||
} | ||
|
||
for (let key in data) { | ||
window.localStorage[key] = JSON.stringify(data[key]) | ||
} | ||
} | ||
|
||
setLocalStorageData() | ||
|
||
var div_1_sizes = [ | ||
[300, 250], | ||
[300, 600] | ||
]; | ||
var div_2_sizes = [ | ||
[728, 90], | ||
[970, 250] | ||
]; | ||
var PREBID_TIMEOUT = 1000; | ||
var FAILSAFE_TIMEOUT = 1500; | ||
|
||
var adUnits = [ | ||
{ | ||
code: '/19968336/header-bid-tag-0', | ||
mediaTypes: { | ||
banner: { | ||
sizes: div_1_sizes | ||
} | ||
}, | ||
bids: [ | ||
{ | ||
bidder: 'appnexus', | ||
params: { | ||
placementId: 13144370, | ||
keywords: { | ||
inline_kvs: ['1'] | ||
} | ||
} | ||
}, | ||
{ | ||
bidder: 'rubicon', | ||
params: { | ||
accountId: '9840', | ||
siteId: '123564', | ||
zoneId: '583584', | ||
inventory: { | ||
area: ['home'] | ||
}, | ||
visitor: { | ||
inline_kvs: ['1'] | ||
} | ||
} | ||
}, | ||
{ | ||
bidder: 'ozone', | ||
params: { | ||
publisherId: 'OZONEGMG0001', | ||
siteId: '4204204209', | ||
placementId: '0420420500', | ||
customData: [ | ||
{ | ||
settings: {}, | ||
targeting: { | ||
inline_kvs: ['1', '2', '3', '4'] | ||
} | ||
} | ||
], | ||
ozoneData: {} | ||
} | ||
} | ||
] | ||
}, | ||
{ | ||
code: '/19968336/header-bid-tag-1', | ||
mediaTypes: { | ||
banner: { | ||
sizes: div_2_sizes | ||
} | ||
}, | ||
bids: [ | ||
{ | ||
bidder: 'appnexus', | ||
params: { | ||
placementId: 13144370 | ||
} | ||
}, | ||
{ | ||
bidder: 'ozone', | ||
params: { | ||
publisherId: 'OZONEGMG0001', | ||
siteId: '4204204209', | ||
placementId: '0420420500' | ||
} | ||
} | ||
] | ||
} | ||
]; | ||
|
||
|
||
var googletag = googletag || {}; | ||
googletag.cmd = googletag.cmd || []; | ||
googletag.cmd.push(function() { | ||
googletag.pubads().disableInitialLoad(); | ||
}); | ||
|
||
var pbjs = pbjs || {}; | ||
pbjs.que = pbjs.que || []; | ||
|
||
pbjs.que.push(function() { | ||
pbjs.setConfig({ | ||
debug: true, | ||
realTimeData: { | ||
auctionDelay: 50, // maximum time for RTD modules to respond | ||
dataProviders: [ | ||
{ | ||
name: 'permutive', | ||
waitForIt: true, | ||
params: { | ||
acBidders: ['appnexus', 'rubicon', 'ozone'], | ||
maxSegs: 500, | ||
overwrites: { | ||
rubicon: function (bid, data, acEnabled, utils, defaultFn) { | ||
if (defaultFn){ | ||
bid = defaultFn(bid, data, acEnabled) | ||
} | ||
if (data.gam && data.gam.length) { | ||
utils.deepSetValue(bid, 'params.visitor.permutive', data.gam) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
] | ||
} | ||
}); | ||
pbjs.addAdUnits(adUnits); | ||
requestBids(); | ||
}); | ||
|
||
function requestBids () { | ||
pbjs.que.push(function() { | ||
pbjs.requestBids({ | ||
bidsBackHandler: initAdserver, | ||
timeout: PREBID_TIMEOUT | ||
}); | ||
}); | ||
} | ||
|
||
function initAdserver() { | ||
if (pbjs.initAdserverSet) return; | ||
pbjs.initAdserverSet = true; | ||
googletag.cmd.push(function() { | ||
pbjs.que.push(function() { | ||
pbjs.setTargetingForGPTAsync(); | ||
googletag.pubads().refresh(); | ||
}); | ||
}); | ||
} | ||
// in case PBJS doesn't load | ||
setTimeout(function() { | ||
initAdserver(); | ||
}, FAILSAFE_TIMEOUT); | ||
|
||
googletag.cmd.push(function() { | ||
googletag.defineSlot('/19968336/header-bid-tag-0', div_1_sizes, 'div-1').addService(googletag.pubads()); | ||
googletag.pubads().enableSingleRequest(); | ||
googletag.enableServices(); | ||
}); | ||
googletag.cmd.push(function() { | ||
googletag.defineSlot('/19968336/header-bid-tag-1', div_2_sizes, 'div-2').addService(googletag.pubads()); | ||
googletag.pubads().enableSingleRequest(); | ||
googletag.enableServices(); | ||
}); | ||
|
||
</script> | ||
|
||
</head> | ||
|
||
<body> | ||
<p><button onclick="requestBids()">Refresh Ad Unit</button></p> | ||
<h2>Basic Prebid.js Example</h2> | ||
<h5>Div-1</h5> | ||
<div id="div-1"> | ||
<script type="text/javascript"> | ||
googletag.cmd.push(function() { | ||
googletag.display("div-1"); | ||
}); | ||
|
||
</script> | ||
</div> | ||
|
||
<br> | ||
|
||
<h5>Div-2</h5> | ||
<div id="div-2"> | ||
<script type="text/javascript"> | ||
googletag.cmd.push(function() { | ||
googletag.display("div-2"); | ||
}); | ||
|
||
</script> | ||
</div> | ||
|
||
</body> | ||
|
||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
/** | ||
* This module adds permutive provider to the real time data module | ||
* The {@link module:modules/realTimeData} module is required | ||
* The module will add custom segment targeting to ad units of specific bidders | ||
* @module modules/permutiveRtdProvider | ||
* @requires module:modules/realTimeData | ||
*/ | ||
import { getGlobal } from '../src/prebidGlobal.js' | ||
import { submodule } from '../src/hook.js' | ||
import { getStorageManager } from '../src/storageManager.js' | ||
import { deepSetValue, deepAccess, isFn, mergeDeep } from '../src/utils.js' | ||
import includes from 'core-js-pure/features/array/includes.js' | ||
|
||
export const storage = getStorageManager() | ||
|
||
function init (config, userConsent) { | ||
return true | ||
} | ||
|
||
/** | ||
* Set segment targeting from cache and then try to wait for Permutive | ||
* to initialise to get realtime segment targeting | ||
*/ | ||
export function initSegments (reqBidsConfigObj, callback, customConfig) { | ||
const permutiveOnPage = isPermutiveOnPage() | ||
const config = mergeDeep({ | ||
waitForIt: false, | ||
params: { | ||
maxSegs: 500, | ||
acBidders: [], | ||
overwrites: {} | ||
} | ||
}, customConfig) | ||
|
||
setSegments(reqBidsConfigObj, config) | ||
|
||
if (config.waitForIt && permutiveOnPage) { | ||
window.permutive.ready(function () { | ||
setSegments(reqBidsConfigObj, config) | ||
callback() | ||
}, 'realtime') | ||
} else { | ||
callback() | ||
} | ||
} | ||
|
||
function setSegments (reqBidsConfigObj, config) { | ||
const adUnits = reqBidsConfigObj.adUnits || getGlobal().adUnits | ||
const data = getSegments(config.params.maxSegs) | ||
const utils = { deepSetValue, deepAccess, isFn, mergeDeep } | ||
|
||
adUnits.forEach(adUnit => { | ||
adUnit.bids.forEach(bid => { | ||
const { bidder } = bid | ||
const acEnabled = isAcEnabled(config, bidder) | ||
const customFn = getCustomBidderFn(config, bidder) | ||
const defaultFn = getDefaultBidderFn(bidder) | ||
|
||
if (customFn) { | ||
customFn(bid, data, acEnabled, utils, defaultFn) | ||
} else if (defaultFn) { | ||
defaultFn(bid, data, acEnabled) | ||
} else { | ||
|
||
} | ||
}) | ||
}) | ||
} | ||
|
||
function getCustomBidderFn (config, bidder) { | ||
const overwriteFn = deepAccess(config, `params.overwrites.${bidder}`) | ||
|
||
if (overwriteFn && isFn(overwriteFn)) { | ||
return overwriteFn | ||
} else { | ||
return null | ||
} | ||
} | ||
|
||
/** | ||
* Returns a function that receives a `bid` object, a `data` object and a `acEnabled` boolean | ||
* and which will set the right segment targeting keys for `bid` based on `data` and `acEnabled` | ||
* @param {string} bidder | ||
* @param {object} data | ||
*/ | ||
function getDefaultBidderFn (bidder) { | ||
const bidderMapper = { | ||
appnexus: function (bid, data, acEnabled) { | ||
if (acEnabled && data.ac && data.ac.length) { | ||
deepSetValue(bid, 'params.keywords.p_standard', data.ac) | ||
} | ||
if (data.appnexus && data.appnexus.length) { | ||
deepSetValue(bid, 'params.keywords.permutive', data.appnexus) | ||
} | ||
|
||
return bid | ||
}, | ||
rubicon: function (bid, data, acEnabled) { | ||
if (acEnabled && data.ac && data.ac.length) { | ||
deepSetValue(bid, 'params.visitor.p_standard', data.ac) | ||
} | ||
if (data.rubicon && data.rubicon.length) { | ||
deepSetValue(bid, 'params.visitor.permutive', data.rubicon) | ||
} | ||
|
||
return bid | ||
}, | ||
ozone: function (bid, data, acEnabled) { | ||
if (acEnabled && data.ac && data.ac.length) { | ||
deepSetValue(bid, 'params.customData.0.targeting.p_standard', data.ac) | ||
} | ||
|
||
return bid | ||
} | ||
} | ||
|
||
return bidderMapper[bidder] | ||
} | ||
|
||
export function isAcEnabled (config, bidder) { | ||
const acBidders = deepAccess(config, 'params.acBidders') || [] | ||
return includes(acBidders, bidder) | ||
} | ||
|
||
export function isPermutiveOnPage () { | ||
return typeof window.permutive !== 'undefined' && typeof window.permutive.ready === 'function' | ||
} | ||
|
||
/** | ||
* Returns all relevant segment IDs in an object | ||
*/ | ||
export function getSegments (maxSegs) { | ||
const legacySegs = readSegments('_psegs').map(Number).filter(seg => seg >= 1000000).map(String) | ||
const _ppam = readSegments('_ppam') | ||
const _pcrprs = readSegments('_pcrprs') | ||
|
||
const segments = { | ||
ac: [..._pcrprs, ..._ppam, ...legacySegs], | ||
rubicon: readSegments('_prubicons'), | ||
appnexus: readSegments('_papns'), | ||
gam: readSegments('_pdfps') | ||
} | ||
|
||
for (const type in segments) { | ||
segments[type] = segments[type].slice(0, maxSegs) | ||
} | ||
|
||
return segments | ||
} | ||
|
||
/** | ||
* Gets an array of segment IDs from LocalStorage | ||
* or returns an empty array | ||
* @param {string} key | ||
*/ | ||
function readSegments (key) { | ||
try { | ||
return JSON.parse(storage.getDataFromLocalStorage(key) || '[]') | ||
} catch (e) { | ||
return [] | ||
} | ||
} | ||
|
||
/** @type {RtdSubmodule} */ | ||
export const permutiveSubmodule = { | ||
name: 'permutive', | ||
getBidRequestData: initSegments, | ||
init: init | ||
} | ||
|
||
submodule('realTimeData', permutiveSubmodule) |
Oops, something went wrong.