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

Audigent RTD configurable per-bidder segment mappings #5903

Merged
merged 26 commits into from
Nov 16, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 33 additions & 8 deletions integrationExamples/gpt/audigentSegments_example.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<html>
<head>
<script>

(function(window, document) {
if (!window.__cmp) {
window.__cmp = (function() {
Expand Down Expand Up @@ -90,11 +91,9 @@
},
bids: [
{
bidder: 'rubicon',
bidder: 'appnexus',
params: {
accountId: '1001',
siteId: '113932',
zoneId: '535510'
placementId: 13144370
}
}
]
Expand All @@ -108,11 +107,25 @@

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

var bidSegmentMappers = {
appnexus: function(bid, segments) {
if (!bid.params) {
bid.params = {}
}
if (!bid.params.user) {
bid.params.user = {}
}

bid.params.user.segments = segments;
}
}

pbjs.que.push(function() {
pbjs.setConfig({
debug: true,
Expand Down Expand Up @@ -232,17 +245,29 @@
auctionDelay: 1000
},
realTimeData: {
auctionDelay: 1000,
dataProviders: [{name: "audigent", waitForIt: true}]
auctionDelay: testAuctionDelay, // lower in real scenario to meet publisher spec
dataProviders: [
{
name: "audigent",
waitForIt: true,
params: {
mapSegments: ['appnexus'],
antlauzon marked this conversation as resolved.
Show resolved Hide resolved
segmentCache: false,
publisherId: 0
}

}
]
}
});
pbjs.addAdUnits(adUnits);

pbjs.requestBids({bidsBackHandler: sendAdserverRequest});
});

function sendAdserverRequest() {
document.getElementById('tdid').innerHTML = adUnits[0].bids[0].userId['tdid'];
document.getElementById('audigent_segments').innerHTML = JSON.stringify(adUnits[0].bids[0].audigent_segments);
document.getElementById('audigent_segments').innerHTML = JSON.stringify(adUnits[0].bids[0].params.user.segments);

if (pbjs.adserverRequestSent) return;
pbjs.adserverRequestSent = true;
Expand Down Expand Up @@ -294,7 +319,7 @@ <h2>Audigent Segments Prebid</h2>
<div id='tdid'>
</div>

Audigent Segments:
Audigent Segments (Appnexus):
<div id='audigent_segments'>
</div>
</body>
Expand Down
73 changes: 54 additions & 19 deletions modules/audigentRtdProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,54 @@ import {submodule} from '../src/hook.js';
import {ajax} from '../src/ajax.js';
import { getStorageManager } from '../src/storageManager.js';

const storage = getStorageManager();
export const storage = getStorageManager();

/** @type {string} */
const MODULE_NAME = 'realTimeData';
const SUBMODULE_NAME = 'audigent';
const HALOID_LOCAL_NAME = 'auHaloId';
const SEG_LOCAL_NAME = '__adgntseg';
export const HALOID_LOCAL_NAME = 'auHaloId';
export const SEG_LOCAL_NAME = '__adgntseg';

const set = (obj, path, val) => {
const keys = path.split('.');
const lastKey = keys.pop();
const lastObj = keys.reduce((obj, key) => obj[key] = obj[key] || {}, obj);
lastObj[lastKey] = lastObj[lastKey] || val;
};

/** bid adapter format segment augmentation functions */
const segmentMappers = {
appnexus: function(bid, segments) {
set(bid, 'params.user.segments', []);
bid.params.user.segments = bid.params.user.segments.concat(segments);
},
generic: function(bid, segments) {
bid.segments = segments;
antlauzon marked this conversation as resolved.
Show resolved Hide resolved
}
}

/**
* decorate adUnits with segment data
* @param {adUnit[]} adUnits
* @param {Object} data
*/
function addSegmentData(adUnits, data) {
export function addSegmentData(adUnits, data, config) {
adUnits.forEach(adUnit => {
set(adUnit, 'fpd.user.data.segments.audigent_segments', data);

if (adUnit.hasOwnProperty('bids')) {
adUnit.bids.forEach(bid => {
bid.audigent_segments = data;
try {
if (config.params.mapSegments && config.params.mapSegments[bid.bidder] && data[bid.bidder]) {
if (typeof config.params.mapSegments[bid.bidder] == 'function') {
config.params.mapSegments[bid.bidder](bid, data[bid.bidder]);
} else if (segmentMappers[bid.bidder]) {
segmentMappers[bid.bidder](bid, data[bid.bidder]);
}
}
} catch (err) {
utils.logError('audigent segment map error.');
}
})
}
})
Expand All @@ -43,16 +73,20 @@ function addSegmentData(adUnits, data) {
* @param {Object} config
* @param {Object} userConsent
*/
function getSegments(reqBidsConfigObj, onDone, config, userConsent) {
export function getSegments(reqBidsConfigObj, onDone, config, userConsent) {
const adUnits = reqBidsConfigObj.adUnits || getGlobal().adUnits;

let jsonData = storage.getDataFromLocalStorage(SEG_LOCAL_NAME);
if (jsonData) {
let data = JSON.parse(jsonData);
if (data.audigent_segments) {
addSegmentData(adUnits, data.audigent_segments);
onDone();
return;
if (config.params.segmentCache) {
let jsonData = storage.getDataFromLocalStorage(SEG_LOCAL_NAME);

if (jsonData) {
let data = JSON.parse(jsonData);

if (data.audigent_segments) {
addSegmentData(adUnits, data.audigent_segments, config);
onDone();
return;
}
}
}

Expand Down Expand Up @@ -88,10 +122,10 @@ function getSegments(reqBidsConfigObj, onDone, config, userConsent) {
* @param {Object} userConsent
* @param {Object} userIds
*/
function getSegmentsAsync(adUnits, onDone, config, userConsent, userIds) {
let reqParams = {}
export function getSegmentsAsync(adUnits, onDone, config, userConsent, userIds) {
let reqParams = {};
if (typeof config == 'object' && config != null && Object.keys(config).length > 0) {
reqParams = config.params
reqParams = config.params.requestParams;
}

const url = `https://seg.halo.ad.gt/api/v1/rtb_segments`;
Expand All @@ -101,7 +135,7 @@ function getSegmentsAsync(adUnits, onDone, config, userConsent, userIds) {
try {
const data = JSON.parse(response);
if (data && data.audigent_segments) {
addSegmentData(adUnits, data.audigent_segments);
addSegmentData(adUnits, data.audigent_segments, config);
onDone();
storage.setDataInLocalStorage(SEG_LOCAL_NAME, JSON.stringify(data));
} else {
Expand All @@ -128,10 +162,11 @@ function getSegmentsAsync(adUnits, onDone, config, userConsent, userIds) {

/**
* module init
* @param {Object} config
* @param {Object} provider
* @param {Objkect} userConsent
* @return {boolean}
*/
export function init(config) {
function init(provider, userConsent) {
return true;
}

Expand Down
75 changes: 34 additions & 41 deletions modules/audigentRtdProvider.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
## Audigent Real-time Data Submodule

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
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 quality user segmentation 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, Audigent Halo ID and other id provider mappings to various third-party
This real-time data module provides quality user segmentation 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, Audigent Halo ID and other id provider mappings to various third-party
segment types that are utilizable across different SSPs. With this module,
these segments can be retrieved and supplied to the SSP in real-time during
the bid request cycle.
Expand All @@ -16,58 +16,51 @@ the bid request cycle.

Compile the audigent RTD module into your Prebid build:

`gulp build --modules=userId,unifiedIdSystem,rtdModule,audigentRtdProvider,rubiconBidAdapter`
`gulp build --modules=userId,unifiedIdSystem,rtdModule,audigentRtdProvider,appnexusBidAdapter`

Configure Prebid to add the Audigent RTD Segment Handler:
```
pbjs.setConfig(
...
realTimeData: {
auctionDelay: 1000,
dataProviders: [
{
name: "audigent",
waitForIt: true
}
]
}
...
}
```

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:
The format of returned segments is a segment type mapping.

```
{
'appnexus': ['anseg1', 'anseg2'],
'google': ['gseg1', 'gseg2']
'appnexus': ['anseg1', 'anseg2'],
'pubmatic': ['pseg1', 'pseg2'],
'spotx': ['sseg1', 'sseg2']
}
```

If a given SSP's API backend supports segment fields, they can then be
attached prior to the bid request being sent:
Add the Audigent RTD provider to your Prebid config, and add any adapters
you would like to specifically provide segments for. Segments will be mapped
into the bid request objects for these adapters.

```
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].audigent_segments['rubicon'];
}
}
pbjs.setConfig(
...
realTimeData: {
auctionDelay: auctionDelay,
dataProviders: [
{
name: "audigent",
waitForIt: true,
params: {
mapSegments: {
'appnexus': true,
antlauzon marked this conversation as resolved.
Show resolved Hide resolved
},
segmentCache: false,
publisherId: 1234
}
}
]
}
...
}
```

### Testing

To view an example of available segments returned by Audigent's backends:

`gulp serve --modules=userId,unifiedIdSystem,rtdModule,audigentRtdProvider,rubiconBidAdapter`
`gulp serve --modules=userId,unifiedIdSystem,rtdModule,audigentRtdProvider,appnexusBidAdapter`

and then point your browser at:

Expand Down
Loading