diff --git a/integrationExamples/gpt/weboramaRtdProvider_example.html b/integrationExamples/gpt/weboramaRtdProvider_example.html
index b81ec52b2c4..73843c49914 100644
--- a/integrationExamples/gpt/weboramaRtdProvider_example.html
+++ b/integrationExamples/gpt/weboramaRtdProvider_example.html
@@ -1,9 +1,10 @@
-
+
+ weborama rtd submodule example
@@ -26,9 +27,8 @@
params: {
setPrebidTargeting: true, // optional
sendToBidders: true, // optional
- onData: function (data, site) { // optional
- var kind = (site) ? 'site' : 'user';
- console.log('onData', kind, data);
+ onData: function (data, meta) { // optional
+ console.log('onData', data, meta);
},
weboCtxConf: {
token: "to-be-defined", // mandatory
@@ -36,21 +36,30 @@
setPrebidTargeting: true, // override param.setPrebidTargeting or default true
sendToBidders: true, // override param.sendToBidders or default true
defaultProfile: { // optional
- webo_ctx: ['moon'],
+ webo_ctx: ["Rugby_Renault_c11495", "Sport_c11893"],
webo_ds: ['bar']
},
- //, onData: function (data, ...) { ...}
+ // enabled: false,
+ //, onData: function (data,...) { ...}
},
weboUserDataConf: {
- accountId: 12345, // optional
+ accountId: 12345, // recommended
setPrebidTargeting: true, // override param.setPrebidTargeting or default true
- sendToBidders: true, // override param.sendToBidders or default true
+ sendToBidders: ['smartadserver'], // specify the bidder to share data
defaultProfile: { // optional
- webo_cs: ['Red'],
+ webo_cs: ['red'],
webo_audiences: ['bam']
},
localStorageProfileKey: 'webo_wam2gam_entry', // default
+ // enabled: false,
//, onData: function (data,...) { ...}
+ },
+ sfbxLiteDataConf: {
+ enabled: true,
+ defaultProfile: { // optional
+ lite_occupation: ['gérant', 'bénévole'],
+ lite_hobbies: ['sport', 'cinéma'],
+ },
}
}
}]
@@ -62,6 +71,9 @@
var div_1_sizes = [
[300, 300]
];
+ var div_2_sizes = [
+ [600, 100]
+ ];
var PREBID_TIMEOUT = 3000;
var FAILSAFE_TIMEOUT = 5000;
@@ -106,6 +118,46 @@
networkId: 456456,
},
}]
+ },
+ {
+ code: '/1056029/webo-wam-prebid',
+ mediaTypes: {
+ banner: {
+ sizes: div_2_sizes
+ }
+ },
+ bids: [{
+ bidder: 'smartadserver',
+ params: {
+ siteId: 1234,
+ pageId: 1234,
+ formatId: 1234,
+ }
+ }, {
+ bidder: 'pubmatic',
+ params: {
+ publisherId: '32572',
+ }
+ }, {
+ bidder: 'appnexus',
+ params: {
+ placementId: 234234,
+ }
+ }, {
+ bidder: 'rubicon',
+ params: {
+ accountId: '14062',
+ siteId: '70608',
+ zoneId: '335918',
+ userId: '12346',
+ }
+ }, {
+ bidder: 'criteo',
+ params: {
+ zoneId: 234234,
+ networkId: 456456,
+ },
+ }]
}
];
@@ -138,7 +190,6 @@
});
}
-
// in case PBJS doesn't load
setTimeout(function () {
initAdserver();
@@ -146,6 +197,7 @@
googletag.cmd.push(function () {
googletag.defineSlot('/1056029/webo-ctx-prebid', div_1_sizes, 'div-gpt-ad-1620653642627-0').addService(googletag.pubads());
+ googletag.defineSlot('/1056029/webo-wam-prebid', div_2_sizes, 'div-gpt-ad-1645023761875-0').addService(googletag.pubads());
googletag.pubads().disableInitialLoad();
googletag.enableServices();
});
@@ -154,11 +206,12 @@
- test webo ctx using prebid.js
+ test webo rtd submodule with prebid.js
Basic Prebid.js Example
Div-1
+
+
diff --git a/modules/weboramaRtdProvider.js b/modules/weboramaRtdProvider.js
index 75e52f753ad..64cdd6508bb 100644
--- a/modules/weboramaRtdProvider.js
+++ b/modules/weboramaRtdProvider.js
@@ -7,57 +7,96 @@
* @requires module:modules/realTimeData
*/
+/**
+ * @typedef dataCallbackMetadata
+ * @property {Boolean} user if true it is user-centric data
+ * @property {String} source describe the source of data, if "contextual" or "wam"
+ * @property {Boolean} isDefault if true it the default profile defined in the configuration
+ */
+
/** onData callback type
* @callback dataCallback
* @param {Object} data profile data
- * @param {Boolean} site true if site, else it is user
+ * @param {dataCallbackMetadata} meta metadata
* @returns {void}
*/
+/** setPrebidTargeting callback type
+ * @callback setPrebidTargetingCallback
+ * @param {String} adUnitCode
+ * @param {Object} data
+ * @param {dataCallbackMetadata} metadata
+ * @returns {Boolean}
+ */
+
+/** sendToBidders callback type
+ * @callback sendToBiddersCallback
+ * @param {Object} bid
+ * @param {String} adUnitCode
+ * @param {Object} data
+ * @param {dataCallbackMetadata} metadata
+ * @returns {Boolean}
+ */
+
/**
* @typedef {Object} ModuleParams
- * @property {?Boolean} setPrebidTargeting if true, will set the GAM targeting (default undefined)
- * @property {?Boolean} sendToBidders if true, will send the contextual profile to all bidders (default undefined)
+ * @property {?setPrebidTargetingCallback|?Boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined)
+ * @property {?sendToBiddersCallback|?Boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined)
* @property {?dataCallback} onData callback
- * @property {?WeboCtxConf} weboCtxConf
- * @property {?WeboUserDataConf} weboUserDataConf
+ * @property {?WeboCtxConf} weboCtxConf site-centric contextual configuration
+ * @property {?WeboUserDataConf} weboUserDataConf user-centric wam configuration
+ * @property {?SfbxLiteDataConf} sfbxLiteDataConf site-centric lite configuration
*/
/**
* @typedef {Object} WeboCtxConf
* @property {string} token required token to be used on bigsea contextual API requests
* @property {?string} targetURL specify the target url instead use the referer
- * @property {?Boolean} setPrebidTargeting if true, will set the GAM targeting (default params.setPrebidTargeting or true)
- * @property {?Boolean} sendToBidders if true, will send the contextual profile to all bidders (default params.sendToBidders or true)
+ * @property {?setPrebidTargetingCallback|?Boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined)
+ * @property {?sendToBiddersCallback|?Boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined)
* @property {?dataCallback} onData callback
* @property {?object} defaultProfile to be used if the profile is not found
* @property {?Boolean} enabled if false, will ignore this configuration
+ * @property {?string} baseURLProfileAPI to be used to point to a different domain than ctx.weborama.com
*/
/**
* @typedef {Object} WeboUserDataConf
* @property {?number} accountId wam account id
- * @property {?Boolean} setPrebidTargeting if true, will set the GAM targeting (default params.setPrebidTargeting or true)
- * @property {?Boolean} sendToBidders if true, will send the user-centric profile to all bidders (default params.sendToBidders or true)
+ * @property {?setPrebidTargetingCallback|?Boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined)
+ * @property {?sendToBiddersCallback|?Boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined)
* @property {?object} defaultProfile to be used if the profile is not found
* @property {?dataCallback} onData callback
* @property {?string} localStorageProfileKey can be used to customize the local storage key (default is 'webo_wam2gam_entry')
* @property {?Boolean} enabled if false, will ignore this configuration
*/
+/**
+ * @typedef {Object} SfbxLiteDataConf
+ * @property {?setPrebidTargetingCallback|?Boolean|?Object} setPrebidTargeting if true, will set the GAM targeting (default undefined)
+ * @property {?sendToBiddersCallback|?Boolean|?Object} sendToBidders if true, will send the contextual profile to all bidders, else expects a list of allowed bidders (default undefined)
+ * @property {?object} defaultProfile to be used if the profile is not found
+ * @property {?dataCallback} onData callback
+ * @property {?string} localStorageProfileKey can be used to customize the local storage key (default is '_lite')
+ * @property {?Boolean} enabled if false, will ignore this configuration
+ */
import {
getGlobal
} from '../src/prebidGlobal.js';
import {
deepSetValue,
- deepAccess,
isEmpty,
mergeDeep,
logError,
logWarn,
tryAppendQueryString,
logMessage,
- isFn
+ isFn,
+ isArray,
+ isStr,
+ isBoolean,
+ isPlainObject,
+ deepClone,
} from '../src/utils.js';
import {
submodule
@@ -75,13 +114,29 @@ const MODULE_NAME = 'realTimeData';
/** @type {string} */
const SUBMODULE_NAME = 'weborama';
/** @type {string} */
+const BASE_URL_CONTEXTUAL_PROFILE_API = 'ctx.weborama.com';
+/** @type {string} */
export const DEFAULT_LOCAL_STORAGE_USER_PROFILE_KEY = 'webo_wam2gam_entry';
/** @type {string} */
const LOCAL_STORAGE_USER_TARGETING_SECTION = 'targeting';
+/** @type {string} */
+export const DEFAULT_LOCAL_STORAGE_LITE_PROFILE_KEY = '_lite';
+/** @type {string} */
+const LOCAL_STORAGE_LITE_TARGETING_SECTION = 'webo';
+/** @type {string} */
+const WEBO_CTX_CONF_SECTION = 'weboCtxConf';
+/** @type {string} */
+const WEBO_USER_DATA_CONF_SECTION = 'weboUserDataConf';
+/** @type {string} */
+const SFBX_LITE_DATA_CONF_SECTION = 'sfbxLiteDataConf';
+
/** @type {number} */
const GVLID = 284;
-/** @type {object} */
-export const storage = getStorageManager({gvlid: GVLID, moduleName: SUBMODULE_NAME});
+/** @type {?Object} */
+export const storage = getStorageManager({
+ gvlid: GVLID,
+ moduleName: SUBMODULE_NAME
+});
/** @type {null|Object} */
let _weboContextualProfile = null;
@@ -89,78 +144,67 @@ let _weboContextualProfile = null;
/** @type {Boolean} */
let _weboCtxInitialized = false;
-/** @type {null|Object} */
+/** @type {?Object} */
let _weboUserDataUserProfile = null;
/** @type {Boolean} */
let _weboUserDataInitialized = false;
+/** @type {?Object} */
+let _sfbxLiteDataProfile = null;
+
+/** @type {Boolean} */
+let _sfbxLiteDataInitialized = false;
+
/** Initialize module
* @param {object} moduleConfig
* @return {Boolean} true if module was initialized with success
*/
function init(moduleConfig) {
- moduleConfig = moduleConfig || {};
- const moduleParams = moduleConfig.params || {};
- const weboCtxConf = moduleParams.weboCtxConf;
- const weboUserDataConf = moduleParams.weboUserDataConf;
+ const moduleParams = moduleConfig?.params || {};
- _weboCtxInitialized = initWeboCtx(moduleParams, weboCtxConf);
- _weboUserDataInitialized = initWeboUserData(moduleParams, weboUserDataConf);
-
- return _weboCtxInitialized || _weboUserDataInitialized;
-}
-
-/** Initialize contextual sub module
- * @param {ModuleParams} moduleParams
- * @param {WeboCtxConf} weboCtxConf
- * @return {Boolean} true if sub module was initialized with success
- */
-function initWeboCtx(moduleParams, weboCtxConf) {
- if (!weboCtxConf || weboCtxConf.enabled === false) {
- moduleParams.weboCtxConf = null;
-
- return false
- }
-
- normalizeConf(moduleParams, weboCtxConf);
-
- _weboCtxInitialized = false;
_weboContextualProfile = null;
+ _weboUserDataUserProfile = null;
+ _sfbxLiteDataProfile = null;
- if (!weboCtxConf.token) {
- logWarn('missing param "token" for weborama contextual sub module initialization');
- return false;
- }
-
- logMessage('weborama contextual intialized with success');
+ _weboCtxInitialized = initSubSection(moduleParams, WEBO_CTX_CONF_SECTION, 'token');
+ _weboUserDataInitialized = initSubSection(moduleParams, WEBO_USER_DATA_CONF_SECTION);
+ _sfbxLiteDataInitialized = initSubSection(moduleParams, SFBX_LITE_DATA_CONF_SECTION);
- return true;
+ return _weboCtxInitialized || _weboUserDataInitialized || _sfbxLiteDataInitialized;
}
-/** Initialize weboUserData sub module
- * @param {ModuleParams} moduleParams
- * @param {WeboUserDataConf} weboUserDataConf
- * @return {Boolean} true if sub module was initialized with success
+/** Initialize subsection module
+ * @param {Object} moduleParams
+ * @param {string} subSection subsection name to initialize
+ * @param {[]string} requiredFields
+ * @return {Boolean} true if module subsection was initialized with success
*/
-function initWeboUserData(moduleParams, weboUserDataConf) {
- if (!weboUserDataConf || weboUserDataConf.enabled === false) {
- moduleParams.weboUserDataConf = null;
+function initSubSection(moduleParams, subSection, ...requiredFields) {
+ const weboSectionConf = moduleParams[subSection] || {enabled: false};
+
+ if (weboSectionConf.enabled === false) {
+ delete moduleParams[subSection];
return false;
}
- normalizeConf(moduleParams, weboUserDataConf);
+ requiredFields ||= [];
- _weboUserDataInitialized = false;
- _weboUserDataUserProfile = null;
+ try {
+ normalizeConf(moduleParams, weboSectionConf);
- let message = 'weborama user-centric intialized with success';
- if (weboUserDataConf.hasOwnProperty('accountId')) {
- message = `weborama user-centric intialized with success for account: ${weboUserDataConf.accountId}`;
+ requiredFields.forEach(field => {
+ if (!weboSectionConf[field]) {
+ throw `missing required field "{field}" on {section}`;
+ }
+ });
+ } catch (e) {
+ logError(`unable to initialize: error on ${subSection} configuration: ${e}`);
+ return false
}
- logMessage(message);
+ logMessage(`weborama ${subSection} initialized with success`);
return true;
}
@@ -169,21 +213,172 @@ function initWeboUserData(moduleParams, weboUserDataConf) {
const globalDefaults = {
setPrebidTargeting: true,
sendToBidders: true,
- onData: (data, kind, def) => logMessage('onData(data,kind,default)', data, kind, def),
+ onData: () => {
+ /* do nothing */ },
}
/** normalize submodule configuration
* @param {ModuleParams} moduleParams
- * @param {WeboCtxConf|WeboUserDataConf} submoduleParams
+ * @param {WeboCtxConf|WeboUserDataConf|SfbxLiteDataConf} submoduleParams
* @return {void}
*/
function normalizeConf(moduleParams, submoduleParams) {
+ // handle defaults
Object.entries(globalDefaults).forEach(([propertyName, globalDefaultValue]) => {
if (!submoduleParams.hasOwnProperty(propertyName)) {
const hasModuleParam = moduleParams.hasOwnProperty(propertyName);
submoduleParams[propertyName] = (hasModuleParam) ? moduleParams[propertyName] : globalDefaultValue;
}
})
+
+ // handle setPrebidTargeting
+ coerceSetPrebidTargeting(submoduleParams)
+
+ // handle sendToBidders
+ coerceSendToBidders(submoduleParams)
+
+ if (!isFn(submoduleParams.onData)) {
+ throw 'onData parameter should be a callback';
+ }
+
+ submoduleParams.defaultProfile = submoduleParams.defaultProfile || {};
+
+ if (!isValidProfile(submoduleParams.defaultProfile)) {
+ throw 'defaultProfile is not valid';
+ }
+}
+
+/** coerce set prebid targeting to function
+ * @param {WeboCtxConf|WeboUserDataConf|SfbxLiteDataConf} submoduleParams
+ * @return {void}
+ */
+function coerceSetPrebidTargeting(submoduleParams) {
+ const setPrebidTargeting = submoduleParams.setPrebidTargeting;
+
+ if (isFn(setPrebidTargeting)) {
+ return
+ }
+
+ if (isBoolean(setPrebidTargeting)) {
+ const shouldSetPrebidTargeting = setPrebidTargeting;
+
+ submoduleParams.setPrebidTargeting = () => shouldSetPrebidTargeting;
+
+ return
+ }
+
+ if (isStr(setPrebidTargeting)) {
+ const allowedAdUnitCode = setPrebidTargeting;
+
+ submoduleParams.setPrebidTargeting = (adUnitCode) => allowedAdUnitCode == adUnitCode;
+
+ return
+ }
+
+ if (isArray(setPrebidTargeting)) {
+ const allowedAdUnitCodes = setPrebidTargeting;
+
+ submoduleParams.setPrebidTargeting = (adUnitCode) => allowedAdUnitCodes.includes(adUnitCode);
+
+ return
+ }
+
+ throw `unexpected format for setPrebidTargeting: ${typeof setPrebidTargeting}`;
+}
+
+/** coerce send to bidders to function
+ * @param {WeboCtxConf|WeboUserDataConf|SfbxLiteDataConf} submoduleParams
+ * @return {void}
+ */
+function coerceSendToBidders(submoduleParams) {
+ const sendToBidders = submoduleParams.sendToBidders;
+
+ if (isFn(sendToBidders)) {
+ return
+ }
+
+ if (isBoolean(sendToBidders)) {
+ const shouldSendToBidders = sendToBidders;
+
+ submoduleParams.sendToBidders = () => shouldSendToBidders;
+
+ return
+ }
+
+ if (isStr(sendToBidders)) {
+ const allowedBidder = sendToBidders;
+
+ submoduleParams.sendToBidders = (bid) => allowedBidder == bid.bidder;
+
+ return
+ }
+
+ if (isArray(sendToBidders)) {
+ const allowedBidders = sendToBidders;
+
+ submoduleParams.sendToBidders = (bid) => allowedBidders.includes(bid.bidder);
+
+ return
+ }
+
+ if (isPlainObject(sendToBidders)) {
+ const sendToBiddersMap = sendToBidders;
+ submoduleParams.sendToBidders = (bid, adUnitCode) => {
+ const bidder = bid.bidder;
+ if (!sendToBiddersMap.hasOwnProperty(bidder)) {
+ return false
+ }
+
+ const value = sendToBiddersMap[bidder];
+
+ if (isBoolean(value)) {
+ return value
+ }
+
+ if (isStr(value)) {
+ return value == adUnitCode
+ }
+
+ if (isArray(value)) {
+ return value.includes(adUnitCode)
+ }
+
+ throw `unexpected format for sendToBidders[${bidder}]: ${typeof value}`;
+ };
+
+ return
+ }
+
+ throw `unexpected format for sendToBidders: ${typeof sendToBidders}`;
+}
+/**
+ * check if profile is valid
+ * @param {*} profile
+ * @returns {Boolean}
+ */
+function isValidProfile(profile) {
+ if (!isPlainObject(profile)) {
+ return false;
+ }
+
+ const keys = Object.keys(profile);
+
+ for (var i in keys) {
+ const key = keys[i];
+ const value = profile[key];
+ if (!isArray(value)) {
+ return false;
+ }
+
+ for (var j in value) {
+ const elem = value[j]
+ if (!isStr(elem)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
}
/** function that provides ad server targeting data to RTD-core
@@ -192,24 +387,27 @@ function normalizeConf(moduleParams, submoduleParams) {
* @returns {Object} target data
*/
function getTargetingData(adUnitsCodes, moduleConfig) {
- moduleConfig = moduleConfig || {};
- const moduleParams = moduleConfig.params || {};
- const weboCtxConf = moduleParams.weboCtxConf || {};
- const weboUserDataConf = moduleParams.weboUserDataConf || {};
- const weboCtxConfTargeting = weboCtxConf.setPrebidTargeting;
- const weboUserDataConfTargeting = weboUserDataConf.setPrebidTargeting;
+ const moduleParams = moduleConfig?.params || {};
- try {
- const profile = getCompleteProfile(moduleParams, weboCtxConfTargeting, weboUserDataConfTargeting);
+ const profileHandlers = buildProfileHandlers(moduleParams);
- if (isEmpty(profile)) {
- return {};
- }
+ if (isEmpty(profileHandlers)) {
+ logMessage('no data to set targeting');
+ return {};
+ }
+ try {
const td = adUnitsCodes.reduce((data, adUnitCode) => {
- if (adUnitCode) {
- data[adUnitCode] = profile;
- }
+ data[adUnitCode] = profileHandlers.reduce((targeting, ph) => {
+ // logMessage(`check if should set targeting for adunit '${adUnitCode}'`);
+ const cph = copyProfileHandler(ph);
+ if (ph.setTargeting(adUnitCode, cph.data, cph.metadata)) {
+ // logMessage(`set targeting for adunit '${adUnitCode}', source '${ph.metadata.source}'`);
+
+ mergeDeep(targeting, cph.data);
+ }
+ return targeting;
+ }, {});
return data;
}, {});
@@ -220,57 +418,155 @@ function getTargetingData(adUnitsCodes, moduleConfig) {
}
}
-/** function that provides complete profile formatted to be used
+/** function that provides data handlers based on the configuration
* @param {ModuleParams} moduleParams
- * @param {Boolean} weboCtxConfTargeting
- * @param {Boolean} weboUserDataConfTargeting
- * @returns {Object} complete profile
+ * @returns {Array