diff --git a/integrationExamples/gpt/anonymised_segments_example.html b/integrationExamples/gpt/anonymised_segments_example.html
new file mode 100644
index 00000000000..16f3f879636
--- /dev/null
+++ b/integrationExamples/gpt/anonymised_segments_example.html
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+Prebid.js Test
+Div-1
+
+
+
+First Party Data (ortb2) Sent to Bidding Adapter
+
+
+
diff --git a/modules/anonymisedRtdProvider.js b/modules/anonymisedRtdProvider.js
new file mode 100644
index 00000000000..48ac649f002
--- /dev/null
+++ b/modules/anonymisedRtdProvider.js
@@ -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');
diff --git a/modules/anonymisedRtdProvider.md b/modules/anonymisedRtdProvider.md
new file mode 100644
index 00000000000..2ff2597690b
--- /dev/null
+++ b/modules/anonymisedRtdProvider.md
@@ -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:support@anonymised.io) 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"
diff --git a/modules/idWardRtdProvider.js b/modules/idWardRtdProvider.js
index dd08a132b2d..8e6e3c20a64 100644
--- a/modules/idWardRtdProvider.js
+++ b/modules/idWardRtdProvider.js
@@ -1,107 +1,10 @@
/**
* This module adds the ID Ward RTD provider to the real time data module
* The {@link module:modules/realTimeData} module is required
- * The module will poulate real-time data from ID Ward
+ * The module will populate real-time data from ID Ward
* @module modules/idWardRtdProvider
* @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';
-/**
- * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule
- */
-
-const MODULE_NAME = 'realTimeData';
-const SUBMODULE_NAME = 'idWard';
-
-export 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('idWardRtdProvider: merging original: ', ortb2);
- logMessage('idWardRtdProvider: 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(`idWardRtdProvider: failed to parse json:`, data);
- return null;
- }
-}
-
-/**
- * Real-time data retrieval from ID Ward
- * @param {Object} reqBidsConfigObj
- * @param {function} onDone
- * @param {Object} rtdConfig
- * @param {Object} userConsent
- */
-export function getRealTimeData(reqBidsConfigObj, onDone, rtdConfig, userConsent) {
- if (rtdConfig && isPlainObject(rtdConfig.params)) {
- const jsonData = storage.getDataFromLocalStorage(rtdConfig.params.cohortStorageKey)
-
- if (!jsonData) {
- return;
- }
-
- const segments = tryParse(jsonData);
-
- if (segments) {
- const udSegment = {
- name: 'id-ward.com',
- ext: {
- segtax: rtdConfig.params.segtax
- },
- segment: segments.map(x => ({id: x}))
- }
-
- logMessage('idWardRtdProvider: user.data.segment: ', udSegment);
- const data = {
- rtd: {
- ortb2: {
- user: {
- data: [
- udSegment
- ]
- }
- }
- }
- };
- 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} */
-export const idWardRtdSubmodule = {
- name: SUBMODULE_NAME,
- getBidRequestData: getRealTimeData,
- init: init
-};
+import { createRtdProvider } from './anonymisedRtdProvider.js';/* eslint prebid/validate-imports: "off" */
-submodule(MODULE_NAME, idWardRtdSubmodule);
+export const { getRealTimeData, rtdSubmodule: idWardRtdSubmodule, storage } = createRtdProvider('idWard');
diff --git a/modules/idWardRtdProvider.md b/modules/idWardRtdProvider.md
index 5a44bfa49f3..1c9f0654de6 100644
--- a/modules/idWardRtdProvider.md
+++ b/modules/idWardRtdProvider.md
@@ -1,3 +1,10 @@
+> **Warning!**
+>
+> The **idWardRtdProvider** module has been renamed to [anonymisedRtdProvider](anonymisedRtdProvider.md) in light of the company's rebranding.
+> **idWardRtdProvider** module is maintained for backward compatibility until the next major Prebid release.
+>
+> Please use anonymisedRtdProvider instead of idWardRtdProvider in your Prebid integration.
+
### Overview
ID Ward 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.
@@ -41,4 +48,4 @@ To view an example of available segments returned by Id Ward:
‘gulp serve --modules=rtdModule,idWardRtdProvider,pubmaticBidAdapter
```
and then point your browser at:
-"http://localhost:9999/integrationExamples/gpt/idward_segments_example.html"
+"http://localhost:9999/integrationExamples/gpt/idward_segments_example.html"
\ No newline at end of file
diff --git a/test/spec/modules/anonymisedRtdProvider_spec.js b/test/spec/modules/anonymisedRtdProvider_spec.js
new file mode 100644
index 00000000000..89115e5e740
--- /dev/null
+++ b/test/spec/modules/anonymisedRtdProvider_spec.js
@@ -0,0 +1,214 @@
+import {config} from 'src/config.js';
+import {getRealTimeData, anonymisedRtdSubmodule, storage} from 'modules/anonymisedRtdProvider.js';
+
+describe('anonymisedRtdProvider', function() {
+ let getDataFromLocalStorageStub;
+
+ const testReqBidsConfigObj = {
+ adUnits: [
+ {
+ bids: ['bid1', 'bid2']
+ }
+ ]
+ };
+
+ const onDone = function() { return true };
+
+ const cmoduleConfig = {
+ 'name': 'anonymised',
+ 'params': {
+ 'cohortStorageKey': 'cohort_ids'
+ }
+ }
+
+ beforeEach(function() {
+ config.resetConfig();
+ getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage')
+ });
+
+ afterEach(function () {
+ getDataFromLocalStorageStub.restore();
+ });
+
+ describe('anonymisedRtdSubmodule', function() {
+ it('successfully instantiates', function () {
+ expect(anonymisedRtdSubmodule.init()).to.equal(true);
+ });
+ });
+
+ describe('Get Real-Time Data', function() {
+ it('gets rtd from local storage and set to ortb2.user.data', function() {
+ const rtdConfig = {
+ params: {
+ cohortStorageKey: 'cohort_ids',
+ bidders: ['smartadserver'],
+ segtax: 503
+ }
+ };
+
+ const bidConfig = {
+ ortb2Fragments: {
+ global: {}
+ }
+ };
+
+ const rtdUserObj1 = {
+ name: 'anonymised.io',
+ ext: {
+ segtax: 503
+ },
+ segment: [
+ {
+ id: 'TCZPQOWPEJG3MJOTUQUF793A'
+ },
+ {
+ id: '93SUG3H540WBJMYNT03KX8N3'
+ }
+ ]
+ };
+
+ getDataFromLocalStorageStub.withArgs('cohort_ids')
+ .returns(JSON.stringify(['TCZPQOWPEJG3MJOTUQUF793A', '93SUG3H540WBJMYNT03KX8N3']));
+
+ getRealTimeData(bidConfig, () => {}, rtdConfig, {});
+ expect(bidConfig.ortb2Fragments.global.user.data).to.deep.include.members([rtdUserObj1]);
+ expect(bidConfig.ortb2Fragments.global.user.keywords).to.be.undefined;
+ });
+
+ it('gets rtd from local storage and set to ortb2.user.keywords for appnexus bidders parameter', function() {
+ const rtdConfig = {
+ params: {
+ cohortStorageKey: 'cohort_ids',
+ bidders: ['smartadserver', 'appnexus'],
+ segtax: 503
+ }
+ };
+
+ const bidConfig = {
+ ortb2Fragments: {
+ global: {}
+ }
+ };
+
+ const rtdUserObj1 = {
+ name: 'anonymised.io',
+ ext: {
+ segtax: 503
+ },
+ segment: [
+ {
+ id: 'TCZPQOWPEJG3MJOTUQUF793A'
+ },
+ {
+ id: '93SUG3H540WBJMYNT03KX8N3'
+ }
+ ]
+ };
+
+ getDataFromLocalStorageStub.withArgs('cohort_ids')
+ .returns(JSON.stringify(['TCZPQOWPEJG3MJOTUQUF793A', '93SUG3H540WBJMYNT03KX8N3']));
+
+ getRealTimeData(bidConfig, () => {}, rtdConfig, {});
+ expect(bidConfig.ortb2Fragments.global.user.data).to.deep.include.members([rtdUserObj1]);
+ expect(bidConfig.ortb2Fragments.global.user.keywords).to.include('perid=TCZPQOWPEJG3MJOTUQUF793A');
+ expect(bidConfig.ortb2Fragments.global.user.keywords).to.include('perid=93SUG3H540WBJMYNT03KX8N3');
+ });
+
+ it('gets rtd from local storage and set to ortb2.user.data if `bidders` parameter undefined', function() {
+ const rtdConfig = {
+ params: {
+ cohortStorageKey: 'cohort_ids',
+ segtax: 503
+ }
+ };
+
+ const bidConfig = {
+ ortb2Fragments: {
+ global: {}
+ }
+ };
+
+ const rtdUserObj1 = {
+ name: 'anonymised.io',
+ ext: {
+ segtax: 503
+ },
+ segment: [
+ {
+ id: 'TCZPQOWPEJG3MJOTUQUF793A'
+ },
+ {
+ id: '93SUG3H540WBJMYNT03KX8N3'
+ }
+ ]
+ };
+
+ getDataFromLocalStorageStub.withArgs('cohort_ids')
+ .returns(JSON.stringify(['TCZPQOWPEJG3MJOTUQUF793A', '93SUG3H540WBJMYNT03KX8N3']));
+
+ getRealTimeData(bidConfig, () => {}, rtdConfig, {});
+ expect(bidConfig.ortb2Fragments.global.user.data).to.deep.include.members([rtdUserObj1]);
+ expect(bidConfig.ortb2Fragments.global.user.keywords).to.be.undefined;
+ });
+
+ it('do not set rtd if `cohortStorageKey` parameter undefined', function() {
+ const rtdConfig = {
+ params: {
+ bidders: ['smartadserver']
+ }
+ };
+
+ const bidConfig = {
+ ortb2Fragments: {
+ global: {}
+ }
+ };
+
+ getDataFromLocalStorageStub.withArgs('cohort_ids')
+ .returns(JSON.stringify(['randomsegmentid']));
+
+ getRealTimeData(bidConfig, () => {}, rtdConfig, {});
+ expect(bidConfig.ortb2Fragments.global.user).to.be.undefined;
+ });
+
+ it('do not set rtd if local storage empty', function() {
+ const rtdConfig = {
+ params: {
+ cohortStorageKey: 'cohort_ids',
+ segtax: 503
+ }
+ };
+
+ const bidConfig = {};
+
+ getDataFromLocalStorageStub.withArgs('cohort_ids')
+ .returns(null);
+
+ expect(config.getConfig().ortb2).to.be.undefined;
+ getRealTimeData(bidConfig, () => {}, rtdConfig, {});
+ expect(config.getConfig().ortb2).to.be.undefined;
+ });
+
+ it('do not set rtd if local storage has incorrect value', function() {
+ const rtdConfig = {
+ params: {
+ cohortStorageKey: 'cohort_ids',
+ segtax: 503
+ }
+ };
+
+ const bidConfig = {};
+
+ getDataFromLocalStorageStub.withArgs('cohort_ids')
+ .returns('wrong cohort ids value');
+
+ expect(config.getConfig().ortb2).to.be.undefined;
+ getRealTimeData(bidConfig, () => {}, rtdConfig, {});
+ expect(config.getConfig().ortb2).to.be.undefined;
+ });
+
+ it('should initialize and return with config', function () {
+ expect(getRealTimeData(testReqBidsConfigObj, onDone, cmoduleConfig)).to.equal(undefined)
+ });
+ });
+});
diff --git a/test/spec/modules/idWardRtdProvider_spec.js b/test/spec/modules/idWardRtdProvider_spec.js
index 924a3794c7b..d1601f058ff 100644
--- a/test/spec/modules/idWardRtdProvider_spec.js
+++ b/test/spec/modules/idWardRtdProvider_spec.js
@@ -52,7 +52,7 @@ describe('idWardRtdProvider', function() {
};
const rtdUserObj1 = {
- name: 'id-ward.com',
+ name: 'anonymised.io',
ext: {
segtax: 503
},
@@ -109,7 +109,7 @@ describe('idWardRtdProvider', function() {
expect(config.getConfig().ortb2).to.be.undefined;
});
- it('should initalise and return with config', function () {
+ it('should initialize and return with config', function () {
expect(getRealTimeData(testReqBidsConfigObj, onDone, cmoduleConfig)).to.equal(undefined)
});
});