Skip to content

Commit

Permalink
im rtd segment module (#7359)
Browse files Browse the repository at this point in the history
  • Loading branch information
eknis authored Aug 31, 2021
1 parent ad8f4cc commit 46751bd
Show file tree
Hide file tree
Showing 4 changed files with 504 additions and 0 deletions.
115 changes: 115 additions & 0 deletions integrationExamples/gpt/imRtdProvider_example.html
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>
197 changes: 197 additions & 0 deletions modules/imRtdProvider.js
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);
41 changes: 41 additions & 0 deletions modules/imRtdProvider.md
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` |
Loading

0 comments on commit 46751bd

Please sign in to comment.