-
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.
- Loading branch information
Showing
4 changed files
with
504 additions
and
0 deletions.
There are no files selected for viewing
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,115 @@ | ||
<html> | ||
<head> | ||
<script> | ||
var FAILSAFE_TIMEOUT = 2000; | ||
|
||
var adUnits = [ | ||
{ | ||
code: 'test-div', | ||
mediaTypes: { | ||
banner: { | ||
sizes: [[300,250],[300,600],[728,90]] | ||
} | ||
}, | ||
bids: [ | ||
{ | ||
bidder: 'appnexus', | ||
params: { | ||
placementId: 13144370 | ||
} | ||
} | ||
] | ||
} | ||
]; | ||
|
||
var pbjs = pbjs || {}; | ||
pbjs.que = pbjs.que || []; | ||
</script> | ||
<script src="../../build/dev/prebid.js" async></script> | ||
|
||
<script> | ||
var googletag = googletag || {}; | ||
var testAuctionDelay = 2000; | ||
googletag.cmd = googletag.cmd || []; | ||
googletag.cmd.push(function() { | ||
googletag.pubads().disableInitialLoad(); | ||
}); | ||
|
||
pbjs.que.push(function() { | ||
pbjs.setConfig({ | ||
debug: true, | ||
realTimeData: { | ||
auctionDelay: testAuctionDelay, // lower in real scenario to meet publisher spec | ||
dataProviders: [ | ||
{ | ||
name: "im", | ||
waitForIt: true, | ||
params: { | ||
cid: 5126 | ||
} | ||
|
||
} | ||
] | ||
} | ||
}); | ||
pbjs.addAdUnits(adUnits); | ||
pbjs.requestBids({bidsBackHandler: sendAdserverRequest}); | ||
}); | ||
|
||
function sendAdserverRequest() { | ||
document.getElementById('imuid').innerHTML = window.localStorage.getItem('__im_uid'); | ||
document.getElementById('im_segments').innerHTML = window.localStorage.getItem('__im_sids'); | ||
|
||
if (pbjs.adserverRequestSent) return; | ||
pbjs.adserverRequestSent = true; | ||
googletag.cmd.push(function() { | ||
pbjs.que.push(function() { | ||
pbjs.setTargetingForGPTAsync(); | ||
googletag.pubads().refresh(); | ||
}); | ||
}); | ||
} | ||
|
||
setTimeout(function() { | ||
sendAdserverRequest(); | ||
}, FAILSAFE_TIMEOUT); | ||
</script> | ||
|
||
<script> | ||
(function () { | ||
var gads = document.createElement('script'); | ||
gads.async = true; | ||
gads.type = 'text/javascript'; | ||
var useSSL = 'https:' == document.location.protocol; | ||
gads.src = (useSSL ? 'https:' : 'http:') + | ||
'//www.googletagservices.com/tag/js/gpt.js'; | ||
var node = document.getElementsByTagName('script')[0]; | ||
node.parentNode.insertBefore(gads, node); | ||
})(); | ||
</script> | ||
|
||
<script> | ||
googletag.cmd.push(function () { | ||
googletag.defineSlot('/112115922/FL_PB_MedRect', [[300, 250], [300, 600], [728, 90]], 'test-div').addService(googletag.pubads()); | ||
googletag.pubads().enableSingleRequest(); | ||
googletag.enableServices(); | ||
}); | ||
</script> | ||
</head> | ||
|
||
<body> | ||
<h2>IM RTD Prebid</h2> | ||
|
||
<div id='test-div'> | ||
<script> | ||
googletag.cmd.push(function() { googletag.display('test-div'); }); | ||
</script> | ||
</div> | ||
|
||
Intimate Merger Universal Identifier: | ||
<div id='imuid'></div> | ||
|
||
Intimate Merger Real-Time Data: | ||
<div id='im_segments'></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,197 @@ | ||
/** | ||
* The {@link module:modules/realTimeData} module is required | ||
* The module will fetch real-time data from Intimate Merger | ||
* @module modules/imRtdProvider | ||
* @requires module:modules/realTimeData | ||
*/ | ||
import {ajax} from '../src/ajax.js'; | ||
import {config} from '../src/config.js'; | ||
import {getGlobal} from '../src/prebidGlobal.js' | ||
import {getStorageManager} from '../src/storageManager.js'; | ||
import { | ||
deepSetValue, | ||
deepAccess, | ||
timestamp, | ||
mergeDeep, | ||
logError, | ||
logInfo, | ||
isFn | ||
} from '../src/utils.js' | ||
import {submodule} from '../src/hook.js'; | ||
|
||
export const imUidLocalName = '__im_uid'; | ||
export const imVidCookieName = '_im_vid'; | ||
export const imRtdLocalName = '__im_sids'; | ||
export const storage = getStorageManager(); | ||
const submoduleName = 'im'; | ||
const segmentsMaxAge = 3600000; // 1 hour (30 * 60 * 1000) | ||
const uidMaxAge = 1800000; // 30 minites (30 * 60 * 1000) | ||
const vidMaxAge = 97200000000; // 37 months ((365 * 3 + 30) * 24 * 60 * 60 * 1000) | ||
|
||
function setImDataInCookie(value) { | ||
storage.setCookie( | ||
imVidCookieName, | ||
value, | ||
new Date(timestamp() + vidMaxAge).toUTCString(), | ||
'none' | ||
); | ||
} | ||
|
||
export function getCustomBidderFunction(config, bidder) { | ||
const overwriteFn = deepAccess(config, `params.overwrites.${bidder}`) | ||
|
||
if (overwriteFn && isFn(overwriteFn)) { | ||
return overwriteFn | ||
} else { | ||
return null | ||
} | ||
} | ||
|
||
/** | ||
* Add real-time data. | ||
* @param {Object} bidConfig | ||
* @param {Object} moduleConfig | ||
* @param {Object} data | ||
*/ | ||
export function setRealTimeData(bidConfig, moduleConfig, data) { | ||
const adUnits = bidConfig.adUnits || getGlobal().adUnits; | ||
const utils = {deepSetValue, deepAccess, logInfo, logError, mergeDeep}; | ||
|
||
if (data.im_segments) { | ||
const ortb2 = config.getConfig('ortb2') || {}; | ||
deepSetValue(ortb2, 'user.ext.data.im_segments', data.im_segments); | ||
config.setConfig({ortb2: ortb2}); | ||
|
||
if (moduleConfig.params.setGptKeyValues || !moduleConfig.params.hasOwnProperty('setGptKeyValues')) { | ||
window.googletag = window.googletag || {cmd: []}; | ||
window.googletag.cmd = window.googletag.cmd || []; | ||
window.googletag.cmd.push(() => { | ||
window.googletag.pubads().setTargeting('im_segments', data.im_segments); | ||
}); | ||
} | ||
} | ||
|
||
adUnits.forEach(adUnit => { | ||
adUnit.bids.forEach(bid => { | ||
const overwriteFunction = getCustomBidderFunction(moduleConfig, bid.bidder); | ||
if (overwriteFunction) { | ||
overwriteFunction(bid, data, utils, config); | ||
} | ||
}) | ||
}); | ||
} | ||
|
||
/** | ||
* Real-time data retrieval from Intimate Merger | ||
* @param {Object} reqBidsConfigObj | ||
* @param {function} onDone | ||
* @param {Object} moduleConfig | ||
*/ | ||
export function getRealTimeData(reqBidsConfigObj, onDone, moduleConfig) { | ||
const cid = deepAccess(moduleConfig, 'params.cid'); | ||
if (!cid) { | ||
logError('imRtdProvider requires a valid cid to be defined'); | ||
onDone(); | ||
return; | ||
} | ||
const sids = storage.getDataFromLocalStorage(imRtdLocalName); | ||
const parsedSids = sids ? sids.split(',') : []; | ||
const mt = storage.getDataFromLocalStorage(`${imRtdLocalName}_mt`); | ||
const localVid = storage.getCookie(imVidCookieName); | ||
let apiUrl = `https://sync6.im-apps.net/${cid}/rtd`; | ||
let expired = true; | ||
let alreadyDone = false; | ||
|
||
if (localVid) { | ||
apiUrl += `?vid=${localVid}`; | ||
setImDataInCookie(localVid); | ||
} | ||
|
||
if (Date.parse(mt) && Date.now() - (new Date(mt)).getTime() < segmentsMaxAge) { | ||
expired = false; | ||
} | ||
|
||
if (sids !== null) { | ||
setRealTimeData(reqBidsConfigObj, moduleConfig, {im_segments: parsedSids}); | ||
onDone(); | ||
alreadyDone = true; | ||
} | ||
|
||
if (expired) { | ||
ajax( | ||
apiUrl, | ||
getApiCallback(reqBidsConfigObj, alreadyDone ? undefined : onDone, moduleConfig), | ||
undefined, | ||
{method: 'GET', withCredentials: true} | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* Api callback from Intimate Merger | ||
* @param {Object} reqBidsConfigObj | ||
* @param {function} onDone | ||
* @param {Object} moduleConfig | ||
*/ | ||
export function getApiCallback(reqBidsConfigObj, onDone, moduleConfig) { | ||
return { | ||
success: function (response, req) { | ||
let parsedResponse = {}; | ||
if (req.status === 200) { | ||
try { | ||
parsedResponse = JSON.parse(response); | ||
} catch (e) { | ||
logError('unable to get Intimate Merger segment data'); | ||
} | ||
|
||
if (parsedResponse.uid) { | ||
const imuid = storage.getDataFromLocalStorage(imUidLocalName); | ||
const imuidMt = storage.getDataFromLocalStorage(`${imUidLocalName}_mt`); | ||
const imuidExpired = Date.parse(imuidMt) && Date.now() - (new Date(imuidMt)).getTime() < uidMaxAge; | ||
if (!imuid || imuidExpired) { | ||
storage.setDataInLocalStorage(imUidLocalName, parsedResponse.uid); | ||
storage.setDataInLocalStorage(`${imUidLocalName}_mt`, new Date(timestamp()).toUTCString()); | ||
} | ||
} | ||
|
||
if (parsedResponse.vid) { | ||
setImDataInCookie(parsedResponse.vid); | ||
} | ||
|
||
if (parsedResponse.segments) { | ||
setRealTimeData(reqBidsConfigObj, moduleConfig, {im_segments: parsedResponse.segments}); | ||
storage.setDataInLocalStorage(imRtdLocalName, parsedResponse.segments); | ||
storage.setDataInLocalStorage(`${imRtdLocalName}_mt`, new Date(timestamp()).toUTCString()); | ||
} | ||
} | ||
if (onDone) { | ||
onDone(); | ||
} | ||
}, | ||
error: function () { | ||
if (onDone) { | ||
onDone(); | ||
} | ||
logError('unable to get Intimate Merger segment data'); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Module init | ||
* @param {Object} provider | ||
* @param {Object} userConsent | ||
* @return {boolean} | ||
*/ | ||
function init(provider, userConsent) { | ||
return true; | ||
} | ||
|
||
/** @type {RtdSubmodule} */ | ||
export const imRtdSubmodule = { | ||
name: submoduleName, | ||
getBidRequestData: getRealTimeData, | ||
init: init | ||
}; | ||
|
||
submodule('realTimeData', imRtdSubmodule); |
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,41 @@ | ||
## Intimate Merger Real-time Data Submodule | ||
|
||
provided by Intimate Merger. | ||
|
||
## Building Prebid with Real-time Data Support | ||
|
||
First, make sure to add the Intimate Merger submodule to your Prebid.js package with: | ||
|
||
`gulp build --modules=rtdModule,imRtdProvider` | ||
|
||
The following configuration parameters are available: | ||
|
||
``` | ||
pbjs.setConfig( | ||
... | ||
realTimeData: { | ||
auctionDelay: 5000, | ||
dataProviders: [ | ||
{ | ||
name: "im", | ||
waitForIt: true, | ||
params: { | ||
cid: 5126, // Set your Intimate Merger Customer ID here for production | ||
setGptKeyValues: true | ||
} | ||
} | ||
] | ||
} | ||
... | ||
} | ||
``` | ||
|
||
### Parameter Descriptions for the im Configuration Section | ||
|
||
| Param under dataProviders | Scope | Type | Description | Example | | ||
| --- | --- | --- | --- | --- | | ||
| name | Required | String | The name of this module. | `"im"` | | ||
| waitForIt | Optional | Boolean | Required to ensure that the auction is delayed until prefetch is complete. Defaults to false but recommended to true | `true` | | ||
| params | Required | Object | Details of module params. | | | ||
| params.cid | Required | Number | This is the Customer ID value obtained via Intimate Merger. | `5126` | | ||
| params.setGptKeyValues | Optional | Boolean | This is set targeting for GPT/GAM. Default setting is true. | `true` | |
Oops, something went wrong.