diff --git a/integrationExamples/gpt/ixMultiFormat.html b/integrationExamples/gpt/ixMultiFormat.html
new file mode 100644
index 00000000000..c4ed5bb9b1e
--- /dev/null
+++ b/integrationExamples/gpt/ixMultiFormat.html
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Prebid.js Test
+ Div-1
+
+
+
+
+
+
+
diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js
index 4837c9c061f..d326cbaf9b1 100644
--- a/modules/ixBidAdapter.js
+++ b/modules/ixBidAdapter.js
@@ -50,18 +50,36 @@ const PROVIDERS = [
'flocId'
]
+const REQUIRED_VIDEO_PARAMS = ['mimes', 'minduration', 'maxduration']; // note: protocol/protocols is also reqd
+
+const VIDEO_PARAMS_ALLOW_LIST = [
+ 'mimes', 'minduration', 'maxduration', 'protocols', 'protocol',
+ 'startdelay', 'placement', 'linearity', 'skip', 'skipmin',
+ 'skipafter', 'sequence', 'battr', 'maxextended', 'minbitrate',
+ 'maxbitrate', 'boxingallowed', 'playbackmethod', 'playbackend',
+ 'delivery', 'pos', 'companionad', 'api', 'companiontype', 'ext',
+ 'playerSize', 'w', 'h'
+];
+
/**
* Transform valid bid request config object to banner impression object that will be sent to ad server.
*
- * @param {object} bid A valid bid request config object.
+ * @param {object} bid A valid bid request config object
* @return {object} A impression object that will be sent to ad server.
*/
function bidToBannerImp(bid) {
const imp = bidToImp(bid);
-
imp.banner = {};
- imp.banner.w = bid.params.size[0];
- imp.banner.h = bid.params.size[1];
+ const impSize = utils.deepAccess(bid, 'params.size');
+ if (impSize) {
+ imp.banner.w = impSize[0];
+ imp.banner.h = impSize[1];
+ // populate sid with size if not id
+ if (!(utils.deepAccess(imp, 'ext.sid'))) {
+ imp.ext.sid = `${impSize[0]}x${impSize[1]}`;
+ }
+ }
+
imp.banner.topframe = utils.inIframe() ? 0 : 1;
_applyFloor(bid, imp, BANNER);
@@ -78,18 +96,27 @@ function bidToBannerImp(bid) {
function bidToVideoImp(bid) {
const imp = bidToImp(bid);
const videoAdUnitRef = utils.deepAccess(bid, 'mediaTypes.video');
- const context = utils.deepAccess(bid, 'mediaTypes.video.context');
- const videoAdUnitAllowlist = [
- 'mimes', 'minduration', 'maxduration', 'protocols', 'protocol',
- 'startdelay', 'placement', 'linearity', 'skip', 'skipmin',
- 'skipafter', 'sequence', 'battr', 'maxextended', 'minbitrate',
- 'maxbitrate', 'boxingallowed', 'playbackmethod', 'playbackend',
- 'delivery', 'pos', 'companionad', 'api', 'companiontype', 'ext'
- ];
-
- imp.video = utils.deepClone(bid.params.video)
- imp.video.w = bid.params.size[0];
- imp.video.h = bid.params.size[1];
+ const videoParamRef = utils.deepAccess(bid, 'params.video');
+
+ if (!checkVideoParams(bid, videoAdUnitRef, videoParamRef)) {
+ return {};
+ }
+
+ imp.video = videoParamRef ? utils.deepClone(bid.params.video) : {};
+
+ for (const adUnitProperty in videoAdUnitRef) {
+ if (VIDEO_PARAMS_ALLOW_LIST.indexOf(adUnitProperty) !== -1 && !imp.video.hasOwnProperty(adUnitProperty)) {
+ imp.video[adUnitProperty] = videoAdUnitRef[adUnitProperty];
+ }
+ }
+
+ if (imp.video.minduration > imp.video.maxduration) {
+ utils.logError('IX Bid Adapter: video minduration [' + imp.video.minduration +
+ '] cannot be greater than video maxduration [' + imp.video.maxduration + ']');
+ return {};
+ }
+
+ const context = (videoParamRef && videoParamRef.context) || (videoAdUnitRef && videoAdUnitRef.context);
if (context) {
if (context === 'instream') {
@@ -97,13 +124,22 @@ function bidToVideoImp(bid) {
} else if (context === 'outstream') {
imp.video.placement = 4;
} else {
- utils.logWarn(`ix bidder params: video context '${context}' is not supported`);
+ utils.logWarn(`IX Bid Adapter: video context '${context}' is not supported`);
}
}
- for (const adUnitProperty in videoAdUnitRef) {
- if (videoAdUnitAllowlist.indexOf(adUnitProperty) !== -1 && !imp.video.hasOwnProperty(adUnitProperty)) {
- imp.video[adUnitProperty] = videoAdUnitRef[adUnitProperty];
+ if (!(imp.video.w && imp.video.h)) {
+ // Getting impression Size
+ const impSize = getFirstSize(utils.deepAccess(imp, 'video.playerSize')) || getFirstSize(utils.deepAccess(bid, 'params.size'));
+ if (impSize) {
+ imp.video.w = impSize[0];
+ imp.video.h = impSize[1];
+ if (!(utils.deepAccess(imp, 'ext.sid'))) {
+ imp.ext.sid = `${impSize[0]}x${impSize[1]}`;
+ }
+ } else {
+ utils.logWarn('IX Bid Adapter: Video size is missing in [mediaTypes.video] missing');
+ return {};
}
}
@@ -128,8 +164,6 @@ function bidToImp(bid) {
if (bid.params.hasOwnProperty('id') &&
(typeof bid.params.id === 'string' || typeof bid.params.id === 'number')) {
imp.ext.sid = String(bid.params.id);
- } else {
- imp.ext.sid = `${bid.params.size[0]}x${bid.params.size[1]}`;
}
const dfpAdUnitCode = utils.deepAccess(bid, 'ortb2Imp.ext.data.adserver.adslot');
@@ -278,16 +312,68 @@ function isValidSize(size) {
* @return {boolean} True if the size object is an element of the size array, and false
* otherwise.
*/
-function includesSize(sizeArray, size) {
+function includesSize(sizeArray = [], size) {
if (isValidSize(sizeArray)) {
return sizeArray[0] === size[0] && sizeArray[1] === size[1];
}
-
for (let i = 0; i < sizeArray.length; i++) {
if (sizeArray[i][0] === size[0] && sizeArray[i][1] === size[1]) {
return true;
}
}
+ return false;
+}
+
+/**
+ * Checks if all required video params are present
+ * @param {object} bid Bid Object
+ * @param {object} mediaTypeVideoRef Ad unit level mediaTypes object
+ * @param {object} paramsVideoRef IX bidder params level video object
+ * @returns bool Are the required video params available
+ */
+function checkVideoParams(bid, mediaTypeVideoRef, paramsVideoRef) {
+ let reqParamsPresent = true;
+
+ if (!mediaTypeVideoRef) {
+ utils.logWarn('IX Bid Adapter: mediaTypes.video is the preferred location for video params in ad unit');
+ }
+
+ for (let property of REQUIRED_VIDEO_PARAMS) {
+ const propInMediaType = mediaTypeVideoRef && mediaTypeVideoRef.hasOwnProperty(property);
+ const propInVideoRef = paramsVideoRef && paramsVideoRef.hasOwnProperty(property);
+
+ if (!propInMediaType && !propInVideoRef) {
+ utils.logError('IX Bid Adapter: ' + property + ' is not included in either the adunit or params level');
+ reqParamsPresent = false;
+ }
+ }
+
+ // early return
+ if (!reqParamsPresent) {
+ return false;
+ }
+
+ // check protocols/protocol
+ const protocolMediaType = mediaTypeVideoRef && mediaTypeVideoRef.hasOwnProperty('protocol');
+ const protocolsMediaType = mediaTypeVideoRef && mediaTypeVideoRef.hasOwnProperty('protocols');
+ const protocolVideoRef = paramsVideoRef && paramsVideoRef.hasOwnProperty('protocol');
+ const protocolsVideoRef = paramsVideoRef && paramsVideoRef.hasOwnProperty('protocols');
+
+ return protocolMediaType || protocolsMediaType || protocolVideoRef || protocolsVideoRef;
+}
+
+/**
+ * Get One size from Size Array
+ * [[250,350]] -> [250, 350]
+ * [250, 350] -> [250, 350]
+ * @param {array} sizes array of sizes
+ */
+function getFirstSize(sizes = []) {
+ if (isValidSize(sizes)) {
+ return sizes;
+ } else if (isValidSize(sizes[0])) {
+ return sizes[0];
+ }
return false;
}
@@ -295,9 +381,9 @@ function includesSize(sizeArray, size) {
/**
* Determines whether or not the given bidFloor parameters are valid.
*
- * @param {*} bidFloor The bidFloor parameter inside bid request config.
- * @param {*} bidFloorCur The bidFloorCur parameter inside bid request config.
- * @return {boolean} True if this is a valid bidFloor parameters format, and false
+ * @param {number} bidFloor The bidFloor parameter inside bid request config.
+ * @param {number} bidFloorCur The bidFloorCur parameter inside bid request config.
+ * @return {bool} True if this is a valid bidFloor parameters format, and false
* otherwise.
*/
function isValidBidFloorParams(bidFloor, bidFloorCur) {
@@ -534,31 +620,31 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
let currMissingImps = [];
while (i < transactionIds.length && requests.length < MAX_REQ_LIMIT) {
- if (impressions[transactionIds[i]].hasOwnProperty('missingCount')) {
- msd = impressions[transactionIds[i]].missingCount;
- }
+ const impObj = impressions[transactionIds[i]];
+ msd = utils.deepAccess(impObj, 'missingCount') && utils.deepAccess(impObj, 'ixImps') ? impObj.missingCount : 0;
if (BASE_REQ_SIZE < MAX_REQ_SIZE) {
- trimImpressions(impressions[transactionIds[i]], MAX_REQ_SIZE - BASE_REQ_SIZE);
+ trimImpressions(impObj, MAX_REQ_SIZE - BASE_REQ_SIZE);
} else {
utils.logError('ix bidder: Base request size has exceeded maximum request size.');
}
- if (impressions[transactionIds[i]].hasOwnProperty('missingImps')) {
- msi = impressions[transactionIds[i]].missingImps.length;
- }
+ msi = utils.deepAccess(impObj, 'missingImps') && utils.deepAccess(impObj, 'ixImps') ? impObj.missingImps.length : 0;
- let currImpsSize = new Blob([encodeURIComponent(JSON.stringify(impressions[transactionIds[i]]))]).size;
+ let currImpsSize = new Blob([encodeURIComponent(JSON.stringify(impObj))]).size;
currReqSize += currImpsSize;
if (currReqSize < MAX_REQ_SIZE) {
- // pushing ix configured sizes first
- r.imp.push(...impressions[transactionIds[i]].ixImps);
+ // since not reading params.size, ixImps can be undefined/empty
+ if (impObj.ixImps && impObj.ixImps.length > 0) {
+ // pushing ix configured sizes first
+ r.imp.push(...impObj.ixImps);
+ }
// update msd msi
r.ext.ixdiag.msd += msd;
r.ext.ixdiag.msi += msi;
- if (impressions[transactionIds[i]].hasOwnProperty('missingImps')) {
- currMissingImps.push(...impressions[transactionIds[i]].missingImps);
+ if (impObj.hasOwnProperty('missingImps') && impObj.missingImps.length > 0) {
+ currMissingImps.push(...impObj.missingImps);
}
i++;
@@ -699,6 +785,7 @@ function trimImpressions(impressions, maxSize) {
currSize = new Blob([encodeURIComponent(JSON.stringify(impressions))]).size;
}
}
+
/**
*
* @param {array} bannerSizeList list of banner sizes
@@ -707,14 +794,15 @@ function trimImpressions(impressions, maxSize) {
*/
function removeFromSizes(bannerSizeList, bannerSize) {
+ if (!bannerSize) return;
+
for (let i = 0; i < bannerSizeList.length; i++) {
- if (bannerSize[0] == bannerSizeList[i][0] && bannerSize[1] == bannerSizeList[i][1]) {
+ const size = bannerSizeList[i];
+ if (bannerSize[0] === size[0] && bannerSize[1] === size[1]) {
bannerSizeList.splice(i, 1);
- return true;
+ break;
}
}
- // size not found
- return false;
}
/**
@@ -790,40 +878,26 @@ export const spec = {
const hasBidFloor = bid.params.hasOwnProperty('bidFloor');
const hasBidFloorCur = bid.params.hasOwnProperty('bidFloorCur');
- if (!isValidSize(bid.params.size)) {
- utils.logError('ix bidder params: bid size has invalid format.');
- return false;
- }
-
if (bid.hasOwnProperty('mediaType') && !(utils.contains(SUPPORTED_AD_TYPES, bid.mediaType))) {
return false;
}
- if (bid.hasOwnProperty('mediaTypes') && !(mediaTypeBannerSizes || mediaTypeVideoPlayerSize)) {
+ if (utils.deepAccess(bid, 'mediaTypes.banner') && !mediaTypeBannerSizes) {
return false;
}
- if (!includesSize(bid.sizes, paramsSize) && !((mediaTypeVideoPlayerSize && includesSize(mediaTypeVideoPlayerSize, paramsSize)) ||
- (mediaTypeBannerSizes && includesSize(mediaTypeBannerSizes, paramsSize)))) {
- utils.logError('ix bidder params: bid size is not included in ad unit sizes or player size.');
- return false;
- }
-
- if (mediaTypeVideoRef && paramsVideoRef) {
- const requiredIXParams = ['mimes', 'minduration', 'maxduration', 'protocols'];
- let isParamsLevelValid = true;
- for (let property of requiredIXParams) {
- if (!mediaTypeVideoRef.hasOwnProperty(property) && !paramsVideoRef.hasOwnProperty(property)) {
- const isProtocolsValid = (property === 'protocols' && (mediaTypeVideoRef.hasOwnProperty('protocol') || paramsVideoRef.hasOwnProperty('protocol')));
- if (isProtocolsValid) {
- continue;
- }
- utils.logError('ix bidder params: ' + property + ' is not included in either the adunit or params level');
- isParamsLevelValid = false;
- }
+ if (paramsSize) {
+ // since there is an ix bidder level size, make sure its valid
+ const ixSize = getFirstSize(paramsSize);
+ if (!ixSize) {
+ utils.logError('ix bidder params: size has invalid format.');
+ return false;
}
-
- if (!isParamsLevelValid) {
+ // check if the ix bidder level size, is present in ad unit level
+ if (!includesSize(bid.sizes, ixSize) &&
+ !(includesSize(mediaTypeVideoPlayerSize, ixSize)) &&
+ !(includesSize(mediaTypeBannerSizes, ixSize))) {
+ utils.logError('ix bidder params: bid size is not included in ad unit sizes or player size.');
return false;
}
}
@@ -839,7 +913,10 @@ export const spec = {
return false;
}
}
-
+ // For multi format unit
+ if (!mediaTypeBannerSizes && (mediaTypeVideoRef || paramsVideoRef)) {
+ return checkVideoParams(bid, mediaTypeVideoRef, paramsVideoRef);
+ }
return true;
},
@@ -867,30 +944,35 @@ export const spec = {
for (let i = 0; i < validBidRequests.length; i++) {
validBidRequest = validBidRequests[i];
-
- if (validBidRequest.mediaType === VIDEO || utils.deepAccess(validBidRequest, 'mediaTypes.video')) {
- if (validBidRequest.mediaType === VIDEO || includesSize(validBidRequest.mediaTypes.video.playerSize, validBidRequest.params.size)) {
- if (!videoImps.hasOwnProperty(validBidRequest.transactionId)) {
+ const videoAdUnitRef = utils.deepAccess(validBidRequest, 'mediaTypes.video');
+ const videoParamRef = utils.deepAccess(validBidRequest, 'params.video');
+
+ // identify video ad unit
+ if (validBidRequest.mediaType === VIDEO || videoAdUnitRef || videoParamRef) {
+ if (!videoImps.hasOwnProperty(validBidRequest.transactionId)) {
+ const imp = bidToVideoImp(validBidRequest);
+ if (Object.keys(imp).length != 0) {
videoImps[validBidRequest.transactionId] = {};
- }
- if (!videoImps[validBidRequest.transactionId].hasOwnProperty('ixImps')) {
videoImps[validBidRequest.transactionId].ixImps = [];
+ videoImps[validBidRequest.transactionId].ixImps.push(imp);
}
- videoImps[validBidRequest.transactionId].ixImps.push(bidToVideoImp(validBidRequest));
}
}
+
if (validBidRequest.mediaType === BANNER ||
- (utils.deepAccess(validBidRequest, 'mediaTypes.banner') && includesSize(utils.deepAccess(validBidRequest, 'mediaTypes.banner.sizes'), validBidRequest.params.size)) ||
+ (utils.deepAccess(validBidRequest, 'mediaTypes.banner.sizes')) ||
(!validBidRequest.mediaType && !validBidRequest.mediaTypes)) {
let imp = bidToBannerImp(validBidRequest);
-
- if (!bannerImps.hasOwnProperty(validBidRequest.transactionId)) {
- bannerImps[validBidRequest.transactionId] = {};
- }
- if (!bannerImps[validBidRequest.transactionId].hasOwnProperty('ixImps')) {
- bannerImps[validBidRequest.transactionId].ixImps = []
+ // Create IX imps from params.size
+ if (utils.deepAccess(validBidRequest, 'params.size')) {
+ if (!bannerImps.hasOwnProperty(validBidRequest.transactionId)) {
+ bannerImps[validBidRequest.transactionId] = {};
+ }
+ if (!bannerImps[validBidRequest.transactionId].hasOwnProperty('ixImps')) {
+ bannerImps[validBidRequest.transactionId].ixImps = []
+ }
+ bannerImps[validBidRequest.transactionId].ixImps.push(imp);
}
- bannerImps[validBidRequest.transactionId].ixImps.push(imp);
if (ixConfig.hasOwnProperty('detectMissingSizes') && ixConfig.detectMissingSizes) {
updateMissingSizes(validBidRequest, missingBannerSizes, imp);
}
diff --git a/modules/ixBidAdapter.md b/modules/ixBidAdapter.md
index c358b19a0a2..59b699bad2d 100644
--- a/modules/ixBidAdapter.md
+++ b/modules/ixBidAdapter.md
@@ -13,30 +13,10 @@ Description
This module connects publishers to Index Exchange's (IX) network of demand
sources through Prebid.js. This module is GDPR and CCPA compliant.
-It is compatible with both the older ad unit format where the `sizes` and
-`mediaType` properties are placed at the top-level of the ad unit, and the newer
-format where this information is encapsulated within the `mediaTypes` object. We
-recommend that you use the newer format when possible as it will be better able
+It is compatible with the newer PrebidJS 5.0 ad unit format where the `banner` and/or `video` properties are encapsulated within the `adUnits[].mediaTypes` object. We
+recommend that you use this newer format when possible as it will be better able
to accommodate new feature additions.
-If a mix of properties from both formats are present within an ad unit, the
-newer format's properties will take precedence.
-
-Here are examples of both formats.
-
-##### Older Format
-```javascript
-var adUnits = [{
- // ...
-
- sizes: [
- [300, 250],
- [300, 600]
- ]
-
- // ...
-}];
-```
##### Newer Format
```javascript
@@ -51,10 +31,7 @@ var adUnits = [{
},
video: {
context: 'instream',
- playerSize: [
- [300, 250],
- [300, 600]
- ]
+ playerSize: [300, 250]
}
},
// ...
@@ -69,30 +46,59 @@ var adUnits = [{
| Video | Fully supported for all IX approved sizes.
| Native | Not supported.
-# Bid Parameters
+
+
+# Ad unit or Bidder Parameters
+
+These params can be specified in the ad unit level `adUnits[].mediaTypes`, which will be the preferred way going forward with PBJS 5.0
Each of the IX-specific parameters provided under the `adUnits[].bids[].params`
object are detailed here.
+
### Banner
| Key | Scope | Type | Description
| --- | --- | --- | ---
-| siteId | Required | String | An IX-specific identifier that is associated with a specific size on this ad unit. This is similar to a placement ID or an ad unit ID that some other modules have. Examples: `'3723'`, `'6482'`, `'3639'`
-| size | Required | Number[] | The single size associated with the site ID. It should be one of the sizes listed in the ad unit under `adUnits[].sizes` or `adUnits[].mediaTypes.banner.sizes`. Examples: `[300, 250]`, `[300, 600]`, `[728, 90]`
+| siteId | Required | String | An IX-specific identifier that is associated with this ad unit. It will be associated to the single size, if the size provided. This is similar to a placement ID or an ad unit ID that some other modules have. Examples: `'3723'`, `'6482'`, `'3639'`
+| sizes | Required | Number[Number[]] | The size / sizes associated with the site ID. It should be one of the sizes listed in the ad unit under `adUnits[].mediaTypes.banner.sizes`. Examples: `[300, 250]`, `[300, 600]`, `[728, 90]`
### Video
| Key | Scope | Type | Description
| --- | --- | --- | ---
-| siteId | Required | String | An IX-specific identifier that is associated with a specific size on this ad unit. This is similar to a placement ID or an ad unit ID that some other modules have. Examples: `'3723'`, `'6482'`, `'3639'`
-| size | Required | Number[] | The single size associated with the site ID. It should be one of the sizes listed in the ad unit under `adUnits[].sizes` or `adUnits[].mediaTypes.video.playerSize`. Examples: `[300, 250]`, `[300, 600]`
-| video | Required | Hash | The video object will serve as the properties of the video ad. You can create any field under the video object that is mentioned in the `OpenRTB Spec v2.5`. Some fields like `mimes, protocols, minduration, maxduration` are required. Properties not defined at this level, will be pulled from the Adunit level.
+| siteId | Required | String | An IX-specific identifier that is associated with this ad unit. It will be associated to the single size, if the size is provided. This is similar to a placement ID or an ad unit ID that some other modules have. Examples: `'3723'`, `'6482'`, `'3639'`
+| size | Optional (Deprecated)| Number[] | The single size associated with the site ID. It should be one of the sizes listed in the ad unit under `adUnits[].sizes` or `adUnits[].mediaTypes.video.playerSize`. Examples: `[300, 250]`, `[300, 600]`
+| video | Optional | Hash | The video object will serve as the properties of the video ad. You can create any field under the video object that is mentioned in the `OpenRTB Spec v2.5`. Some fields like `mimes, protocols, minduration, maxduration` are required. Properties not defined at this level, will be pulled from the Adunit level.
+|video.w| Required | Integer | The video player size width in pixels that will be passed to demand partners.
+|video.h| Required | Integer | The video player size height in pixels that will be passed to demand partners.
+|video.playerSize| Optional* | Integer | The video player size that will be passed to demand partners. * In the absence of `video.w` and `video.h`, this field is required.
| video.mimes | Required | String[] | Array list of content MIME types supported. Popular MIME types include, but are not limited to, `"video/x-ms- wmv"` for Windows Media and `"video/x-flv"` for Flash Video.
|video.minduration| Required | Integer | Minimum video ad duration in seconds.
|video.maxduration| Required | Integer | Maximum video ad duration in seconds.
|video.protocol / video.protocols| Required | Integer / Integer[] | Either a single protocol provided as an integer, or protocols provided as a list of integers. `2` - VAST 2.0, `3` - VAST 3.0, `5` - VAST 2.0 Wrapper, `6` - VAST 3.0 Wrapper
+## Deprecation warning
+
+We are deprecating the older format
+of having `mediaType` and `sizes` at the ad unit level.
+
+Here are examples of the format.
+
+##### Older Deprecated Format
+```javascript
+var adUnits = [{
+ // ...
+
+ sizes: [
+ [300, 250],
+ [300, 600]
+ ]
+
+ // ...
+}];
+```
+
Setup Guide
===========
@@ -100,10 +106,15 @@ Setup Guide
Follow these steps to configure and add the IX module to your Prebid.js
integration.
+Both video and banner params will be read from the `adUnits[].mediaTypes.video` and `adUnits[].mediaTypes.banner` respectively.
+
The examples in this guide assume the following starting configuration (you may remove banner or video, if either does not apply).
+
In regards to video, `context` can either be `'instream'` or `'outstream'`. Note that `outstream` requires additional configuration on the adUnit.
+
+
```javascript
var adUnits = [{
code: 'banner-div-a',
@@ -134,21 +145,23 @@ var adUnits = [{
### 1. Add IX to the appropriate ad units
-For each size in an ad unit that IX will be bidding on, add one of the following
+For each ad unit that IX will be bidding on, add one of the following
bid objects under `adUnits[].bids`:
+- size is optional and deprecated
```javascript
{
bidder: 'ix',
params: {
siteId: '',
- size: []
+ size: [] // deprecated
}
}
```
-Set `params.siteId` and `params.size` in each bid object to the values provided
+Set `params.siteId` in the bid object to the values provided
by your IX representative.
+- `params.size` is not required anymore
**Examples**
@@ -167,14 +180,7 @@ var adUnits = [{
bids: [{
bidder: 'ix',
params: {
- siteId: '12345',
- size: [300, 250]
- }
- }, {
- bidder: 'ix',
- params: {
- siteId: '12345',
- size: [300, 600]
+ siteId: '12345'
}
}]
}];
@@ -185,35 +191,30 @@ var adUnits = [{
code: 'video-div-a',
mediaTypes: {
video: {
+ // Preferred location for openrtb v2.5 compatible video obj
context: 'instream',
- playerSize: [
- [300, 250],
- [300, 600]
- ]
+ playerSize: [300, 250],
+ mimes: [
+ 'video/mp4',
+ 'video/webm'
+ ],
+ minduration: 0,
+ maxduration: 60,
+ protocols: [6]
}
},
bids: [{
bidder: 'ix',
params: {
- siteId: '12345',
- size: [300, 250],
- video: {
- mimes: [
- 'video/mp4',
- 'video/webm'
- ],
- minduration: 0,
- maxduration: 60,
- protocols: [6]
- }
+ siteId: '12345'
}
}, {
bidder: 'ix',
params: {
siteId: '12345',
- size: [300, 600],
video: {
// openrtb v2.5 compatible video obj
+ // If required, use this to override mediaTypes.video.XX properties
}
}
}]
@@ -231,7 +232,14 @@ var adUnits = [{
mediaTypes: {
video: {
context: 'outstream',
- playerSize: [[300, 250]]
+ playerSize: [300, 250],
+ mimes: [
+ 'video/mp4',
+ 'video/webm'
+ ],
+ minduration: 0,
+ maxduration: 60,
+ protocols: [6]
}
},
renderer: {
@@ -244,15 +252,8 @@ var adUnits = [{
bidder: 'ix',
params: {
siteId: '12345',
- size: [300, 250],
video: {
- mimes: [
- 'video/mp4',
- 'video/webm'
- ],
- minduration: 0,
- maxduration: 60,
- protocols: [6]
+ // If required, use this to override mediaTypes.video.XX properties
}
}
}]
@@ -413,11 +414,9 @@ FAQs
### Why do I have to input size in `adUnits[].bids[].params` for IX when the size is already in the ad unit?
-There is one important reason why we recommend it:
+No, only `siteId` is required.
-1. An IX site ID is recommended to map to a single size, whereas an ad unit can have multiple
-sizes. To ensure that the right site ID is mapped to the correct size in the ad unit,
-we require the size to be explicitly stated or our bidder will auto assign the site ID to sizes that are not assigned.
+The `size` parameter is no longer a required field, the `siteId` will now be associated with all the sizes in the ad unit.
### How do I view IX's bid request in the network?
diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js
index 48c8e48e6af..cf716fd594b 100644
--- a/test/spec/modules/ixBidAdapter_spec.js
+++ b/test/spec/modules/ixBidAdapter_spec.js
@@ -212,11 +212,10 @@ describe('IndexexchangeAdapter', function () {
siteId: '123',
size: [300, 250]
},
- sizes: [[300, 250], [300, 600]],
mediaTypes: {
video: {
context: 'outstream',
- playerSize: [[400, 100]]
+ playerSize: [600, 700]
},
banner: {
sizes: [[300, 250], [300, 600]]
@@ -246,20 +245,19 @@ describe('IndexexchangeAdapter', function () {
maxduration: 60,
protocols: [1]
},
- size: [400, 100]
+ size: [300, 250]
},
- sizes: [[300, 250], [300, 600]],
mediaTypes: {
video: {
context: 'outstream',
- playerSize: [[400, 100]]
+ playerSize: [300, 250]
},
banner: {
sizes: [[300, 250], [300, 600]]
}
},
adUnitCode: 'div-gpt-ad-1460505748562-0',
- transactionId: '173f49a8-7549-4218-a23c-e7ba59b47230',
+ transactionId: '273f49a8-7549-4218-a23c-e7ba59b47230',
bidId: '1a2b3c4e',
bidderRequestId: '11a22b33c44e',
auctionId: '1aa2bb3cc4de',
@@ -531,10 +529,10 @@ describe('IndexexchangeAdapter', function () {
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
- it('should return false when size is missing', function () {
+ it('should return True when size is missing ', function () {
const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]);
delete bid.params.size;
- expect(spec.isBidRequestValid(bid)).to.equal(false);
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
});
it('should return false when size array is wrong length', function () {
@@ -553,33 +551,47 @@ describe('IndexexchangeAdapter', function () {
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
- it('should return false when mediaTypes is not banner or video', function () {
+ it('should return false when mediaTypes.banner does not have sizes', function () {
const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]);
bid.mediaTypes = {
- native: {
- sizes: [[300, 250]]
+ banner: {
+ size: [[300, 250]]
}
};
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
- it('should return false when mediaTypes.banner does not have sizes', function () {
- const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]);
+ it('should return false when mediaTypes.video.playerSize does not include params.size', function () {
+ const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]);
bid.mediaTypes = {
- banner: {
- size: [[300, 250]]
+ video: {
+ playerSize: [300, 250]
}
};
+ bid.params.size = [100, 200];
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
- it('should return false when mediaTypes.video does not have sizes', function () {
+ it('should return true when mediaTypes.video.playerSize includes params.size', function () {
const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]);
bid.mediaTypes = {
video: {
- size: [[300, 250]]
+ playerSize: [[300, 250], [200, 300]]
}
};
+ bid.params.size = [[300, 250]];
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+
+ it('should return true when bid.params.size is missing', function () {
+ const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]);
+ delete bid.params.size;
+ expect(spec.isBidRequestValid(bid)).to.equal(true);
+ });
+
+ it('should return false when minduration is missing', function () {
+ const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]);
+ delete bid.params.video.minduration;
expect(spec.isBidRequestValid(bid)).to.equal(false);
});
@@ -709,7 +721,7 @@ describe('IndexexchangeAdapter', function () {
const request = spec.buildRequests(cloneValidBid, ALIAS_OPTIONS);
const payload = JSON.parse(request[0].data.r);
expect(request).to.be.an('array');
- expect(request).to.have.lengthOf(1);
+ expect(request).to.have.lengthOf.above(0); // should be 1 or more
expect(payload.user.eids).to.have.lengthOf(5);
expect(payload.user.eids).to.deep.include(DEFAULT_USERID_PAYLOAD[0]);
});
@@ -1517,7 +1529,7 @@ describe('IndexexchangeAdapter', function () {
expect(impression.id).to.equal(DEFAULT_BANNER_VALID_BID[0].bidId);
expect(impression.banner).to.exist;
- expect(impression.banner.w).to.equal(DEFAULT_BANNER_VALID_BID[0].params.size[0]);
+ expect(impression.banner.w).to.equal(DEFAULT_BANNER_VALID_BID[0].params.size[0]);// undefined - 300
expect(impression.banner.h).to.equal(DEFAULT_BANNER_VALID_BID[0].params.size[1]);
expect(impression.banner.topframe).to.exist;
expect(impression.banner.topframe).to.be.oneOf([0, 1]);
@@ -1858,25 +1870,7 @@ describe('IndexexchangeAdapter', function () {
expect(impression.video.skippable).to.equal(false);
expect(impression.ext).to.exist;
expect(impression.ext.siteID).to.equal(DEFAULT_VIDEO_VALID_BID[0].params.siteId.toString());
- expect(impression.ext.sid).to.equal(sidValue);
- });
-
- it('impression should have correct format when mediaType is specified.', function () {
- const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]);
- delete bid.mediaTypes;
- bid.mediaType = 'video';
- const requestBidFloor = spec.buildRequests([bid])[0];
- const impression = JSON.parse(requestBidFloor.data.r).imp[0];
- const sidValue = `${DEFAULT_VIDEO_VALID_BID[0].params.size[0].toString()}x${DEFAULT_VIDEO_VALID_BID[0].params.size[1].toString()}`;
-
- expect(impression.id).to.equal(DEFAULT_VIDEO_VALID_BID[0].bidId);
- expect(impression.video).to.exist;
- expect(impression.video.w).to.equal(DEFAULT_VIDEO_VALID_BID[0].params.size[0]);
- expect(impression.video.h).to.equal(DEFAULT_VIDEO_VALID_BID[0].params.size[1]);
- expect(impression.video.placement).to.not.exist;
- expect(impression.ext).to.exist;
- expect(impression.ext.siteID).to.equal(DEFAULT_VIDEO_VALID_BID[0].params.siteId.toString());
- expect(impression.ext.sid).to.equal(sidValue);
+ expect(impression.ext.sid).to.equal(sidValue); // TODO undefined - 400x600
});
it('should set correct placement if context is outstream', function () {
@@ -1891,6 +1885,14 @@ describe('IndexexchangeAdapter', function () {
expect(impression.video.placement).to.equal(4);
});
+ it('should handle unexpected context', function() {
+ const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]);
+ bid.mediaTypes.video.context = 'VaccineJanssen';
+ const request = spec.buildRequests([bid])[0];
+ const impression = JSON.parse(request.data.r).imp[0];
+ expect(impression.video.placement).to.be.undefined;
+ });
+
it('should not override video properties if they are already configured at the params video level', function () {
const bid = utils.deepClone(DEFAULT_VIDEO_VALID_BID[0]);
bid.mediaTypes.video.context = 'outstream';
@@ -1944,22 +1946,31 @@ describe('IndexexchangeAdapter', function () {
});
describe('only video bidder params set', function () {
- const request = spec.buildRequests(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID);
-
- const videoImp = JSON.parse(request[0].data.r).imp[0];
- expect(JSON.parse(request[0].data.r).imp).to.have.lengthOf(1);
- expect(JSON.parse(request[0].data.v)).to.equal(VIDEO_ENDPOINT_VERSION);
- expect(videoImp.id).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].bidId);
- expect(videoImp.video).to.exist;
- expect(videoImp.video.w).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].params.size[0]);
- expect(videoImp.video.h).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].params.size[1]);
+ it('should generate video impression', function () {
+ const request = spec.buildRequests(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID);
+ const videoImp = JSON.parse(request[1].data.r).imp[0];
+ expect(JSON.parse(request[1].data.r).imp).to.have.lengthOf(1);
+ expect(JSON.parse(request[1].data.v)).to.equal(VIDEO_ENDPOINT_VERSION);
+ expect(videoImp.id).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].bidId);
+ expect(videoImp.video).to.exist;
+ expect(videoImp.video.w).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].params.size[0]);
+ expect(videoImp.video.h).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].params.size[1]);
+ });
+ it('should get missing sizes count 0 when params.size not used', function () {
+ const bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]);
+ delete bid.params.size;
+ const request = spec.buildRequests([bid]);
+ const diagObj = JSON.parse(request[0].data.r).ext.ixdiag;
+ expect(diagObj.msd).to.equal(0);
+ expect(diagObj.msi).to.equal(0);
+ });
});
describe('both banner and video bidder params set', function () {
const request = spec.buildRequests([DEFAULT_MULTIFORMAT_BANNER_VALID_BID[0], DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]]);
it('should return valid banner and video requests', function () {
const bannerImp = JSON.parse(request[0].data.r).imp[0];
- expect(JSON.parse(request[0].data.r).imp).to.have.lengthOf(2);
+ expect(JSON.parse(request[0].data.r).imp).to.have.lengthOf(4);
expect(JSON.parse(request[0].data.v)).to.equal(BANNER_ENDPOINT_VERSION);
expect(bannerImp.id).to.equal(DEFAULT_MULTIFORMAT_BANNER_VALID_BID[0].bidId);
expect(bannerImp.banner).to.exist;
@@ -1971,18 +1982,18 @@ describe('IndexexchangeAdapter', function () {
expect(JSON.parse(request[1].data.v)).to.equal(VIDEO_ENDPOINT_VERSION);
expect(videoImp.id).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].bidId);
expect(videoImp.video).to.exist;
- expect(videoImp.video.w).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].params.size[0]);
- expect(videoImp.video.h).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].params.size[1]);
+ expect(videoImp.video.w).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].mediaTypes.video.playerSize[0]);
+ expect(videoImp.video.h).to.equal(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0].mediaTypes.video.playerSize[1]);
});
it('should contain all correct IXdiag properties', function () {
const diagObj = JSON.parse(request[0].data.r).ext.ixdiag;
expect(diagObj.iu).to.equal(0);
expect(diagObj.nu).to.equal(0);
- expect(diagObj.ou).to.equal(1);
+ expect(diagObj.ou).to.equal(2);
expect(diagObj.ren).to.equal(false);
- expect(diagObj.mfu).to.equal(1);
- expect(diagObj.allu).to.equal(1);
+ expect(diagObj.mfu).to.equal(2);
+ expect(diagObj.allu).to.equal(2);
expect(diagObj.version).to.equal('$prebid.version$');
});
});