Skip to content

Commit

Permalink
IX Bid Adapter: Outstream Support Update (#8412)
Browse files Browse the repository at this point in the history
* outstream player update

* documentation update

Co-authored-by: Love Sharma <love.sharma@indexexchange.com>
  • Loading branch information
lksharma and Love Sharma authored May 17, 2022
1 parent 26621fd commit 3ef3cf4
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 93 deletions.
85 changes: 60 additions & 25 deletions modules/ixBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
deepAccess,
deepClone,
deepSetValue,
getGptSlotInfoForAdUnitCode,
hasDeviceAccess,
inIframe,
isArray,
Expand Down Expand Up @@ -39,11 +40,12 @@ const VIDEO_TIME_TO_LIVE = 3600; // 1hr
const NET_REVENUE = true;
const MAX_REQUEST_SIZE = 8000;
const MAX_REQUEST_LIMIT = 4;
const OUTSTREAM_MINIMUM_PLAYER_SIZE = [300, 250];
const PRICE_TO_DOLLAR_FACTOR = {
JPY: 1
};
const USER_SYNC_URL = 'https://js-sec.indexww.com/um/ixmatch.html';
const RENDERER_URL = 'https://js-sec.indexww.com/htv/video-player.js';

const FLOOR_SOURCE = { PBJS: 'p', IX: 'x' };
export const ERROR_CODES = {
BID_SIZE_INVALID_FORMAT: 1,
Expand Down Expand Up @@ -856,12 +858,10 @@ function buildIXDiag(validBidRequests) {

if (deepAccess(bid, 'mediaTypes.video.context') === 'outstream') {
ixdiag.ou++;
// renderer only needed for outstream

const hasRenderer = typeof (deepAccess(bid, 'renderer') || deepAccess(bid, 'mediaTypes.video.renderer')) === 'object';

// if any one ad unit is missing renderer, set ren status to false in diag
ixdiag.ren = ixdiag.ren && hasRenderer ? (deepAccess(ixdiag, 'ren')) : hasRenderer;
if (isIndexRendererPreferred(bid)) {
ixdiag.ren = true;
}
}

if (deepAccess(bid, 'mediaTypes.video.context') === 'instream') {
Expand Down Expand Up @@ -966,7 +966,7 @@ function getPageUrl() {
* @returns {string}
*/
function detectParamsType(validBidRequest) {
if (deepAccess(validBidRequest, 'params.video') && deepAccess(validBidRequest, 'mediaTypes.video')) {
if (deepAccess(validBidRequest, 'mediaTypes.video') && bidToVideoImp(validBidRequest).video) {
return VIDEO;
}

Expand Down Expand Up @@ -1128,24 +1128,18 @@ function getCachedErrors() {

/**
*
* Initialize Outstream Renderer
* Initialize IX Outstream Renderer
* @param {Object} bid
*/
function outstreamRenderer(bid) {
bid.renderer.push(() => {
var config = {
width: bid.width,
height: bid.height,
timeout: 3000
};

// IXOutstreamPlayer supports both vastUrl and vastXml, so we can pass either.
// Since vastUrl is going to be deprecated from exchange response, vastXml takes priority.
if (bid.vastXml) {
window.IXOutstreamPlayer(bid.vastXml, bid.adUnitCode, config);
} else {
window.IXOutstreamPlayer(bid.vastUrl, bid.adUnitCode, config);
bid.renderer.push(function () {
const adUnitCode = bid.adUnitCode;
const divId = document.getElementById(adUnitCode) ? adUnitCode : getGptSlotInfoForAdUnitCode(adUnitCode).divId;
if (!divId) {
logWarn(`IX Bid Adapter: adUnitCode: ${divId} not found on page.`);
return;
}
window.createIXPlayer(divId, bid);
});
}

Expand All @@ -1154,22 +1148,48 @@ function outstreamRenderer(bid) {
* @param {string} id
* @returns {Renderer}
*/
function createRenderer(id) {
function createRenderer(id, renderUrl) {
const renderer = Renderer.install({
id: id,
url: RENDERER_URL,
url: renderUrl,
loaded: false
});

try {
renderer.setRender(outstreamRenderer);
} catch (err) {
logWarn('Prebid Error calling setRender on renderer', err);
return null;
}

if (!renderUrl) {
logWarn('Outstream renderer URL not found');
return null;
}

return renderer;
}

/**
* Returns whether our renderer could potentially be used.
* @param {*} bid bid object
*/
function isIndexRendererPreferred(bid) {
if (deepAccess(bid, 'mediaTypes.video.context') !== 'outstream') {
return false;
}

// ad unit renderer could be on the adUnit.mediaTypes.video level or adUnit level
let renderer = deepAccess(bid, 'mediaTypes.video.renderer');
if (!renderer) {
renderer = deepAccess(bid, 'renderer');
}

const isValid = !!(typeof (renderer) === 'object' && renderer.url && renderer.render);
// if renderer on the adunit is not valid or it's only a backup, our renderer may be used
return !isValid || renderer.backupOnly;
}

export const spec = {

code: BIDDER_CODE,
Expand Down Expand Up @@ -1253,6 +1273,17 @@ export const spec = {
return false;
}
}

const videoImp = bidToVideoImp(bid).video;
if (deepAccess(bid, 'mediaTypes.video.context') === OUTSTREAM && isIndexRendererPreferred(bid) && videoImp) {
const outstreamPlayerSize = deepAccess(videoImp, 'playerSize')[0];
const isValidSize = outstreamPlayerSize[0] >= OUTSTREAM_MINIMUM_PLAYER_SIZE[0] && outstreamPlayerSize[1] >= OUTSTREAM_MINIMUM_PLAYER_SIZE[1];
if (!isValidSize) {
logError(`IX Bid Adapter: ${mediaTypeVideoPlayerSize} is an invalid size for IX outstream renderer`);
return false;
}
}

return true;
},

Expand Down Expand Up @@ -1363,8 +1394,12 @@ export const spec = {
const bidRequest = getBidRequest(innerBids[j].impid, requestBid.imp, bidderRequest.validBidRequests);
bid = parseBid(innerBids[j], responseBody.cur, bidRequest);

if (!deepAccess(bid, 'mediaTypes.video.renderer') && deepAccess(bid, 'mediaTypes.video.context') === 'outstream') {
bid.renderer = createRenderer(innerBids[j].bidId);
if (bid.mediaType === VIDEO && isIndexRendererPreferred(bidRequest)) {
const renderUrl = deepAccess(responseBody, 'ext.videoplayerurl');
bid.renderer = createRenderer(innerBids[j].bidId, renderUrl);
if (!bid.renderer) {
continue;
}
}

bids.push(bid);
Expand Down
84 changes: 42 additions & 42 deletions modules/ixBidAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,10 @@ object are detailed here.
| 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.w| Required | Integer | The width of the video player in pixels that will be passed to demand partners.<br /> *If you are using Index’s outstream player and have placed the `video` object at the `bidder` level, this is a required field. You must define the size of the video player using the `video.w` and `video.h` parameters, with a minimum video player size of 300 x 250.
|video.h| Required | Integer | The height of the video player in pixels that will be passed to demand partners. <br />*If you are using Index’s outstream player and have placed the `video` object at the `bidder` level, this is a required field. You must define the size of the video player using the `video.w` and `video.h` parameters, with a minimum video player size of 300 x 250.
|video.playerSize| Optional* | Array[Integer,Integer] | The video player size that will be passed to demand partners.</br /> *If you are using Index’s outstream player and have placed the `video` object at the `adUnit` level, this is a required field. You must define the size of the video player using this parameter, with a minimum video player size of 300 x 250.
| video.mimes | Required | String[] | If you are using Index’s outstream video player and want to learn more about what is supported, see [List of supported OpenRTB bid request fields for Sellers](https://kb.indexexchange.com/publishers/openrtb_integration/list_of_supported_openrtb_bid_request_fields_for_sellers.htm#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
Expand Down Expand Up @@ -111,9 +111,7 @@ Both video and banner params will be read from the `adUnits[].mediaTypes.video`
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.


In regards to video, `context` can either be `'instream'` or `'outstream'`.

```javascript
var adUnits = [{
Expand Down Expand Up @@ -195,9 +193,9 @@ var adUnits = [{
context: 'instream',
playerSize: [300, 250],
mimes: [
'video/mp4',
'video/webm'
],
'video/mp4',
'video/webm'
],
minduration: 0,
maxduration: 60,
protocols: [6]
Expand All @@ -224,45 +222,47 @@ Please note that you can re-use the existing `siteId` within the same flex
position.

**Video (Outstream):**
Note that currently, outstream video rendering must be configured by the publisher. In the adUnit, a `renderer` object must be defined, which includes a `url` pointing to the video rendering script, and a `render` function for creating the video player. See http://prebid.org/dev-docs/show-outstream-video-ads.html for more information.

Publishers have two options to receive outstream video demand from Index:
* Using Index’s outstream video player
* In an outstream video configuration set up by the publisher. For more information, see [Prebid’s documentation on how to show video ads.](https://docs.prebid.org/dev-docs/show-outstream-video-ads.html)

**Index’s outstream video player**
Publishers who are using Index as a bidding adapter in Prebid.js can show outstream video ads on their site from us by using Index’s outstream video player. This allows a video ad to display inside of a video player and can be placed anywhere on a publisher’s site, such as in-article, in-feed, and more.

Define a new `video` object for our outstream video player at either the adUnit level or the `bidder` level. If you are setting it at the bidder level, define the size of the video player using the parameters `video.h` and `video.w`. If you are setting it at the `adUnit` level, define the size using video.playerSize.

For more information on how to structure the `video` object, refer to the following code example:


```javascript
var adUnits = [{
code: 'video-div-a',
code: 'div-gpt-ad-1571167646410-1',
mediaTypes: {
video: {
playerSize: [640, 360],
context: 'outstream',
playerSize: [300, 250],
mimes: [
'video/mp4',
'video/webm'
],
minduration: 0,
maxduration: 60,
protocols: [6]
}
},
renderer: {
url: 'https://test.com/my-video-player.js',
render: function (bid) {
...
api: [2],
protocols: [2, 3, 5, 6],
minduration: 5,
maxduration: 30,
mimes: ['video/mp4', 'application/javascript'],
placement: 3
}
},
bids: [{
bidder: 'ix',
params: {
siteId: '12345',
video: {
// If required, use this to override mediaTypes.video.XX properties
}
siteId: '715964'
}
}]
}];
```
<em>Please note that your use of the outstream video player will be governed by and subject to the terms and conditions of i) any master services or license agreement entered into by you and Index Exchange; ii) the information provided on our knowledge base linked [here](https://kb.indexexchange.com/publishers/prebid_integration/outstream_video_prebidjs.htm) and [here](https://kb.indexexchange.com/publishers/guidelines/standard_contractual_clauses.htm), and iii) our [Privacy Policy](https://www.indexexchange.com/privacy/). Your use of Index’s outstream video player constitutes your acknowledgement and acceptance of the foregoing. </em>

#### Video Caching

Note that the IX adapter expects a client-side Prebid Cache to be enabled for video bidding.
Note that the IX adapter expects a client-side Prebid Cache to be enabled for instream video bidding.

```
pbjs.setConfig({
Expand Down Expand Up @@ -293,21 +293,21 @@ pbjs.setConfig({
By default, the IX bidding adapter bids on all banner sizes available in the ad unit when configured to at least one banner size. If you want the IX bidding adapter to only bid on the banner size it’s configured to, switch off this feature using `detectMissingSizes`.
```
pbjs.setConfig({
ix: {
detectMissingSizes: false
}
});
ix: {
detectMissingSizes: false
}
});
```
OR
```
pbjs.setBidderConfig({
bidders: ["ix"],
config: {
ix: {
detectMissingSizes: false
}
}
});
bidders: ["ix"],
config: {
ix: {
detectMissingSizes: false
}
}
});
```

### 2. Include `ixBidAdapter` in your build process
Expand Down
Loading

0 comments on commit 3ef3cf4

Please sign in to comment.