-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Safe renderer #6585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Safe renderer #6585
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,22 +17,23 @@ In simple terms, a renderer offers publishers: | |
| - A way to introduce new ad formats without disrupting user experience | ||
| - Control over maintaining design consistency between ads and site content | ||
|
|
||
| ## Renderer Object | ||
| ## Types of renderers | ||
|
|
||
| {: .table .table-bordered .table-striped } | ||
| | Name | Scope | Type | Description | | ||
| |--------------+----------+---------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||
| | `url` | Required | String | URL to the renderer script that will be loaded. This script should create a renderer object in the global scope. | | ||
| | `render` | Required | Function | Function that tells Prebid.js how to invoke the renderer script to render a bid. The function receives the bid object as a parameter. | | ||
| | `backupOnly` | Optional | Boolean | if set to true, buyer or adapter renderer will be preferred | | ||
| From Prebid 11.15 onward, publishers and adapters can specify their custom renderers in two ways: top window renderers (the old-fashioned way) and the new Safe Renderer approach. The latter has the significant advantage of executing renderer code inside the ad frame, where the ad markup and other important data are accessible within the frame context, whereas the old approach executed renderers in the top window. We strongly recommend using the new Safe Renderer approach whenever possible. | ||
|
|
||
| If both Safe Renderer and top window renderers are specified, the Safe Renderer takes precedence. You can also disable top window renderers through the top level configuration flag: | ||
|
|
||
| ```javascript | ||
| config.setConfig({ allowTopWindowRenderers: false }) | ||
| ``` | ||
|
|
||
| ## Renderer Implementation Levels | ||
|
|
||
| Renderers can be specified at multiple levels: | ||
| Renderers can be specified at multiple levels by specifying either `safeRenderer` or `renderer` field on one of the following levels: | ||
|
|
||
| 1. MediaType Level (adUnit.mediaTypes.video\|banner\|native.renderer): If a renderer is associated with a specific mediaType (video, banner, or native), it will be used to display any demand associated with that mediaType. This is the preferred method for all ad types. | ||
| 2. AdUnit Level (adUnit.renderer): Applied to all bids for this ad unit that don't override it. This is a legacy approach; using the mediaType-level renderer is preferred. | ||
| 3. Bidder Level (adUnit.bids[].renderer): Applied only to this bidder, overriding adUnit renderer if both exist. | ||
| 1. MediaType Level `adUnit.mediaTypes.video|banner|native|audio`: If a renderer is associated with a specific mediaType (video, banner, audio or native), it will be used to display any demand associated with that mediaType. This is the preferred method for all ad types. | ||
| 2. AdUnit Level `adUnit`: Applied to all bids for this ad unit that don't override it. This is a legacy approach; using the mediaType-level renderer is preferred. | ||
| 3. Bidder Level `adUnit.bids[]`: Applied only to this bidder, overriding adUnit renderer if both exist. | ||
| 4. Default: If no renderer is specified at any level, Prebid will use the default renderer for the media type, if one exists. For banner and native ads, Prebid.js has built-in default rendering capabilities. | ||
|
|
||
| ### Priority Order | ||
|
|
@@ -44,9 +45,148 @@ When multiple renderers are defined, the following priority is used: | |
| 3. Bidder Level renderer | ||
| 4. Default renderer | ||
|
|
||
| ## Special Cases | ||
| ## Safe renderer | ||
|
|
||
| The Safe Renderer works similarly to the default Prebid renderer in that it is injected into the ad frame. The key difference is that it does not render the ad by itself. Instead, it loads an external renderer script using the URL specified in the Safe Renderer configuration. Once the script is loaded, the Safe Renderer executes the `window.pbRenderInFrame({ mediaType, config, ...renderingData })` function, which must be defined by the external script | ||
|
|
||
| ### Config object | ||
|
|
||
| {: .table .table-bordered .table-striped } | ||
| | Name | Scope | Type | Description | | ||
| | -------------- | ---------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | `url` | Required | String | URL to the external renderer script that will be loaded and executed within Safe renderer | | ||
| | `config` | Optional | Object | Object that will be passed to external renderer script as a `config` field. For bid adapters use | | ||
| | `getConfig` | Optional | Function | Function that will evaluate `config` object accessible in external renderer script. For publisher's use. Accepts `bidResponse` as a parameter | | ||
|
|
||
| ```javascript | ||
| const adUnits = [ | ||
| { | ||
| mediaTypes: { | ||
| video: { | ||
| context: 'outstream', | ||
| playerSize: [300, 250], | ||
| mimes: ['video/mp4'], | ||
| safeRenderer: { | ||
| url: 'https://trafto.s3.eu-central-1.amazonaws.com/rendererV2.js', | ||
| getConfig: (bidResponse) => { | ||
| return { | ||
| configField: 'passed-from-adunit-config' | ||
| } | ||
| } | ||
| }, | ||
| } | ||
| }, | ||
| code: adUnitCode, | ||
| } | ||
| ]; | ||
| ``` | ||
|
|
||
| ### External script example implementation | ||
|
|
||
| Existing top level custom renderers can be easily migrated to work with the new Safe Renderer approach. The external script simply needs to define the `window.pbRenderInFrame` method and execute the rendering logic inside it. The function accepts a payload object containing `mediaType`, `config` (either passed by bid adapters or evaluated by the publisher-provided `getConfig(bidResponse)` function), and `...renderingData`. | ||
|
|
||
| ```javascript | ||
| /* global YVAP */ | ||
| /** | ||
| * Reference implementation for `bid.safeRenderer.url`. | ||
| * Prebid injects this script into the creative iframe and then calls `window.pbRenderInFrame(payload)`. | ||
| */ | ||
| window.pbRenderInFrame = function ({ mediaType, config, ...renderingData }) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find this a bit confusing, because you are partially destructuring here and then describe the params below, but leave out the Is The
So I guess |
||
|
|
||
| function yvapPlayerRender(b) { | ||
| var safeAdId = | ||
| b.adId != null && String(b.adId).length | ||
| ? String(b.adId).replace(/[^a-zA-Z0-9_-]/g, '') | ||
| : ''; | ||
| var targetNodeId = | ||
| 'pb-yvap-' + | ||
| (safeAdId || 'slot-' + Date.now() + '-' + Math.random().toString(36).slice(2, 9)); | ||
|
|
||
| var container = document.createElement('div'); | ||
| container.id = targetNodeId; | ||
| if (b.width != null) { | ||
| container.style.width = | ||
| typeof b.width === 'number' ? b.width + 'px' : String(b.width); | ||
| } | ||
| if (b.height != null) { | ||
| container.style.height = | ||
| typeof b.height === 'number' ? b.height + 'px' : String(b.height); | ||
| } | ||
| document.body.appendChild(container); | ||
|
|
||
|
|
||
| function initPlayer() { | ||
| // eslint-disable-next-line no-new | ||
| new YVAP({ | ||
| id: targetNodeId, | ||
| player: { | ||
| type: 'Outstream', | ||
| controls: true, | ||
| height: b.height, | ||
| width: b.width | ||
| }, | ||
| ads: { | ||
| adTagXml: b.vastXml | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| if (window.YVAP) { | ||
| initPlayer(); | ||
| return; | ||
| } | ||
|
|
||
| var script = document.createElement('script'); | ||
| script.src = 'https://s.yimg.com/kp/yvap/1.9.0/yvap.js'; | ||
| script.async = true; | ||
| script.onload = function () { | ||
| initPlayer(); | ||
| }; | ||
| script.onerror = function () { | ||
| // eslint-disable-next-line no-console | ||
| console.error('[Yahoo ADS bid adapter]: Outstream renderer script failed to load.'); | ||
| }; | ||
| var firstScript = document.getElementsByTagName('script')[0]; | ||
| if (firstScript && firstScript.parentNode) { | ||
| firstScript.parentNode.insertBefore(script, firstScript); | ||
| } else { | ||
| (document.head || document.documentElement).appendChild(script); | ||
| } | ||
| } | ||
|
|
||
| yvapPlayerRender(renderingData); | ||
| }; | ||
| ``` | ||
|
|
||
| ### Rendering data | ||
|
|
||
| {: .table .table-bordered .table-striped } | ||
| | Property | Description | | ||
| | ---------- | ------------- | | ||
| | `ad` | Ad markup | | ||
| | `adUrl` | Ad markup url | | ||
| | `width` | Width of the creative | | ||
| | `height` | Height of the creative | | ||
| | `instl` | Interstitial flag (`1` for interstitial, `0` for non-interstitial) | | ||
| | `vastXml` | The VAST XML content (if available instead of vastUrl) | | ||
| | `vastUrl` | URL to the VAST XML for video ads | | ||
| | `mediaType` | Type of media ('video', 'banner', etc.) | | ||
| | `safeRenderer` | Prepared Safe Renderer configuration (including `url` and related fields) used to load and run the external renderer script | | ||
|
|
||
| ## Top window renderer | ||
|
|
||
| ### Config object | ||
|
|
||
| {: .table .table-bordered .table-striped } | ||
| | Name | Scope | Type | Description | | ||
| |--------------+----------+---------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||
| | `url` | Required | String | URL to the renderer script that will be loaded. This script should create a renderer object in the global scope. | | ||
| | `render` | Required | Function | Function that tells Prebid.js how to invoke the renderer script to render a bid. The function receives the bid object as a parameter. | | ||
| | `backupOnly` | Optional | Boolean | if set to true, buyer or adapter renderer will be preferred | | ||
|
|
||
| ### Special Cases | ||
|
|
||
| ### Banner with Custom Renderer | ||
| #### Banner with Custom Renderer | ||
|
|
||
| Although renderers are commonly associated with video ads, they can also be used with banner ads to create custom rendering experiences: | ||
|
|
||
|
|
@@ -96,7 +236,7 @@ A banner renderer might be used to: | |
| 4. Apply custom styling or containers to maintain site design aesthetics | ||
| 5. Implement fallback scenarios for different devices or browsers | ||
|
|
||
| ## Renderer Implementation Example | ||
| ### Renderer Implementation Example | ||
|
|
||
| ```javascript | ||
| // Example of a secure custom banner renderer implementation | ||
|
|
@@ -182,7 +322,7 @@ window.BannerRenderer = function (config) { | |
| }; | ||
| ``` | ||
|
|
||
| ## Common Renderer Properties | ||
| ### Common Top window renderer Properties | ||
|
|
||
| Here are commonly used properties from the bid object that can be accessed in the renderer: | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this is what you meant?