Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
33 changes: 28 additions & 5 deletions modules/permutiveRtdProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ export function getModuleConfig(customModuleConfig) {
acBidders: [],
overwrites: {},
enforceVendorConsent: false,
bidders: {
msft: {
customCohorts: { source: 'ls', key: '_papns' }
},
},
},
},
permutiveModuleConfig,
Expand All @@ -108,13 +113,15 @@ export function setBidderRtb (bidderOrtb2, moduleConfig, segmentData) {
const acBidders = deepAccess(moduleConfig, 'params.acBidders')
const maxSegs = deepAccess(moduleConfig, 'params.maxSegs')
const transformationConfigs = deepAccess(moduleConfig, 'params.transformations') || []
const biddersConfig = deepAccess(moduleConfig, 'params.bidders') || {}

const ssps = segmentData?.ssp?.ssps ?? []
const sspCohorts = segmentData?.ssp?.cohorts ?? []
const topics = segmentData?.topics ?? {}

const bidders = new Set([...acBidders, ...ssps])
bidders.forEach(function (bidder) {
const bidderConfig = biddersConfig[bidder] || {};
const currConfig = { ortb2: bidderOrtb2[bidder] || {} }

let cohorts = []
Expand All @@ -129,11 +136,29 @@ export function setBidderRtb (bidderOrtb2, moduleConfig, segmentData) {
cohorts = [...new Set([...cohorts, ...sspCohorts])].slice(0, maxSegs)
}

const nextConfig = updateOrtbConfig(bidder, currConfig, cohorts, sspCohorts, topics, transformationConfigs, segmentData)
const customCohortsData = getCustomCohortsData(bidderConfig, bidder, segmentData, maxSegs)

const nextConfig = updateOrtbConfig(bidder, currConfig, cohorts, sspCohorts, topics, transformationConfigs, customCohortsData)
bidderOrtb2[bidder] = nextConfig.ortb2
})
}

/**
* Resolves custom cohorts data for a bidder, reading from localStorage if configured.
* @param {Object} bidderCfg - Bidder-specific configuration from params.bidders
* @param {string} bidder - The bidder identifier
* @param {Object} segmentData - Segment data grouped by bidder or type
* @param {number} maxSegs - Maximum number of segments
* @return {string[]} Custom cohort IDs
*/
function getCustomCohortsData (bidderCfg, bidder, segmentData, maxSegs) {
const customCohorts = bidderCfg?.customCohorts
if (customCohorts?.source === 'ls' && customCohorts?.key) {
return makeSafe(() => readSegments(customCohorts.key, []).map(String).slice(0, maxSegs)) || []
}
return deepAccess(segmentData, bidder) || []
}

/**
* Updates `user.data` object in existing bidder config with Permutive segments
* @param {string} bidder - The bidder identifier
Expand All @@ -143,14 +168,12 @@ export function setBidderRtb (bidderOrtb2, moduleConfig, segmentData) {
* @param {Object} topics - Privacy Sandbox Topics, keyed by IAB taxonomy version (600, 601, etc.)
* @param {Object[]} transformationConfigs - array of objects with `id` and `config` properties, used to determine
* the transformations on user data to include the ORTB2 object
* @param {Object} segmentData - The segments available for targeting
* @param {string[]} customCohortsData - Custom cohort IDs for this bidder
* @return {Object} Merged ortb2 object
*/
function updateOrtbConfig(bidder, currConfig, segmentIDs, sspSegmentIDs, topics, transformationConfigs, segmentData) {
function updateOrtbConfig(bidder, currConfig, segmentIDs, sspSegmentIDs, topics, transformationConfigs, customCohortsData) {
logger.logInfo(`Current ortb2 config`, { bidder, config: currConfig })

const customCohortsData = deepAccess(segmentData, bidder) || []

const name = 'permutive.com'

const permutiveUserData = {
Expand Down
65 changes: 65 additions & 0 deletions test/spec/modules/permutiveCombined_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ describe('permutiveRtdProvider', function () {
acBidders: [],
overwrites: {},
enforceVendorConsent: false,
bidders: {
msft: {
customCohorts: { source: 'ls', key: '_papns' }
},
},
},
})

Expand Down Expand Up @@ -689,6 +694,66 @@ describe('permutiveRtdProvider', function () {
})
})
})

describe('bidders config with customCohorts', function () {
it('should read custom cohorts from localStorage for msft bidder using customCohorts config', function () {
const segmentsData = transformedTargeting()
const expectedAppnexusCohorts = segmentsData.appnexus

const moduleConfig = {
name: 'permutive',
waitForIt: true,
params: {
acBidders: ['msft'],
maxSegs: 500,
bidders: {
msft: {
customCohorts: { source: 'ls', key: '_papns' }
}
}
}
}
const bidderConfig = {}

setBidderRtb(bidderConfig, moduleConfig, segmentsData)

expect(bidderConfig['msft'].user.data).to.deep.include.members([
{
name: 'permutive',
segment: expectedAppnexusCohorts.map(id => ({ id })),
},
])

expectedAppnexusCohorts.forEach(id => {
expect(bidderConfig['msft'].user.keywords).to.include(`permutive=${id}`)
})
})

it('should fall back to segmentData lookup when customCohorts is not configured', function () {
const segmentsData = transformedTargeting()

const moduleConfig = {
name: 'permutive',
waitForIt: true,
params: {
acBidders: ['appnexus'],
maxSegs: 500,
bidders: {}
}
}
const bidderConfig = {}

setBidderRtb(bidderConfig, moduleConfig, segmentsData)

const expectedAppnexusCohorts = segmentsData.appnexus
expect(bidderConfig['appnexus'].user.data).to.deep.include.members([
{
name: 'permutive',
segment: expectedAppnexusCohorts.map(id => ({ id })),
},
])
})
})
})

describe('Getting segments', function () {
Expand Down
Loading