Skip to content

Commit 9f6f421

Browse files
committed
Support IAD SDA test in Permutive module
Updates the Permutive RTD module to support a test for segmentation with the new IAB standard data taxonomy. Initially we are mapping a small selection of Permutive to IAB cohort IDs and including these in the ORTB2 object. We also set the `segtax` value appropriately for the Index exchange, which we're using for this test.
1 parent 15f7ec1 commit 9f6f421

File tree

2 files changed

+76
-14
lines changed

2 files changed

+76
-14
lines changed

modules/permutiveRtdProvider.js

+49-10
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ function init (moduleConfig, userConsent) {
3030
export function initSegments (reqBidsConfigObj, callback, customModuleConfig) {
3131
const permutiveOnPage = isPermutiveOnPage()
3232
const moduleConfig = getModuleConfig(customModuleConfig)
33-
const segmentData = getSegments(moduleConfig.params.maxSegs)
33+
const segmentData = getSegments(moduleConfig.params.maxSegs, segmentIdTransformationsByBidder)
3434

3535
setSegments(reqBidsConfigObj, moduleConfig, segmentData)
3636

@@ -70,11 +70,12 @@ export function setBidderRtb (auctionDetails, customModuleConfig) {
7070
const moduleConfig = getModuleConfig(customModuleConfig)
7171
const acBidders = deepAccess(moduleConfig, 'params.acBidders')
7272
const maxSegs = deepAccess(moduleConfig, 'params.maxSegs')
73-
const segmentData = getSegments(maxSegs)
73+
const segmentData = getSegments(maxSegs, segmentIdTransformationsByBidder)
7474

7575
acBidders.forEach(function (bidder) {
7676
const currConfig = bidderConfig[bidder] || {}
77-
const nextConfig = mergeOrtbConfig(currConfig, segmentData)
77+
const extData = extensionDataByBidder[bidder] || {}
78+
const nextConfig = mergeOrtbConfig(currConfig, segmentData, extData)
7879

7980
config.setBidderConfig({
8081
bidders: [bidder],
@@ -84,12 +85,13 @@ export function setBidderRtb (auctionDetails, customModuleConfig) {
8485
}
8586

8687
/**
87-
* Merges segments into existing bidder config
88+
* Merges segments and extension data into existing bidder config
8889
* @param {Object} currConfig - Current bidder config
8990
* @param {Object} segmentData - Segment data
91+
* @param {Object} extData - Exchange-specific extension data
9092
* @return {Object} Merged ortb2 object
9193
*/
92-
function mergeOrtbConfig (currConfig, segmentData) {
94+
function mergeOrtbConfig (currConfig, segmentData, extData) {
9395
const segment = segmentData.ac.map(seg => {
9496
return { id: seg }
9597
})
@@ -98,7 +100,7 @@ function mergeOrtbConfig (currConfig, segmentData) {
98100
const currSegments = deepAccess(ortbConfig, 'ortb2.user.data') || []
99101
const userSegment = currSegments
100102
.filter(el => el.name !== name)
101-
.concat({ name, segment })
103+
.concat({ name, segment, ext: extData })
102104

103105
deepSetValue(ortbConfig, 'ortb2.user.data', userSegment)
104106

@@ -225,9 +227,10 @@ export function isPermutiveOnPage () {
225227
/**
226228
* Get all relevant segment IDs in an object
227229
* @param {number} maxSegs - Maximum number of segments to be included
230+
* @param {Object} bidderTransformations - object containing functions to transform segment IDs, keyed by bidder ID
228231
* @return {Object}
229232
*/
230-
export function getSegments (maxSegs) {
233+
export function getSegments (maxSegs, bidderTransformations) {
231234
const legacySegs = readSegments('_psegs').map(Number).filter(seg => seg >= 1000000).map(String)
232235
const _ppam = readSegments('_ppam')
233236
const _pcrprs = readSegments('_pcrprs')
@@ -236,11 +239,16 @@ export function getSegments (maxSegs) {
236239
ac: [..._pcrprs, ..._ppam, ...legacySegs],
237240
rubicon: readSegments('_prubicons'),
238241
appnexus: readSegments('_papns'),
239-
gam: readSegments('_pdfps')
242+
gam: readSegments('_pdfps'),
243+
ix: legacySegs
240244
}
241245

242-
for (const type in segments) {
243-
segments[type] = segments[type].slice(0, maxSegs)
246+
for (const bidder in segments) {
247+
segments[bidder] = segments[bidder].slice(0, maxSegs)
248+
249+
if (bidderTransformations.hasOwnProperty(bidder)) {
250+
segments[bidder] = bidderTransformations[bidder](segments[bidder])
251+
}
244252
}
245253

246254
return segments
@@ -260,6 +268,37 @@ function readSegments (key) {
260268
}
261269
}
262270

271+
/**
272+
* Bidder-specific extension data for use in the ORTB2 object.
273+
*/
274+
const extensionDataByBidder = {
275+
ix: {
276+
segtax: '4'
277+
}
278+
}
279+
280+
/**
281+
* Bidder-specific functions to apply to an array of segment IDs.
282+
* Each function should return an a new array of transformed segment IDs.
283+
*/
284+
const segmentIdTransformationsByBidder = {
285+
ix: segments => segments.map(iabSegmentId).filter(id => id != 'unknown')
286+
}
287+
288+
/**
289+
* Transform a Permutive segment ID into an IAB audience taxonomy ID.
290+
* Currently uses a hardcoded mapping to support an initial test of this functionality.
291+
* @param {string} permutiveSegmentId
292+
* @return {string} IAB audience taxonomy ID associated with the Permutive segment ID
293+
*/
294+
function iabSegmentId(permutiveSegmentId) {
295+
const iabIdsByPermutiveId = {
296+
1: '1' // TODO
297+
}
298+
299+
return iabIdsByPermutiveId[permutiveSegmentId] || 'unknown'
300+
}
301+
263302
/** @type {RtdSubmodule} */
264303
export const permutiveSubmodule = {
265304
name: MODULE_NAME,

test/spec/modules/permutiveRtdProvider_spec.js

+27-4
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,17 @@ describe('permutiveRtdProvider', function () {
4242
return { id: seg }
4343
})
4444

45+
const expectedBidderExtensionData = {
46+
ix: {
47+
segtax: '4'
48+
}
49+
}
50+
4551
setBidderRtb({}, moduleConfig)
4652

4753
acBidders.forEach(bidder => {
4854
expect(bidderConfig[bidder].ortb2.user.data).to.deep.include.members([{
55+
ext: expectedBidderExtensionData[bidder] || {},
4956
name: 'permutive.com',
5057
segment: expectedTargetingData
5158
}])
@@ -91,11 +98,22 @@ describe('permutiveRtdProvider', function () {
9198
describe('Getting segments', function () {
9299
it('should retrieve segments in the expected structure', function () {
93100
const data = transformedTargeting()
94-
expect(getSegments(250)).to.deep.equal(data)
101+
expect(getSegments(250, {})).to.deep.equal(data)
102+
})
103+
it('should apply bidder transformations', function () {
104+
const transformedSegments = ['1', '2', '3']
105+
const transformations = {
106+
ix: segments => transformedSegments
107+
}
108+
109+
const expectedSegmentData = transformedTargeting()
110+
expectedSegmentData['ix'] = transformedSegments
111+
112+
expect(getSegments(10, transformations)).to.deep.equal(expectedSegmentData)
95113
})
96114
it('should enforce max segments', function () {
97115
const max = 1
98-
const segments = getSegments(max)
116+
const segments = getSegments(max, {})
99117

100118
for (const key in segments) {
101119
expect(segments[key]).to.have.length(max)
@@ -293,6 +311,10 @@ describe('permutiveRtdProvider', function () {
293311
expect(isAcEnabled({ params: { acBidders: ['ozone'] } }, 'ozone')).to.equal(true)
294312
expect(isAcEnabled({ params: { acBidders: ['kjdvb'] } }, 'ozone')).to.equal(false)
295313
})
314+
it('checks if AC is enabled for Index', function () {
315+
expect(isAcEnabled({ params: { acBidders: ['ix'] } }, 'ix')).to.equal(true)
316+
expect(isAcEnabled({ params: { acBidders: ['kjdvb'] } }, 'ix')).to.equal(false)
317+
})
296318
})
297319
})
298320

@@ -313,7 +335,7 @@ function getConfig () {
313335
name: 'permutive',
314336
waitForIt: true,
315337
params: {
316-
acBidders: ['appnexus', 'rubicon', 'ozone', 'trustx'],
338+
acBidders: ['appnexus', 'rubicon', 'ozone', 'trustx', 'ix'],
317339
maxSegs: 500
318340
}
319341
}
@@ -326,7 +348,8 @@ function transformedTargeting () {
326348
ac: [...data._pcrprs, ...data._ppam, ...data._psegs.filter(seg => seg >= 1000000)],
327349
appnexus: data._papns,
328350
rubicon: data._prubicons,
329-
gam: data._pdfps
351+
gam: data._pdfps,
352+
ix: data._psegs.filter(seg => seg >= 1000000)
330353
}
331354
}
332355

0 commit comments

Comments
 (0)