diff --git a/integrationExamples/gpt/audigentSegments_example.html b/integrationExamples/gpt/audigentSegments_example.html
new file mode 100644
index 00000000000..9b72da76d23
--- /dev/null
+++ b/integrationExamples/gpt/audigentSegments_example.html
@@ -0,0 +1,262 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Audigent Segments Prebid
+
+
+
+
+TDID:
+
+
+
+Audigent Segments:
+
+
+
+
diff --git a/modules/audigentRtdProvider.js b/modules/audigentRtdProvider.js
new file mode 100644
index 00000000000..8b45287bddc
--- /dev/null
+++ b/modules/audigentRtdProvider.js
@@ -0,0 +1,138 @@
+/**
+ * This module adds audigent provider to the real time data module
+ * The {@link module:modules/realTimeData} module is required
+ * The module will fetch segments from audigent server
+ * @module modules/audigentRtdProvider
+ * @requires module:modules/realTimeData
+ */
+
+/**
+ * @typedef {Object} ModuleParams
+ * @property {string} siteKey
+ * @property {string} pubKey
+ * @property {string} url
+ * @property {?string} keyName
+ * @property {number} auctionDelay
+ */
+
+import {config} from '../src/config.js';
+import {getGlobal} from '../src/prebidGlobal.js';
+import * as utils from '../src/utils.js';
+import {submodule} from '../src/hook.js';
+import {ajax} from '../src/ajax.js';
+
+/** @type {string} */
+const MODULE_NAME = 'realTimeData';
+
+/** @type {ModuleParams} */
+let _moduleParams = {};
+
+/**
+ * XMLHttpRequest to get data form audigent server
+ * @param {string} url server url with query params
+ */
+
+export function setData(data) {
+ utils.setDataInLocalStorage('__adgntseg', JSON.stringify(data));
+}
+
+function getSegments(adUnits, onDone) {
+ try {
+ let jsonData = utils.getDataFromLocalStorage('__adgntseg');
+ if (jsonData) {
+ let data = JSON.parse(jsonData);
+ if (data.audigent_segments) {
+ let dataToReturn = adUnits.reduce((rp, cau) => {
+ const adUnitCode = cau && cau.code;
+ if (!adUnitCode) { return rp }
+ rp[adUnitCode] = data;
+ return rp;
+ }, {});
+
+ onDone(dataToReturn);
+ return;
+ }
+ }
+ getSegmentsAsync(adUnits, onDone);
+ } catch (e) {
+ getSegmentsAsync(adUnits, onDone);
+ }
+}
+
+function getSegmentsAsync(adUnits, onDone) {
+ const userIds = (getGlobal()).getUserIds();
+ let tdid = null;
+
+ if (userIds && userIds['tdid']) {
+ tdid = userIds['tdid'];
+ } else {
+ onDone({});
+ }
+
+ const url = `https://seg.ad.gt/api/v1/rtb_segments?tdid=${tdid}`;
+
+ ajax(url, {
+ success: function (response, req) {
+ if (req.status === 200) {
+ try {
+ const data = JSON.parse(response);
+ if (data && data.audigent_segments) {
+ setData(data);
+ let dataToReturn = adUnits.reduce((rp, cau) => {
+ const adUnitCode = cau && cau.code;
+ if (!adUnitCode) { return rp }
+ rp[adUnitCode] = data;
+ return rp;
+ }, {});
+
+ onDone(dataToReturn);
+ } else {
+ onDone({});
+ }
+ } catch (err) {
+ utils.logError('unable to parse audigent segment data');
+ onDone({})
+ }
+ } else if (req.status === 204) {
+ // unrecognized site key
+ onDone({});
+ }
+ },
+ error: function () {
+ onDone({});
+ utils.logError('unable to get audigent segment data');
+ }
+ }
+ );
+}
+
+/** @type {RtdSubmodule} */
+export const audigentSubmodule = {
+ /**
+ * used to link submodule with realTimeData
+ * @type {string}
+ */
+ name: 'audigent',
+ /**
+ * get data and send back to realTimeData module
+ * @function
+ * @param {adUnit[]} adUnits
+ * @param {function} onDone
+ */
+ getData: getSegments
+};
+
+export function init(config) {
+ const confListener = config.getConfig(MODULE_NAME, ({realTimeData}) => {
+ try {
+ _moduleParams = realTimeData.dataProviders && realTimeData.dataProviders.filter(pr => pr.name && pr.name.toLowerCase() === 'audigent')[0].params;
+ _moduleParams.auctionDelay = realTimeData.auctionDelay;
+ } catch (e) {
+ _moduleParams = {};
+ }
+ confListener();
+ });
+}
+
+submodule('realTimeData', audigentSubmodule);
+init(config);
diff --git a/modules/audigentRtdProvider.md b/modules/audigentRtdProvider.md
new file mode 100644
index 00000000000..47bcbbbf951
--- /dev/null
+++ b/modules/audigentRtdProvider.md
@@ -0,0 +1,52 @@
+Audigent is a next-generation data management platform and a first-of-a-kind
+"data agency" containing some of the most exclusive content-consuming audiences
+across desktop, mobile and social platforms.
+
+This real-time data module provides first-party Audigent segments that can be
+attached to bid request objects destined for different SSPs in order to optimize
+targeting. Audigent maintains a large database of first-party Tradedesk Unified
+ID to third party segment mappings that can now be queried at bid-time.
+
+Usage:
+
+Compile the audigent RTD module into your Prebid build:
+
+`gulp build --modules=userId,unifiedIdSystem,rtdModule,audigentRtdProvider,rubiconBidAdapter`
+
+Audigent segments will then be attached to each bid request objects in
+`bid.realTimeData.audigent_segments`
+
+The format of the segments is a per-SSP mapping:
+
+```
+{
+ 'appnexus': ['anseg1', 'anseg2'],
+ 'google': ['gseg1', 'gseg2']
+}
+```
+
+If a given SSP's API backend supports segment fields, they can then be
+attached prior to the bid request being sent:
+
+```
+pbjs.requestBids({bidsBackHandler: addAudigentSegments});
+
+function addAudigentSegments() {
+ for (i = 0; i < adUnits.length; i++) {
+ let adUnit = adUnits[i];
+ for (j = 0; j < adUnit.bids.length; j++) {
+ adUnit.bids[j].userId.lipb.segments = adUnit.bids[j].realTimeData.audigent_segments['rubicon'];
+ }
+ }
+}
+```
+
+To view an example of the segments returned by Audigent's backends:
+
+`gulp serve --modules=userId,unifiedIdSystem,rtdModule,audigentRtdProvider,rubiconBidAdapter`
+
+and then point your browser at:
+
+`http://localhost:9999/integrationExamples/gpt/audigentSegments_example.html`
+
+
diff --git a/test/spec/modules/realTimeModule_spec.js b/test/spec/modules/realTimeModule_spec.js
index bf25b3f0a04..89b44333636 100644
--- a/test/spec/modules/realTimeModule_spec.js
+++ b/test/spec/modules/realTimeModule_spec.js
@@ -10,6 +10,10 @@ import {
isIdMatchingAdUnit,
setData
} from 'modules/browsiRtdProvider.js';
+import {
+ init as audigentInit,
+ setData as setAudigentData
+} from 'modules/audigentRtdProvider.js';
import {config} from 'src/config.js';
import {makeSlot} from '../integration/faker/googletag.js';
@@ -27,8 +31,9 @@ describe('Real time module', function() {
'pubKey': 'testPub',
'keyName': 'bv'
}
+ }, {
+ 'name': 'audigent'
}]
-
}
};
@@ -58,6 +63,10 @@ describe('Real time module', function() {
}
};
+ const audigentSegments = {
+ audigent_segments: {'a': 1, 'b': 2}
+ }
+
function getAdUnitMock(code = 'adUnit-code') {
return {
code,
@@ -189,4 +198,46 @@ describe('Real time module', function() {
expect(test4).to.equal(true);
})
});
+
+ describe('Real time module with Audigent provider', function() {
+ afterEach(function () {
+ $$PREBID_GLOBAL$$.requestBids.removeAll();
+ });
+
+ let targeting = [];
+ init(config);
+ audigentInit(config);
+ config.setConfig(conf);
+ setAudigentData(audigentSegments);
+
+ it('check module using requestBidsHook', function () {
+ let adUnits1 = [getAdUnitMock('audigentAd_1')];
+ let targeting = [];
+ let dataReceived = null;
+
+ // set slot
+ const slotsB = createSlots();
+ window.googletag.pubads().setSlots(slotsB);
+
+ function afterBidHook(data) {
+ dataReceived = data;
+ slotsB.map(s => {
+ targeting = [];
+ s.getTargeting().map(value => {
+ targeting.push(Object.keys(value).toString());
+ });
+ });
+ }
+
+ requestBidsHook(afterBidHook, {adUnits: adUnits1});
+ setTimeout(() => {
+ dataReceived.adUnits.forEach(unit => {
+ unit.bids.forEach(bid => {
+ expect(bid.realTimeData).to.have.property('audigent_segments');
+ expect(bid.realTimeData.audigent_segments).to.deep.equal(audigentSegments.audigent_segments);
+ });
+ });
+ }, 200);
+ });
+ });
});