-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Brandmetrics RTD Module: add new RTD module (#7756)
* First version of brandmetrics RTD- module * Implement brandmetricsRtdProvider * Add gdpr and usp consent- checks * Add user- consent related tests * Set targeting keys in a more generic way * Test- logic updates
- Loading branch information
1 parent
d48e7fa
commit 55e7cdb
Showing
3 changed files
with
399 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
/** | ||
* This module adds brandmetrics provider to the real time data module | ||
* The {@link module:modules/realTimeData} module is required | ||
* The module will load load the brandmetrics script and set survey- targeting to ad units of specific bidders. | ||
* @module modules/brandmetricsRtdProvider | ||
* @requires module:modules/realTimeData | ||
*/ | ||
import { config } from '../src/config.js' | ||
import { submodule } from '../src/hook.js' | ||
import { deepSetValue, mergeDeep, logError, deepAccess } from '../src/utils.js' | ||
import {loadExternalScript} from '../src/adloader.js' | ||
const MODULE_NAME = 'brandmetrics' | ||
const MODULE_CODE = MODULE_NAME | ||
const RECEIVED_EVENTS = [] | ||
const GVL_ID = 422 | ||
const TCF_PURPOSES = [1, 7] | ||
|
||
function init (config, userConsent) { | ||
const hasConsent = checkConsent(userConsent) | ||
|
||
if (hasConsent) { | ||
const moduleConfig = getMergedConfig(config) | ||
initializeBrandmetrics(moduleConfig.params.scriptId) | ||
} | ||
return hasConsent | ||
} | ||
|
||
/** | ||
* Checks TCF and USP consents | ||
* @param {Object} userConsent | ||
* @returns {boolean} | ||
*/ | ||
function checkConsent (userConsent) { | ||
let consent = false | ||
|
||
if (userConsent && userConsent.gdpr && userConsent.gdpr.gdprApplies) { | ||
const gdpr = userConsent.gdpr | ||
|
||
if (gdpr.vendorData) { | ||
const vendor = gdpr.vendorData.vendor | ||
const purpose = gdpr.vendorData.purpose | ||
|
||
let vendorConsent = false | ||
if (vendor.consents) { | ||
vendorConsent = vendor.consents[GVL_ID] | ||
} | ||
|
||
if (vendor.legitimateInterests) { | ||
vendorConsent = vendorConsent || vendor.legitimateInterests[GVL_ID] | ||
} | ||
|
||
const purposes = TCF_PURPOSES.map(id => { | ||
return (purpose.consents && purpose.consents[id]) || (purpose.legitimateInterests && purpose.legitimateInterests[id]) | ||
}) | ||
const purposesValid = purposes.filter(p => p === true).length === TCF_PURPOSES.length | ||
consent = vendorConsent && purposesValid | ||
} | ||
} else if (userConsent.usp) { | ||
const usp = userConsent.usp | ||
consent = usp[1] !== 'N' && usp[2] !== 'Y' | ||
} | ||
|
||
return consent | ||
} | ||
|
||
/** | ||
* Add event- listeners to hook in to brandmetrics events | ||
* @param {Object} reqBidsConfigObj | ||
* @param {function} callback | ||
*/ | ||
function processBrandmetricsEvents (reqBidsConfigObj, moduleConfig, callback) { | ||
const callBidTargeting = (event) => { | ||
if (event.available && event.conf) { | ||
const targetingConf = event.conf.displayOption || {} | ||
if (targetingConf.type === 'pbjs') { | ||
setBidderTargeting(reqBidsConfigObj, moduleConfig, targetingConf.targetKey || 'brandmetrics_survey', event.survey.measurementId) | ||
} | ||
} | ||
callback() | ||
} | ||
|
||
if (RECEIVED_EVENTS.length > 0) { | ||
callBidTargeting(RECEIVED_EVENTS[RECEIVED_EVENTS.length - 1]) | ||
} else { | ||
window._brandmetrics = window._brandmetrics || [] | ||
window._brandmetrics.push({ | ||
cmd: '_addeventlistener', | ||
val: { | ||
event: 'surveyloaded', | ||
reEmitLast: true, | ||
handler: (ev) => { | ||
RECEIVED_EVENTS.push(ev) | ||
if (RECEIVED_EVENTS.length === 1) { | ||
// Call bid targeting only for the first received event, if called subsequently, last event from the RECEIVED_EVENTS array is used | ||
callBidTargeting(ev) | ||
} | ||
}, | ||
} | ||
}) | ||
} | ||
} | ||
|
||
/** | ||
* Sets bid targeting of specific bidders | ||
* @param {Object} reqBidsConfigObj | ||
* @param {string} key Targeting key | ||
* @param {string} val Targeting value | ||
*/ | ||
function setBidderTargeting (reqBidsConfigObj, moduleConfig, key, val) { | ||
const bidders = deepAccess(moduleConfig, 'params.bidders') | ||
if (bidders && bidders.length > 0) { | ||
const ortb2 = {} | ||
deepSetValue(ortb2, 'ortb2.user.ext.data.' + key, val) | ||
config.setBidderConfig({ | ||
bidders: bidders, | ||
config: ortb2 | ||
}) | ||
} | ||
} | ||
|
||
/** | ||
* Add the brandmetrics script to the page. | ||
* @param {string} scriptId - The script- id provided by brandmetrics or brandmetrics partner | ||
*/ | ||
function initializeBrandmetrics(scriptId) { | ||
if (scriptId) { | ||
const path = 'https://cdn.brandmetrics.com/survey/script/' | ||
const file = scriptId + '.js' | ||
const url = path + file | ||
|
||
loadExternalScript(url, MODULE_CODE) | ||
} | ||
} | ||
|
||
/** | ||
* Merges a provided config with default values | ||
* @param {Object} customConfig | ||
* @returns | ||
*/ | ||
function getMergedConfig(customConfig) { | ||
return mergeDeep({ | ||
waitForIt: false, | ||
params: { | ||
bidders: [], | ||
scriptId: undefined, | ||
} | ||
}, customConfig) | ||
} | ||
|
||
/** @type {RtdSubmodule} */ | ||
export const brandmetricsSubmodule = { | ||
name: MODULE_NAME, | ||
getBidRequestData: function (reqBidsConfigObj, callback, customConfig) { | ||
try { | ||
const moduleConfig = getMergedConfig(customConfig) | ||
if (moduleConfig.waitForIt) { | ||
processBrandmetricsEvents(reqBidsConfigObj, moduleConfig, callback) | ||
} else { | ||
callback() | ||
} | ||
} catch (e) { | ||
logError(e) | ||
} | ||
}, | ||
init: init | ||
} | ||
|
||
submodule('realTimeData', brandmetricsSubmodule) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Brandmetrics Real-time Data Submodule | ||
This module is intended to be used by brandmetrics (https://brandmetrics.com) partners and sets targeting keywords to bids if the browser is eligeble to see a brandmetrics survey. | ||
The module hooks in to brandmetrics events and requires a brandmetrics script to be running. The module can optionally load and initialize brandmetrics by providing the 'scriptId'- parameter. | ||
|
||
## Usage | ||
Compile the Brandmetrics RTD module into your Prebid build: | ||
``` | ||
gulp build --modules=rtdModule,brandmetricsRtdProvider | ||
``` | ||
|
||
> Note that the global RTD module, `rtdModule`, is a prerequisite of the Brandmetrics RTD module. | ||
Enable the Brandmetrics RTD in your Prebid configuration, using the below format: | ||
|
||
```javascript | ||
pbjs.setConfig({ | ||
..., | ||
realTimeData: { | ||
auctionDelay: 500, // auction delay | ||
dataProviders: [{ | ||
name: 'brandmetrics', | ||
waitForIt: true // should be true if there's an `auctionDelay`, | ||
params: { | ||
scriptId: '00000000-0000-0000-0000-000000000000', | ||
bidders: ['ozone'] | ||
} | ||
}] | ||
}, | ||
... | ||
}) | ||
``` | ||
|
||
## Parameters | ||
| Name | Type | Description | Default | | ||
| ----------------- | -------------------- | ------------------ | ------------------ | | ||
| name | String | This should always be `brandmetrics` | - | | ||
| waitForIt | Boolean | Should be `true` if there's an `auctionDelay` defined (recommended) | `false` | | ||
| params | Object | | - | | ||
| params.bidders | String[] | An array of bidders which should receive targeting keys. | `[]` | | ||
| params.scriptId | String | A script- id GUID if the brandmetrics- script should be initialized. | `undefined` | |
Oops, something went wrong.