Skip to content
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

Rename idWardRtdProvider to anonymisedRtdProvider #10176

Merged
merged 15 commits into from
Apr 26, 2024
112 changes: 112 additions & 0 deletions integrationExamples/gpt/anonymised_segments_example.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<html>
<head>
<script async src="../../build/dev/prebid.js"></script>
<script async src="https://securepubads.g.doubleclick.net/tag/js/gpt.js"></script>
<script>
var FAILSAFE_TIMEOUT = 3300;
var PREBID_TIMEOUT = 2000;

var adUnits = [{
code: 'div-gpt-ad-1460505748561-0',
mediaTypes: {
banner: {
sizes: [[300, 250], [300,600]],
}
},
// Replace this object to test a new Adapter!
bids: [
{
bidder: 'pubmatic',
params: {
publisherId: '156276', // required
adSlot: 'pubmatic_test', // required
}
}
]
}];

var pbjs = pbjs || {};
pbjs.que = pbjs.que || [];

</script>

<script>
var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
googletag.cmd.push(function() {
googletag.pubads().disableInitialLoad();
});

pbjs.que.push(function() {
pbjs.setConfig({
debugging: {
enabled: true
},
ortb2: {
user: {
data: [
// Anonymised segment taxonomy inserted here
]
},
},
realTimeData: {
dataProviders: [
{
name: "anonymised",
params: {
cohortStorageKey: "cohort_ids",
bidders: ['smartadserver', 'appnexus'],
segtax: 1000
}
}
]
}
});
pbjs.addAdUnits(adUnits);
pbjs.requestBids({
bidsBackHandler: sendAdserverRequest,
timeout: PREBID_TIMEOUT
});

document.getElementById( "user-segments" ).innerHTML = JSON.stringify( pbjs.getConfig('ortb2') );
});

