Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
20 changes: 12 additions & 8 deletions modules/permutiveRtdProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import { MODULE_TYPE_RTD } from '../src/activities/modules.js';

/**
* @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule
* @typedef {import('./permutiveRtdProviderTypes.d.ts').PermutiveRtdProviderConfig} PermutiveRtdProviderConfig
* @typedef {import('./permutiveRtdProviderTypes.d.ts').PermutiveRtdProviderParams} PermutiveRtdProviderParams
* @typedef {import('./permutiveRtdProviderTypes.d.ts').PermutiveBidderConfig} PermutiveBidderConfig
* @typedef {import('./permutiveRtdProviderTypes.d.ts').PermutiveTransformationConfig} PermutiveTransformationConfig
*/

const MODULE_NAME = 'permutive'
Expand Down Expand Up @@ -77,8 +81,8 @@ function getParamsFromPermutive() {
* As items with a higher priority will be deeply merged into the previous config, deep merges are performed by
* reversing the priority order.
*
* @param {Object} customModuleConfig - Publisher config for module
* @return {Object} Deep merges of the default, Permutive and custom config.
* @param {PermutiveRtdProviderConfig} customModuleConfig - Publisher config for module
* @return {PermutiveRtdProviderConfig} Deep merges of the default, Permutive and custom config.
*/
export function getModuleConfig(customModuleConfig) {
// Use the params from Permutive if available, otherwise fallback to the cached value set by Permutive.
Expand All @@ -102,7 +106,7 @@ export function getModuleConfig(customModuleConfig) {
/**
* Sets ortb2 config for ac bidders
* @param {Object} bidderOrtb2 - The ortb2 object for the all bidders
* @param {Object} moduleConfig - Publisher config for module
* @param {PermutiveRtdProviderConfig} moduleConfig - Publisher config for module
* @param {Object} segmentData - Segment data grouped by bidder or type
*/
export function setBidderRtb (bidderOrtb2, moduleConfig, segmentData) {
Expand All @@ -115,7 +119,7 @@ export function setBidderRtb (bidderOrtb2, moduleConfig, segmentData) {
const sspCohorts = segmentData?.ssp?.cohorts ?? []
const topics = segmentData?.topics ?? {}

const bidders = new Set([...acBidders, ...ssps])
const bidders = new Set([...acBidders, ...ssps, ...Object.keys(biddersConfig)])
bidders.forEach(function (bidder) {
const bidderConfig = biddersConfig[bidder] || {};
const currConfig = { ortb2: bidderOrtb2[bidder] || {} }
Expand All @@ -141,7 +145,7 @@ export function setBidderRtb (bidderOrtb2, moduleConfig, segmentData) {

/**
* Resolves custom cohorts data for a bidder, reading from localStorage if configured.
* @param {Object} bidderCfg - Bidder-specific configuration from params.bidders
* @param {PermutiveBidderConfig} 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
Expand All @@ -162,7 +166,7 @@ function getCustomCohortsData (bidderCfg, bidder, segmentData, maxSegs) {
* @param {string[]} segmentIDs - Permutive segment IDs
* @param {string[]} sspSegmentIDs - Permutive SSP segment IDs
* @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
* @param {PermutiveTransformationConfig[]} transformationConfigs - array of objects with `id` and `config` properties, used to determine
* the transformations on user data to include the ORTB2 object
* @param {string[]} customCohortsData - Custom cohort IDs for this bidder
* @return {Object} Merged ortb2 object
Expand Down Expand Up @@ -258,7 +262,7 @@ function updateOrtbConfig(bidder, currConfig, segmentIDs, sspSegmentIDs, topics,
/**
* Set segments on bid request object
* @param {Object} reqBidsConfigObj - Bid request object
* @param {Object} moduleConfig - Module configuration
* @param {PermutiveRtdProviderConfig} moduleConfig - Module configuration
* @param {Object} segmentData - Segment object
*/
function setSegments (reqBidsConfigObj, moduleConfig, segmentData) {
Expand Down Expand Up @@ -314,7 +318,7 @@ function getCustomBidderFn (moduleConfig, bidder) {

/**
* Check whether ac is enabled for bidder
* @param {Object} moduleConfig - Module configuration
* @param {PermutiveRtdProviderConfig} moduleConfig - Module configuration
* @param {string} bidder - Bidder name
* @return {boolean}
*/
Expand Down
2 changes: 1 addition & 1 deletion modules/permutiveRtdProvider.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ as well as enabling settings for specific use cases mentioned above (e.g. acbidd
| params.acBidders | String[] | An array of bidder codes to share cohorts with in certain versions of Prebid, see below | `[]` |
| params.maxSegs | Integer | Maximum number of cohorts to be included in either the `permutive` or `p_standard` key-value. | `500` |
| params.enforceVendorConsent | Boolean | When `true`, require TCF vendor consent for Permutive (vendor 361). See note below. | `false` |
| params.bidders | Object | Per-bidder configuration for custom cohort sources. Keys are bidder codes. | `{}` |
| params.bidders | Object | Per-bidder configuration for custom cohort sources. Keys are bidder codes; listing a bidder here also causes the module to write ortb2 data for that bidder, even if it is not in `acBidders` or on Permutive's SSP list. | `{}` |
Comment thread
patmmccann marked this conversation as resolved.
| params.bidders.\<bidder\>.customCohorts | Object | Custom cohorts source configuration for a specific bidder. | - |
| params.bidders.\<bidder\>.customCohorts.source | String | Storage type to read custom cohorts from. Currently only `'ls'` (localStorage) is supported. | - |
| params.bidders.\<bidder\>.customCohorts.key | String | The localStorage key to read custom cohorts from. | - |
Expand Down
89 changes: 89 additions & 0 deletions modules/permutiveRtdProviderTypes.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* Source for custom cohorts.
*
* Currently only `ls` (localStorage) is supported.
*/
export type PermutiveCustomCohortsSource = 'ls';

export interface PermutiveCustomCohortsConfig {
/**
* Where to read the custom cohorts from. Currently only `ls` (localStorage) is supported.
*/
source: PermutiveCustomCohortsSource;
/**
* The localStorage key to read the custom cohort IDs from.
* The value must be a JSON-encoded array of cohort IDs.
*/
key: string;
}

export interface PermutiveBidderConfig {
/**
* Custom cohort source for this bidder. When set, the module will read cohort
* IDs from the configured source and attach them to the bidder's ortb2 payload.
*/
customCohorts?: PermutiveCustomCohortsConfig;
}

export interface PermutiveIabTransformationConfig {
/**
* IAB audience taxonomy version (e.g. `4` for v1.1).
*/
segtax: number;
/**
* Mapping of Permutive segment IDs (keys) to IAB taxonomy IDs (values).
*/
iabIds: Record<string, string>;
}

export interface PermutiveTransformationConfig {
/**
* Transformation identifier. Currently only `iab` is supported.
*/
id: 'iab';
/**
* Transformation-specific configuration.
*/
config: PermutiveIabTransformationConfig;
}

export interface PermutiveRtdProviderParams {
/**
* Bidder codes to share Permutive cohorts with via the Audience Connector
* (`p_standard` / `ac` segments).
*/
acBidders?: string[];
/**
* Maximum number of cohorts to include in either the `permutive` or
* `p_standard` key-value. Defaults to `500`.
*/
maxSegs?: number;
/**
* When `true`, require TCF vendor consent for Permutive (vendor 361).
* Defaults to `false`.
*/
enforceVendorConsent?: boolean;
/**
* Per-bidder configuration for custom cohort sources. Keys are bidder codes.
* Listing a bidder here also causes the module to write ortb2 data for that
* bidder, even if it is not in `acBidders` or on Permutive's SSP list.
*/
bidders?: Record<string, PermutiveBidderConfig>;
/**
* Transformations to apply to `user.data` entries before they are written
* to the ortb2 payload.
*/
transformations?: PermutiveTransformationConfig[];
}

export interface PermutiveRtdProviderConfig {
/**
* When `true`, the auction waits for the Permutive SDK to reach real-time
* before completing the bid request data callback. Defaults to `false`.
*/
waitForIt?: boolean;
/**
* Module-specific parameters.
*/
params?: PermutiveRtdProviderParams;
}
34 changes: 34 additions & 0 deletions test/spec/modules/permutiveCombined_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,40 @@ describe('permutiveRtdProvider', function () {
},
])
})

it('should write ortb2 for a bidder configured only via params.bidders (not in acBidders or ssps)', function () {
const segmentsData = transformedTargeting()
const expectedAppnexusCohorts = segmentsData.appnexus

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

setBidderRtb(bidderConfig, moduleConfig, segmentsData)

expect(bidderConfig['msft']).to.not.be.undefined
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}`)
})
})
})
})

Expand Down
Loading