-
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.
- Loading branch information
Showing
5 changed files
with
462 additions
and
4 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
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
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,171 @@ | ||
/** | ||
* This module adds the Adloox provider to the real time data module | ||
* This module adds the [Adloox]{@link https://www.adloox.com/} provider to the real time data module | ||
* The {@link module:modules/realTimeData} module is required | ||
* The module will inject Adloox's prebid API JS | ||
* The module will fetch segments from Adloox's server | ||
* @module modules/adlooxRtdProvider | ||
* @requires module:modules/realTimeData | ||
* @requires module:modules/adlooxAnalyticsAdapter | ||
*/ | ||
|
||
/* eslint prebid/validate-imports: "warn" */ | ||
|
||
import { command as analyticsCommand, COMMAND } from './adlooxAnalyticsAdapter.js'; | ||
import { config as _config } from '../src/config.js'; | ||
import { submodule } from '../src/hook.js'; | ||
import includes from 'core-js-pure/features/array/includes.js'; | ||
import { getGlobal } from '../src/prebidGlobal.js'; | ||
import * as utils from '../src/utils.js'; | ||
|
||
const MODULE = 'adlooxRtdProvider'; | ||
|
||
let CONFIGURED = false; | ||
|
||
const URL_JS = 'https://p.adlooxtracking.com/gpt/a.js'; | ||
|
||
function init(config, userConsent) { | ||
utils.logInfo(MODULE, 'init', config, userConsent); | ||
|
||
if (!utils.isPlainObject(config)) { | ||
utils.logError(MODULE, 'missing config'); | ||
return false; | ||
} | ||
if (config.params === undefined) config.params = {}; | ||
if (!(utils.isPlainObject(config.params))) { | ||
utils.logError(MODULE, 'invalid params'); | ||
return false; | ||
} | ||
if (!(config.params.js === undefined || utils.isStr(config.params.js))) { | ||
utils.logError(MODULE, 'invalid js params value'); | ||
return false; | ||
} | ||
// legacy/deprecated configuration code path | ||
if (config.params.params === undefined) { | ||
config.params.params = {}; | ||
} else if (!utils.isPlainObject(config.params.params) || !(utils.isInteger(config.params.params.clientid) && utils.isInteger(config.params.params.tagid) && utils.isInteger(config.params.params.platformid))) { | ||
utils.logError(MODULE, 'invalid subsection params block'); | ||
return false; | ||
} | ||
|
||
window.adloox_pubint = window.adloox_pubint || { cmd: [] }; | ||
|
||
const script = document.createElement('script'); | ||
script.src = config.params.js || URL_JS; | ||
utils.insertElement(script); | ||
|
||
function analyticsConfigCallback(data) { | ||
CONFIGURED = true; | ||
|
||
const params = utils.mergeDeep({}, config.params.params, data); | ||
|
||
window.adloox_pubint.cmd.push(function() { | ||
window.adloox_pubint.init(params); | ||
}); | ||
} | ||
if (Object.keys(config.params.params).length) { | ||
utils.logWarn(MODULE, 'legacy/deprecated configuration (please migrate to adlooxAnalyticsAdapter)'); | ||
analyticsConfigCallback({}); | ||
} else { | ||
analyticsCommand(COMMAND.CONFIG, null, analyticsConfigCallback); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
function getBidRequestData(reqBidsConfigObj, callback, config, userConsent) { | ||
if (!CONFIGURED) { | ||
utils.logError(MODULE, 'getBidRequestData', 'called before configured, is analytics enabled?'); | ||
return; | ||
} | ||
|
||
utils.logInfo(MODULE, 'getBidRequestData', reqBidsConfigObj, callback, config, userConsent); | ||
|
||
const context = { | ||
set: function(n, x) { | ||
utils.logInfo(MODULE, 'segment', 'context', n, x); | ||
const data = _config.getConfig('fpd.context.data') || {}; | ||
delete data[n]; | ||
if (x !== undefined) data[n] = x; | ||
_config.setConfig({ fpd: { context: { data: data } } }); | ||
} | ||
}; | ||
const user = { | ||
set: function(n, x) { | ||
utils.logInfo(MODULE, 'segment', 'user', n, x); | ||
const data = _config.getConfig('fpd.user.data') || {}; | ||
delete data[n]; | ||
if (x !== undefined) data[n] = x; | ||
_config.setConfig({ fpd: { user: { data: data } } }); | ||
} | ||
}; | ||
const slots = (reqBidsConfigObj.adUnits || getGlobal().adUnits).map(adUnit => { | ||
return { | ||
id: adUnit.code, | ||
// modules/gptPreAuction.js does not update the AdUnits themselves... (╯°□°)╯ ┻━┻ | ||
name: utils.deepAccess(adUnit, 'fpd.context.pbAdSlot') || utils.getGptSlotInfoForAdUnitCode(adUnit.code).gptSlot || adUnit.code, | ||
set: function(n, x) { | ||
utils.logInfo(MODULE, 'segment', 'slot', adUnit.code, n, x); | ||
const data = utils.deepAccess(adUnit, 'fpd.context.data', {}); | ||
delete data[n]; | ||
if (x !== undefined) data[n] = x; | ||
utils.deepSetValue(adUnit, 'fpd.context.data', data); | ||
} | ||
}; | ||
}); | ||
|
||
window.adloox_pubint.cmd.push(function() { | ||
window.adloox_pubint.seg(context, user, slots, callback); | ||
}); | ||
} | ||
|
||
function getTargetingData(adUnitArray, config, userConsent) { | ||
utils.logInfo(MODULE, 'getTargetingData', adUnitArray, config, userConsent); | ||
|
||
function add(pairs, dest) { | ||
// targeting:getTargetingValues expects strings or arrays | ||
Object.keys(pairs).filter(key => /^adl_/.test(key)).forEach(k => { | ||
let v = pairs[k]; | ||
switch (true) { | ||
case utils.isBoolean(v): | ||
if (!v) break; | ||
v = 1; | ||
// falls through | ||
case utils.isNumber(v): | ||
if (!v) break; | ||
v = v.toString(); | ||
// falls through | ||
case utils.isStr(v): | ||
if (!v.length) break; | ||
v = [ v ]; | ||
// falls through | ||
case utils.isArray(v): | ||
let i = v.length; | ||
if (!i) break; | ||
while (i-- > 0) v[i] = v[i].toString(); | ||
dest[k] = v; | ||
// falls through | ||
} | ||
}); | ||
} | ||
|
||
const data0 = {}; | ||
add(_config.getConfig('fpd.context.data') || {}, data0); | ||
add(_config.getConfig('fpd.user.data') || {}, data0); | ||
|
||
return getGlobal().adUnits.filter(adUnit => includes(adUnitArray, adUnit.code)).reduce((data, adUnit) => { | ||
data[adUnit.code] = utils.deepClone(data0); | ||
const fpdContextData = utils.deepAccess(adUnit, 'fpd.context.data', {}); | ||
add(fpdContextData, data[adUnit.code]); | ||
return data; | ||
}, {}); | ||
} | ||
|
||
export const subModuleObj = { | ||
name: 'adloox', | ||
init: init, | ||
getBidRequestData: getBidRequestData, | ||
getTargetingData: getTargetingData | ||
}; | ||
|
||
submodule('realTimeData', subModuleObj); |
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,85 @@ | ||
# Overview | ||
|
||
Module Name: Adloox RTD Provider | ||
Module Type: RTD Provider | ||
Maintainer: [email protected] | ||
|
||
# Description | ||
|
||
RTD provider for adloox.com. Contact [email protected] for information. | ||
|
||
In addition to populating the ad server key-value targeting, fetched segments (prefixed with `adl_...`) will also populate [First Party Data](https://docs.prebid.org/features/firstPartyData.html), some examples of the segments as described by the Adloox 'Google Publisher Tag Targeting Guidelines' and where they are placed are: | ||
|
||
* Page/Device segments are placed into `fpd.context.data`, for example: | ||
* **`adl_ivt`:** `fpd.context.data.adl_ivt` is a boolean | ||
* **`adl_ua_old`:** `fpd.context.data.ua_old` is a boolean | ||
* **`adl_ip`:** `fpd.context.data.adl_ip` is an array of strings | ||
* AdUnit segments are placed into `AdUnit.fpd.context.data`, for example: | ||
* **`adl_{dis,vid,aud}`:** `AdUnit.fpd.context.data.adl_{dis,vid,aud}` is an array of integers | ||
* **`adl_atf`:** `AdUnit.fpd.context.data.adl_atf` is a boolean (or `-1` on no measure) | ||
|
||
**N.B.** this provider does not offer or utilise any user orientated data | ||
|
||
This module adds an HTML `<script>` tag to the page to fetch our JavaScript from `https://p.adlooxtracking.com/gpt/a.js` (~3kiB gzipped) to support this integration. | ||
|
||
## Example | ||
|
||
To view an example of an Adloox integration look at the example provided in the [Adloox Analytics Adapter documentation](./adlooxAnalyticsAdapter.md#example). | ||
|
||
# Integration | ||
|
||
To use this, you *must* also integrate the [Adloox Analytics Adapter](./adlooxAnalyticsAdapter.md) as shown below: | ||
|
||
pbjs.setConfig({ | ||
... | ||
|
||
realTimeData: { | ||
auctionDelay: 100, // see below for guidance | ||
dataProviders: [ | ||
{ | ||
name: 'adloox', | ||
params: { | ||
params: { // optional | ||
thresholds: [ 50, 80 ] | ||
} | ||
} | ||
} | ||
] | ||
}, | ||
|
||
... | ||
}); | ||
pbjs.enableAnalytics({ | ||
provider: 'adloox', | ||
options: { | ||
client: 'adlooxtest', | ||
clientid: 127, | ||
platformid: 0, | ||
tagid: 0 | ||
} | ||
}); | ||
|
||
You may optionally pass a subsection `params` in the `params` block to the Adloox RTD Provider, these will be passed through to the segment handler as is and as described by the integration guidelines. | ||
|
||
**N.B.** If you pass `params` to the Adloox Analytics Adapter, `id1` (`AdUnit.code`) and `id2` (`%%pbAdSlot%%`) *must* describe a stable identifier otherwise no usable segments will be served and so they *must not* be changed; if `id1` for your inventory could contain a non-stable random number please consult with us before continuing | ||
|
||
Though our segment technology is fast (less than 10ms) the time it takes for the users device to connect to our service and fetch the segments may not be. For this reason we recommend setting `auctionDelay` no lower than 100ms and if possible you should explore using user-agent sourced information such as [NetworkInformation.{rtt,downlink,...}](https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation) to dynamically tune this for each user. | ||
|
||
## Prebid Ad Slot | ||
|
||
To create reliable segments, a stable description for slots on your inventory needs to be supplied which is typically solved by using the [Prebid Ad Slot](https://docs.prebid.org/features/pbAdSlot.html). | ||
|
||
You may use one of two ways to do achieve this: | ||
|
||
* for display inventory [using GPT](https://developers.google.com/publisher-tag/guides/get-started) you may configure Prebid.js to automatically use the [full ad unit path](https://developers.google.com/publisher-tag/reference#googletag.Slot_getAdUnitPath) | ||
1. include the [`gptPreAuction` module](https://docs.prebid.org/dev-docs/modules/gpt-pre-auction.html) | ||
1. wrap both `pbjs.setConfig({...})` and `pbjs.enableAnalytics({...})` with `googletag.cmd.push(function() { ... })` | ||
* set `pbAdSlot` in the [first party data](https://docs.prebid.org/dev-docs/adunit-reference.html#first-party-data) variable `AdUnit.fpd.context.pbAdSlot` for all your ad units | ||
|
||
## Timeouts | ||
|
||
It is strongly recommended you increase any [failsafe timeout](https://docs.prebid.org/dev-docs/faq.html#when-starting-out-what-should-my-timeouts-be) you use by at least the value you supply to `auctionDelay` above. | ||
|
||
Adloox recommends you use the following (based on [examples provided on the Prebid.js website](https://docs.prebid.org/dev-docs/examples/basic-example.html)) | ||
|
||
FAILSAFE_TIMEOUT = AUCTION_DELAY + (3 * PREBID_TIMEOUT) |
Oops, something went wrong.