function sendAdserverRequest() {
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>
googletag.cmd.push(function () {
googletag.defineSlot('/19968336/header-bid-tag-0', [[300, 250], [300, 600]], 'div-gpt-ad-1460505748561-0').addService(googletag.pubads());
googletag.pubads().enableSingleRequest();
googletag.enableServices();
});
</script>

<script>!function(a){var e="https://s.go-mpulse.net/boomerang/",t="addEventListener";if("False"=="True")a.BOOMR_config=a.BOOMR_config||{},a.BOOMR_config.PageParams=a.BOOMR_config.PageParams||{},a.BOOMR_config.PageParams.pci=!0,e="https://s2.go-mpulse.net/boomerang/";if(window.BOOMR_API_key="5G3ZS-8L7PG-U23WM-5CA4K-LQ3YP",function(){function n(e){a.BOOMR_onload=e&&e.timeStamp||(new Date).getTime()}if(!a.BOOMR||!a.BOOMR.version&&!a.BOOMR.snippetExecuted){a.BOOMR=a.BOOMR||{},a.BOOMR.snippetExecuted=!0;var i,_,o,r=document.createElement("iframe");if(a[t])a[t]("load",n,!1);else if(a.attachEvent)a.attachEvent("onload",n);r.src="javascript:void(0)",r.title="",r.role="presentation",(r.frameElement||r).style.cssText="width:0;height:0;border:0;display:none;",o=document.getElementsByTagName("script")[0],o.parentNode.insertBefore(r,o);try{_=r.contentWindow.document}catch(O){i=document.domain,r.src="javascript:var d=document.open();d.domain='"+i+"';void(0);",_=r.contentWindow.document}_.open()._l=function(){var a=this.createElement("script");if(i)this.domain=i;a.id="boomr-if-as",a.src=e+"5G3ZS-8L7PG-U23WM-5CA4K-LQ3YP",BOOMR_lstart=(new Date).getTime(),this.body.appendChild(a)},_.write("<bo"+'dy onload="document._l();">'),_.close()}}(),"".length>0)if(a&&"performance"in a&&a.performance&&"function"==typeof a.performance.setResourceTimingBufferSize)a.performance.setResourceTimingBufferSize();!function(){if(BOOMR=a.BOOMR||{},BOOMR.plugins=BOOMR.plugins||{},!BOOMR.plugins.AK){var e=""=="true"?1:0,t="",n="ghh4w4yxem66iyi6ijxa-f-a8f1ed317-clientnsv4-s.akamaihd.net",i="false"=="true"?2:1,_={"ak.v":"32","ak.cp":"540505","ak.ai":parseInt("351538",10),"ak.ol":"0","ak.cr":17,"ak.ipv":4,"ak.proto":"http/1.1","ak.rid":"322de403","ak.r":36326,"ak.a2":e,"ak.m":"dscx","ak.n":"essl","ak.bpcip":"49.207.203.0","ak.cport":5172,"ak.gh":"23.47.149.85","ak.quicv":"","ak.tlsv":"tls1.2","ak.0rtt":"","ak.csrc":"-","ak.acc":"bbr","ak.t":"1629373038","ak.ak":"hOBiQwZUYzCg5VSAfCLimQ==admFPBlxVf0VKeanKFKUThzq+or23aIaVFP5DBXpeOGEuvD5mQz0UZbvK242Y8cupS91bsNaM7uJT3/O00EszGTxlFhkv439YkTWfyegvqVlJhcrZ7jcRkIoyrmjoBqDZoF0WaG4rhwmNzkKEv6T1noRYwEWwRHOG8p7osPXWy5as6KkmhOYUiYk8S5hQj+HFzhYI5YUTx+8urmHdpVIDBkramcrT2V89mb0cH5L2bSGS2hahAA3Kkf+0Dul7r5hDFQaVTf17e4oKdM1G8cKVF5LGRxRl3v4Rn6tBJ+fjrJ7XYQWV30w1LPwcAmSfRX8iTCK4xzHwG1fwDFHb5tWVsxHeEkRgNN3/KhnrCjxKtaROjJeWypJf/rjn1HWHwy7uVVsP9f/HRN3drCCkEvJBmu6yi0jzFFCoeEkbUEoq+8=","ak.pv":"396","ak.dpoabenc":"","ak.tf":i};if(""!==t)_["ak.ruds"]=t;var o={i:!1,av:function(e){var t="http.initiator";if(e&&(!e[t]||"spa_hard"===e[t]))_["ak.feo"]=void 0!==a.aFeoApplied?1:0,BOOMR.addVar(_)},rv:function(){var a=["ak.bpcip","ak.cport","ak.cr","ak.csrc","ak.gh","ak.ipv","ak.m","ak.n","ak.ol","ak.proto","ak.quicv","ak.tlsv","ak.0rtt","ak.r","ak.acc","ak.t","ak.tf"];BOOMR.removeVar(a)}};BOOMR.plugins.AK={akVars:_,akDNSPreFetchDomain:n,init:function(){if(!o.i){var a=BOOMR.subscribe;a("before_beacon",o.av,null,null),a("onbeacon",o.rv,null,null),o.i=!0}return this},is_complete:function(){return!0}}}}()}(window);</script></head>

<body>
<h2>Prebid.js Test</h2>
<h5>Div-1</h5>
<div id='div-gpt-ad-1460505748561-0'>
<script type='text/javascript'>
googletag.cmd.push(function() { googletag.display('div-gpt-ad-1460505748561-0'); });
</script>
</div>
<h5>First Party Data (ortb2) Sent to Bidding Adapter</h5>
<div id="user-segments"></div>
</body>
</html>
122 changes: 122 additions & 0 deletions modules/anonymisedRtdProvider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/**
* This module adds the Anonymised RTD provider to the real time data module
* The {@link module:modules/realTimeData} module is required
* The module will populate real-time data from Anonymised
* @module modules/anonymisedRtdProvider
* @requires module:modules/realTimeData
*/
import {getStorageManager} from '../src/storageManager.js';
import {submodule} from '../src/hook.js';
import {isPlainObject, mergeDeep, logMessage, logError} from '../src/utils.js';
import {MODULE_TYPE_RTD} from '../src/activities/modules.js';

export function createRtdProvider(moduleName) {
const MODULE_NAME = 'realTimeData';
const SUBMODULE_NAME = moduleName;

const storage = getStorageManager({ moduleType: MODULE_TYPE_RTD, moduleName: SUBMODULE_NAME });
/**
* Add real-time data & merge segments.
* @param ortb2 object to merge into
* @param {Object} rtd
*/
function addRealTimeData(ortb2, rtd) {
if (isPlainObject(rtd.ortb2)) {
logMessage(`${SUBMODULE_NAME}RtdProvider: merging original: `, ortb2);
logMessage(`${SUBMODULE_NAME}RtdProvider: merging in: `, rtd.ortb2);
mergeDeep(ortb2, rtd.ortb2);
}
}
/**
* Try parsing stringified array of segment IDs.
* @param {String} data
*/
function tryParse(data) {
try {
return JSON.parse(data);
} catch (err) {
logError(`${SUBMODULE_NAME}RtdProvider: failed to parse json:`, data);
return null;
}
}
/**
* Real-time data retrieval from Anonymised
* @param {Object} reqBidsConfigObj
* @param {function} onDone
* @param {Object} rtdConfig
* @param {Object} userConsent
*/
function getRealTimeData(reqBidsConfigObj, onDone, rtdConfig, userConsent) {
if (rtdConfig && isPlainObject(rtdConfig.params)) {
const cohortStorageKey = rtdConfig.params.cohortStorageKey;
const bidders = rtdConfig.params.bidders;

if (cohortStorageKey !== 'cohort_ids') {
logError(`${SUBMODULE_NAME}RtdProvider: 'cohortStorageKey' should be 'cohort_ids'`)
return;
}

const jsonData = storage.getDataFromLocalStorage(cohortStorageKey);
if (!jsonData) {
return;
}

const segments = tryParse(jsonData);

if (segments) {
const udSegment = {
name: 'anonymised.io',
ext: {
segtax: rtdConfig.params.segtax
},
segment: segments.map(x => ({id: x}))
}

logMessage(`${SUBMODULE_NAME}RtdProvider: user.data.segment: `, udSegment);
const data = {
rtd: {
ortb2: {
user: {
data: [
udSegment
]
}
}
}
};

if (bidders?.includes('appnexus')) {
data.rtd.ortb2.user.keywords = segments.map(x => `perid=${x}`).join(',');
}

addRealTimeData(reqBidsConfigObj.ortb2Fragments?.global, data.rtd);
onDone();
}
}
}
/**
* Module init
* @param {Object} provider
* @param {Object} userConsent
* @return {boolean}
*/
function init(provider, userConsent) {
return true;
}
/** @type {RtdSubmodule} */
const rtdSubmodule = {
name: SUBMODULE_NAME,
getBidRequestData: getRealTimeData,
init: init
};

submodule(MODULE_NAME, rtdSubmodule);

return {
getRealTimeData,
rtdSubmodule,
storage
};
}

export const { getRealTimeData, rtdSubmodule: anonymisedRtdSubmodule, storage } = createRtdProvider('anonymised');
54 changes: 54 additions & 0 deletions modules/anonymisedRtdProvider.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
### Overview

Anonymised is a data anonymization technology for privacy-preserving advertising. Publishers and advertisers are able to target and retarget custom audience segments covering 100% of consented audiences.
Anonymised’s Real-time Data Provider automatically obtains segment IDs from the Anonymised on-domain script (via localStorage) and passes them to the bid-stream.

### Integration

- Build the anonymisedRtd module into the Prebid.js package with:

```bash
gulp build --modules=anonymisedRtdProvider,...
```

- Use `setConfig` to instruct Prebid.js to initilaize the anonymisedRtdProvider module, as specified below.

### Configuration

```javascript
pbjs.setConfig({
realTimeData: {
dataProviders: [
{
name: "anonymised",
waitForIt: true,
params: {
cohortStorageKey: "cohort_ids",
bidders: ["smartadserver", "appnexus"],
segtax: 1000
}
}
]
}
});
```

### Config Syntax details
| Name |Type | Description | Notes |
| :------------ | :------------ | :------------ |:------------ |
| name | String | Anonymised Rtd module name | 'anonymised' always|
| waitForIt | Boolean | Required to ensure that the auction is delayed until prefetch is complete | Optional. Defaults to false |
| params.cohortStorageKey | String | the `localStorage` key, under which Anonymised Marketing Tag stores the segment IDs | 'cohort_ids' always |
| params.bidders | Array | Bidders with which to share segment information | Optional |
| params.segtax | Integer | The taxonomy for Anonymised | '1000' always |

Please note that anonymisedRtdProvider should be integrated into the publisher website along with the [Anonymised Marketing Tag](https://support.anonymised.io/integrate/marketing-tag).
Please reach out to Anonymised [representative](mailto:[email protected]) if you have any questions or need further help to integrate Prebid, anonymisedRtdProvider, and Anonymised Marketing Tag

### Testing
To view an example of available segments returned by Anonymised:
```bash
gulp serve --modules=rtdModule,anonymisedRtdProvider,pubmaticBidAdapter
```
And then point your browser at:
"http://localhost:9999/integrationExamples/gpt/anonymised_segments_example.html"