Skip to content
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

I2I - updates and new logic for sizeConfig feature #4129

Closed
jsnellbaker opened this issue Aug 29, 2019 · 22 comments
Closed

I2I - updates and new logic for sizeConfig feature #4129

jsnellbaker opened this issue Aug 29, 2019 · 22 comments

Comments

@jsnellbaker
Copy link
Collaborator

This I2I documents the (currently) planned updates to the sizeConfig feature for Prebid.js 3.0. It is open to feedback, so please share any thoughts/concerns/ideas/questions in regards to the outlined approach.

Table of Contents

Status of sizeConfig feature

Context for change:

  • a number of issues/questions have been raised in the past regarding trouble/confusion in using the sizeConfig feature of Prebid.js
  • most of these issues resolved to misunderstandings of the interaction between setting labels in adUnit/bid and the labels role in the sizeConfig object.
    • it was assumed that by setting a label, the corresponding config would be the only source used as the means to filter unsupported ad sizes from the adUnit/bid. Each adUnit would follow a different config according to the labels that were set.
    • instead the feature only looked at all the size configs, figured out which matched the screen-size (ignoring the labels field), combined the list of supported sizes (if there were multiple) and used that final list of sizes to update/filter all adUnits. The labels were only used after this size filtering piece was done to allow/deny the adUnit/bid from entering the auction
  • a number of people felt this logic was frustrating and rather limiting when trying to support more complex uses-cases:
    • such as, when they wanted to define several different configs (for different ad-slots/sections of the page) that re-used/overlapped the mediaQuery params. This type of setup caused the wrong positions to be used for the wrong ad-slots due the merged configs.
  • as a result, it lead to several people try to adopt non-standard adUnit setups where they basically duplicated their adUnit (with the same adUnitCode) so that one would be used in one environment (such as desktop) while another would be used in another (such as mobile)

Proposed updates on sizeConfig feature

Primary Goals:

  • provide publishers a way to choose which specific sizeConfigs should be used for a given adUnit/bid.
  • maintain as many aspects of the original logic as possible, to ease the transition process and to support previous use-cases (eg setup configs without labels, configs with global scope).
  • should be easy to understand yet have the ability to be complex.
  • (if possible) minimize the amount of work for publishers to do for them to use this new logic (or to continue to use their existing setups if they weren't affected by original pain points)

Details on change:

  • the current API structure in the setConfig and adUnit/bid levels remains mostly unchanged (see last point).
  • the internal logics of the how/when these configs are used has been updated; the logic is primarily driven through the presence of the labels field in the sizeConfig objects, rather than the mediaQuery alone be responsible for activating a (or multiple) config(s).
  • add support for a special adUnit label that can be set to have that adUnit (and all its bids) be exempt from the sizeConfig feature.
    • name open for suggstions; some considered options: disable, off, 'pass', 'VIP'

When using a config with a label:
  • that config is only used when that label is used within an adUnit/bid.
  • other configs that happen to share qualifying mediaQuerys for the current screen-size are not included in the filtering process for that adUnit/bid.
  • when multiple label configs are simulatenously valid (see conditions below), the lists of sizes from those configs are combined to form one list.
    • Condition(s):
      • the mediaQuerys for those label configs match the current screen-size
      • multiple qualifying labels are present at the same level in the adUnit/bid
        sizeConfig: [{
            mediaQuery: '(min-width: 1000px)',
            sizesSupported: [[728, 90], [728, 450]],
            labels: ['desktop']
        }, {
            mediaQuery: '(min-width: 1500px)',
            sizesSupported: [[728, 90], [1000, 90], [1000, 450]],
            labels: ['xl']
        }, {
            mediaQuery: '(max-width: 999px)',
            sizesSupported: [[728, 45], [300, 90], [300, 45]],
            labels: ['tablet']
        }]
        
        adUnit: {
            code: 'adUnit1',
            labelAny: ['desktop', 'xl', 'tablet'], 
            mediaTypes: { banner: { sizes: [...] } }
            bids :[{...}]
        }
        • for example - if the screen-size supports, desktop and xl, then their two sizesSupported fields would be combined into one list with the following sizes [[728, 90], [728, 450], [1000, 90], [1000, 450]].
        • when multiple labels configs are active at the adUnit and bid levels, they are treated as two separate phases of filtering; the logic would process the adUnit level first, followed by the bid level (same as current logic).
    • When this merge occurs, we will print messages in console log denoting which label configs were merged and the final list of valid sizes

When using a config without a label:
  • that config is only used when an adUnit/bid does not have any labels defined at all
    • if the adUnit had no label, but a bid did - then that bid's label config is used instead of a no-label config.
  • when multiple no-label configs are simultaneously valid (see condition below), the lists of sizes from those configs are combined to form one list.
    • Condition(s):
      • the mediaQuery for those no-label configs match the current screen-size
    • When this merge occurs, will print messages in the console log denoting some no-label configs were merged and the final list of valid sizes.

Status of other aspects of the sizeConfig feature

  • just to clarify, the following aspects of the feature would remain in their current form:
    • the labelAny and labelAll fields in the adUnit/bid objects
      • would still enforce the and/or relationship requirements of the labels for that adUnit/bid. If it fails, then the adUnit/bid is not included in the auction.
    • ability to pass custom labels in the pbjs.requestBids call and use it to allow/block adUnits/bids
      • in this case, we'd just look for the presence of the label in the adUnit/bid rather than lookup the setConfig configs to filter-out sizes.
    • would still only affect banner type ads, since they're the only media type where the sizes play a pivotal role.
      • video and native type ads are exempt from the feature.
    • for multi-format units - see details in this Prebid.js PR
    • if all sizes are filtered out of an adUnit/bid as a result of the sizes supported by the chosen configs, then that adUnit/bid is removed from the auction.

Outstanding Concerns:

  • New disable feature for an adUnit, should this work at the bid-level as well?
    • Is there a real use-case where this would be needed?
      • If you want a bid to always be included when you have other bids with a label, you can just not include the label on that bid.
    • If the ability is there, it seems likely that a label set at the adUnit level should still be respected (thus making this bid-level setting act like a secondary filter; similar to how adUnit & bid level labels interact). Should it act differently?
  • The current API is rather restricted from a developer perspective; we're unable to add new fields/flags to the feature in the setConfig since the primary configuration point is an array.
    • This field could be reformatted to be nested within an object config (like most other setConfig settings), but this would force a change to publishers to update their setups.
  • While this new logic should promote an more intutitve sense of control (via the labels), there are some aspects of the logic that could be considered confusing, namely: merging of multiple configs and interaction between label and no-label (ie global) configs

Examples of Updated Approach

Example 1: Complex rules working together

sample setup of config object and adUnit(s):

sizeConfig: [{
	mediaQuery: '(min-width: 1200px)',
	sizesSupported: [[728, 90], [728, 450]],
	labels: ['leaderboard-desktop']
}, {
    mediaQuery: '(min-width: 750px) and (max-width: 1199px)',
    sizesSupported: [[728, 90]]
    labels: ['leaderboard-tablet']
}, {
    mediaQuery: '(min-width: 750px) and (max-width: 1199px)',
    sizesSupported: [[300, 250], [400, 400]]
    labels: ['left-square-tablet']
}, {
    mediaQuery: '(min-width: 750px)',
    sizesSupported: [[300, 250], [300, 300], [300, 600]]
}, {
    mediaQuery: '(max-width: 749px)',
    sizesSupported: [[200, 200], [150, 150]]
}]

adUnits: [{
    code: 'side-rail-1', 
    mediaTypes: { banner: { sizes: [[300, 250], [300, 600], [160, 600]] } }
    bids :[{
        bidder: 'bidderD',
        params: {...}
    }]
}, {
    code: 'side-rail-2', 
    mediaTypes: { banner: { sizes: [[120, 600], [160, 600]] } }
    bids :[{
        bidder: 'bidderD',
        params: {...}
    }]
}, {
    code: 'leaderboard',
    labelAny: ['leaderboard-desktop', 'leaderboard-tablet'], 
    mediaTypes: { banner: { sizes: [[728, 90], [728, 450]] } }
    bids :[{
        bidder: 'bidderA',
        params: {...}
    }, {
        bidder: 'bidderB',
        params: {...}
    }, {
        bidder: 'bidderC',
        params: {...}
    }]
}, {
    code: 'left-square',
    mediaTypes: { banner: { sizes: [[300, 250], [300, 600]] } }
    bids :[{
        bidder: 'bidderA',
        params: {...},
        labelAny: ['left-square-tablet']
    }, {
        bidder: 'bidderC',
        params: {...}
    }]
}, {
    code: 'footer-ad',
    labelAny: ['VIP'],      // always include this ad 
    mediaTypes: { banner: { sizes: [[728, 90], [970, 90], [300, 250], [250, 250]] } }
    bids :[{
        bidder: 'bidderA',
        params: {...}
    }, {
        bidder: 'bidderB',
        params: {...}
    }]
}]

As a result of this config and assuming screen-width is 1500px, the following would happen to each adUnit:

  • side-rail-1
    • the 4th sizeConfig would activate
    • the sizes would be filtered down to [[300, 250], [300, 600]]
    • bidderD's bid for this adUnit is included in the auction
  • side-rail-2
    • the 4th sizeConfig would activate
    • the sizes would all be filtered out
    • this adUnit is prevented from participating in the auction
  • leaderboard
    • though multiple labels are listed, only the leaderboard-desktop config activates
    • all the current sizes match the list of supported sizes, so no size filtering takes place
    • bidderA's', bidderB's', and bidderC's' bids for this adUnit are included in the auction
  • left-square
    • since a bid contains a label-based config, we only look at that config and ignore the no-label configs; since the noted label config's mediaQuery doesn't match the screen-size, that specific bid is excluded from the auction
    • bidderC's bid is included in the auction and the sizes remain untouched
  • footer-ad
    • due to presence of the VIP label, this adUnit is exempt from the sizeConfig feature
    • bidderA's and bidderB's bids for this adUnitare always included in the auction

Example 2 - No more duplicating adUnits as a workaround

Example taken from #3226 (comment)

Some context on the setup:
In the example noted below, notice the duplicated the adUnit banner. Per the client, they made a copy of the banner adUnit in order to prevent the 300x250 size from being included in screens >992px.

In the old logic, the sizeConfig would have merged the w992 with either the w768 or the w1200 config. If there was just one banner that listed all 3 sizes, then the 300x250 would have been included in the request since the merged configs listed 300x250 as a valid size.

By splitting the sizes across duplicate adUnits, it ensures that even if the configs are merged together at the larger screen-sizes - the 300x250 wouldn't be part of the active banner adUnit (since that size belongs to the other copy of the banner adUnit).

// I split the MediaQueries by format and make sure they don't overlap for the same format
sizeConfig: [
  {
    mediaQuery: '(min-width: 1200px)',
    sizesSupported: [[728, 90]],
    labels: ['w1200']
  }, {
    mediaQuery: '(min-width: 768px) and (max-width: 1199.98px)',
    sizesSupported: [[468, 60]],
    labels: ['w768']
  }, {
    mediaQuery: '(min-width: 320px) and (max-width: 767.98px)',
    sizesSupported: [[300, 250]],
    labels: ['w320']
  }, {
    mediaQuery: '(min-width: 992px)',
    sizesSupported: [[300, 250]],
    labels: ['w992']
  }
]

// The tricky part: declaring the same adunit twice with different rules
adUnits: [
  {
    code: 'banner',
    labelAny: ['w1200', 'w768'],
    mediaTypes: {
      banner: {
        sizes: [[728, 90], [468, 60]],
      }
    },
    bids: [
      {
        bidder: 'appnexus',
        params: {
          placementId: 111111,
        }
      }
    ]
  }, {
    code: 'banner',
    labelAny: ['w320'],
    mediaTypes: {
      banner: {
        sizes: [[300, 250]],
      }
    },
    bids: [
      {
        bidder: 'appnexus',
        params: {
          placementId: 222222,
        }
      }
    ]
  }, {
    code: 'mpu',
    labelAny: ['w992'],
    mediaTypes: {
      banner: {
        sizes: [[300, 250]],
      }
    },
    bids: [
      {
        bidder: 'appnexus',
        params: {
          placementId: 333333,
        }
      }
    ]
  }
]

With the new approach, the banner adUnit can be 1 complete adUnit without the risk of the 300x250 size being included accidentally (see below). The correct size is ensured due to the new logic incorporating the label that's currently used by that adUnit and looking only at that label's config.

This setup allows a cleaner set of adUnits; by allevating the complexity that came from managing the sizes and the labels across duplicated adUnits, the previously noted workaround should no longer be necessary.

// size configs remain largely the same due to unique requirements per ad-slot (renamed labels to clarify)
sizeConfig: [{
    mediaQuery: '(min-width: 1200px)',
    sizesSupported: [[728, 90]],
    labels: ['banner-w1200'],
  }, {
    mediaQuery: '(min-width: 768px) and (max-width: 1199.98px)',
    sizesSupported: [[468, 60]],
    labels: ['banner-w768'],
  }, {
    mediaQuery: '(min-width: 320px) and (max-width: 767.98px)',
    sizesSupported: [[300, 250]],
    labels: ['banner-w320'],
  }, {
    mediaQuery: '(min-width: 992px)',
    sizesSupported: [[300, 250]],
    labels: ['mpu-w992'],
  }
]

// notice banner adUnit has been consolidated and there is no risk that the 300x250 size will be accidentally included through the `mpu-w992` config
adUnits: [
  {
    code: 'banner',
    mediaTypes: {
      banner: {
        sizes: [[728, 90], [468, 60], [300,250]],
      },
    },
    bids: [
      {
      	labelAny: ['banner-w1200', 'banner-w768'],
        bidder: 'appnexus',
        params: {
          placementId: 111111,
        },
      }, {
      	labelAny: ['banner-w320'],
        bidder: 'appnexus',
        params: {
          placementId: 222222,
        }
      } 
    ]
  }, {
    code: 'mpu',
    labelAny: ['mpu-w992'],
    mediaTypes: {
      banner: {
        sizes: [[300, 250]],
      }
    },
    bids: [
      {
        bidder: 'appnexus',
        params: {
          placementId: 333333,
        }
      }
    ]
  }
]
@bretg
Copy link
Collaborator

bretg commented Sep 13, 2019

@harpere and I dug into this and while we appreciate that quite a bit of work was put into the proposal, we have a couple of observations and reservations.

First, this approach isn't any easier to understand than the current system. One of the complaints people had about the original design was that they didn't get it. The other complaint was lack of flexibility. In both cases, a root problem was the assumption that a global sizeConfig would fit. This model still uses a global sizeConfig, and adds invisible functionality to every adunit (label or no) that then requires awkward flags (like VIP) to control edge cases.

Second, the approach as documented isn't backwards compatible. Everyone who has an existing sizeconfig would have to change, in a major and fairly complicated way, completely flipping the sense of the "join" between sizeConfig and adunits.

Related, the proposal as documented also flips the definition of labelAny to set labels and the labels keyword becomes a conditional. That's confusing.

One modification that would address both of the previous concerns is to keep labelAny as the conditional and label as the declarative, which would mean switching them everywhere in your examples. So anywhere you have 'label', replace with labelAny, and vice versa.

But even doing that, we don't think this proposal does what #3226 asks for, which is to provide straightforward controls similar to a certain well-known ad server.

So here's an alternate proposal, which achieves full backwards-compatibility and infinite control using a paradigm already familiar to everyone managing scenarios complex enough to complain about v1. It also opens the door to supporting the concept for video.

  1. in each AdUnit, allow an optional 'sizeConfig' array in mediaTypes.banner instead of sizes.
  2. this array is a list of increasing screen sizes (no need for mediaQuery) which define which ad sizes are relevant for this adunit
  3. if the sizes array is empty, the adunit is removed
  4. we could also support sizeConfig at the bid level, though this use case is not a strong one in our opinion. We recommend trying to live without it here to keep things simple.

Here's an example showing this approach is pretty straightforward to read, since all the relevant info is together -- no scrolling up to another data structure:

adUnits: [{
    code: 'side-rail-1',
    mediaTypes: { banner: {  sizeConfig: [
       { minViewPort: [0,0], sizes: [] },  // adunit doesn't exist for width < 750px
       { minViewPort: [750,0], sizes: [[120, 600]] }],  // only this size for 750px < screen < 1200px
       { minViewPort: [1200,0], sizes: [[120, 600], [160, 600]] }] // both sizes for >= 1200px
    }},
    bids :[{ ... }]
}]

Advantages:

  1. reads like a code switch statement
  2. no intermediate 'labels'
  3. labelAny/labelAll functionality can still be used for platform, country, etc.
  4. people familiar with the GAM approach will likely find this comfortable. we've tweaked it a bit, but the form is similar.
  5. backwards compatible with existing functionality
  6. no need for special flags like 'VIP'
  7. when Rubicon open sources its 'pattern' library next quarter, this particular improvement will already be released. :-)

Drawbacks:

  1. may be more verbose if long lists of sizes need to be repeated

Here's your full Example 1 converted to the alternate approach:

adUnits: [{
    code: 'side-rail-1',     // adunit only present for >= 750px
    mediaTypes: { banner: { sizeConfig: [
        { minViewPort: [0,0], sizes: [] },    // remove if < 750px
        { minViewPort: [750,0], sizes: [[300, 250], [300, 600]] }]
      }},
    bids :[{
        bidder: 'bidderD',
        params: {...}
    }]
}, {
    code: 'side-rail-2', // adunit only present for > 750px
    mediaTypes: { banner: {  sizeConfig: [
       { minViewPort: [0,0], sizes: [] },
       { minViewPort: [750,0], sizes: [[120, 600], [160, 600]] }]
    }},
    bids :[{
        bidder: 'bidderD',
        params: {...}
    }]
}, {
    code: 'leaderboard', // adunit has diff sizes for >750 and >1200
    mediaTypes: { banner: { sizeConfig:
      { minViewPort: [0,0], sizes: [] },
      { minViewPort: [750,0], sizes: [[728, 90]] },
      { minViewPort: [1200,0], sizes: [[728, 90], [728, 450]] }
    }},
    bids :[{
        bidder: 'bidderA',
        params: {...}
    }, {
        bidder: 'bidderB',
        params: {...}
    }, {
        bidder: 'bidderC',
        params: {...}
    }]
}, {
    code: 'left-square',
    mediaTypes: { banner: { sizes: [[300, 250], [300, 600]] } }
    bids :[{
        bidder: 'bidderA', // only bids if 750 <= screen < 1200 
        params: {...},
        sizeConfig: [{ minViewPort: [0,0], sizes: [] },
                     { minViewPort: [750,0], sizes: [[300, 250]] },
                     { minViewPort: [1200,0], sizes: [] }]
    }, {
        bidder: 'bidderC',
        params: {...}
    }]
}, {
    code: 'footer-ad',  // no sizeConfig action
    mediaTypes: { banner: { sizes: [[728, 90], [970, 90], [300, 250], [250, 250]] } }
    bids :[{
        bidder: 'bidderA',
        params: {...}
    }, {
        bidder: 'bidderB',
        params: {...}
    }]
}]

@jsnellbaker
Copy link
Collaborator Author

Thanks for the feedback and consideration. I do understand your points against the original proposal in its attempts 'to stay the same and be different'.

The suggested alternative has merit, though I need to digest it a bit more.

A few initial questions:

  • the property minViewPort, would it be easier setup-wise to also include a maxViewPort for that tier? it would save the need to declare an empty config in order to capture a set of dimensions in the middle.
  • with the reference to maintaining backward compatibility, there was a goal to have this new logic be part of 3.0 to introduce any potential breaking changes. Would we still want to support the old approach in some capacity to allow people to adjust to this new setup even in 3.0?
    • If so:
      • if there is a scenario where we detect that both sets of logic were (for some reason) active -> should we implement a bias towards the new format; ie ignore the old setup entirely if the new format was detected.
      • I assume we would have to wait to 4.0 to fully deprecate the old approach?
  • could you confirm if this is how the label field would be expected to work in the new proposal?
    • workflow below:
      • the pub would assign their desired labels (using either labelAny or labelAll only at the adUnit level to indicate when that adUnit should participate
      • the pub would then to have to pass the 'active' or 'qualifying' label(s) for that page inside the requestBids function
      • if the adUnit labels match the labels passed into the auction, then the adUnit stays in the auction - otherwise it's removed.
    • are there other likely scenarios we'd want to aim to support?
  • if we add video as a supported mediaType for the sizeConfig feature, do you see any complications with extending the current logic in how Prebid handles multi-format requests? Or would a new set of logic be needed here?
    • in my mind of extending the logic, when a banner, video, and native request is made - the following would happen:
      • the banner part of the request would undergo filtering on the sizes as described above
      • the video part of the request would also undergo filtering on the playerSize field
      • the native part of the request would be automatically included in the end request, as native is not covered by the sizeConfig feature
      • if there was a label setup on the adUnit and it failed the logic check, then the entire adUnit (including the native) would be removed from the auction

@bretg
Copy link
Collaborator

bretg commented Sep 16, 2019

  • I'm fine with maxViewPort
  • I don't think we should make conversion any harder than needed. My (unproven) assumption is that sizeconfig works as-is for many pubs. There have been only a few more complex use cases that have requested a more sophisticated design. I don't see the need to make the silent majority change.
  • labels: I think you have the use case correct, but getting picky about the language, labelAny and labelAll are conditions, not assignments. The assignment of the label can happen either in pbjs.requestbids() or in sizeconfig -- no changes from 1.x.
  • video: I'm not solid on the use case here, but top-of-the-head suggestion would be to just allow the sizeConfig to define playerSize
    var adUnit1 = {
        code: 'videoAdUnit',
        mediaTypes: {
            video: {
                context: 'instream',
                sizeConfig: [{ minViewPort: [0,0], playerSize: [] },
                     { minViewPort: [700,500], playerSize: [[640,480]] },
                     { minViewPort: [1300,750], playerSize: [[640,480],[1280,720]] }]
            }

@harpere
Copy link
Collaborator

harpere commented Sep 19, 2019

Agree with what's been said:

  • also ok with maxViewPort, but think we should make it optional.
  • labels: like bret said, your use case makes sense to me. I think the proposal is to leave the current functionality as is, including the sizeConfigs with mediaQueries and labels, in case people are using it, and just add the new "minViewPort" (and maxViewPort) sizeConfig feature in addition to it.
  • video: yep, think it should work the same way, as you both described

@jsnellbaker
Copy link
Collaborator Author

Hi @bretg @harpere

Just to confirm, I understand the desire to not impact existing users too much by proposing that we keep the existing function intact while adding this new logic. But how long would we plan to maintain the 'current' logic? Are we eventually going to deprecate the setConfig approach?

I wanted to explicitly clarify this point, since the feedback so far is that it appears to be staying for good. If so, why? The new logic appears to cover the use-cases of the current logic; there doesn't appear to be anything uniquely done by the 'current' approach that won't be possible with the new approach.

Maintaining both approaches makes sense if we're going to eventually deprecate the one (as we can setup the proper logic in the code and present the proper message in documentation). But if they're both going to stay, what would be the reason publishers want to use the 'current' logic over the 'new' logic?

@bretg
Copy link
Collaborator

bretg commented Sep 20, 2019

Are we eventually going to deprecate the setConfig approach?

It's a good question, but one I don't think we have enough data on. It's not clear to me what proportion of publishers are happily using the current approach vs those struggling with complex use cases. I propose we leave the global setConfig approach until we get feedback from pubs. I've set up a meeting with the 3 pubs that are Prebid.org members.

@GLStephen
Copy link
Collaborator

@bretg I spoke to three people here who work with our config builder and our publishers to manage their configs. The consensus was the more explicit, purpose built, number two option would be preferred. Making it similar to that other ad server is good from the standpoint of applying an understandable config in a complex site.

However, there was explicit feedback that:

  1. The same config should be applied at the bidder level. This would likely necessitate creating some sort of external config list, then adding them by reference at each level. Would this be better as a prebid data structure? It could of course always be handled in the javascript config.
  2. Duplication of adunits should not be removed, this escape valve is very useful and paired with labels that deactivate one vs another will likely provide emergent capabilities we don't foresee

@bretg
Copy link
Collaborator

bretg commented Sep 25, 2019

Thanks for the thoughtful response @GLStephen .

  1. We did allow for sizeConfig to be at the bidder level. See the 'left-square' example -- bids[].sizeConfig is a thing. However, maybe you're worried about duplication -- like having 10 adunits on the page, with every instance of bidderA replicating the same sizeConfig? So you'd be looking for some kind of 'macro'? If so, one approach would be something really generic like:
pbjs.setConfig({
   macros: {
      sizeConfigForBidderA: [{ minViewPort: [0,0], sizes: [] },
                     { minViewPort: [750,0], sizes: [[300, 250]] },
                     { minViewPort: [1200,0], sizes: [] }]
   }
});

Then maybe we could extend AdUnit processing resolve macros. e.g.

}, {
    code: 'left-square',
    mediaTypes: { banner: { sizes: [[300, 250], [300, 600]] } }
    bids :[{
        bidder: 'bidderA',
        params: {...},
        sizeConfig: $sizeConfigForBidderA$
    }, {
        bidder: 'bidderC',
        params: {...}
    }]
}, {

And to limit the performance impact, the scanning for macros is only turned on by the existence of any defined macros. Overall macros seem like a pretty high-end feature -- do you have any simpler ideas in mind?

  1. By this I assume mean that the feature where PBJS merges multiple adunits with the same code.

@benjaminclot
Copy link
Contributor

benjaminclot commented Sep 26, 2019

@bretg's proposal has my preference overall. A few remarks:

  • I do prefer minViewport over maxViewport, mainly because the 'well-known ad server' uses this and it allows for a faster check of rules if they're written the same way
  • I want to still have the possibility to have duplicate ad units (same codes), as sometimes it's easier to read, and also allows easily readable grouping of configs, like 'these are the rules and bidder IDs for desktop' and 'these are the rules and bidder IDs for mobile'
  • I still want to be able to exclude an ad unit based on the viewport, whatever formats it contains (banner, native, video, etc.); e.g. as of today we have to mix banner and native formats in the same adunit (or via a duplicated one) because some bidders use 'true' native and others don't -- but I still wan't to be able to say 'below this size, don't display either'.

@bretg
Copy link
Collaborator

bretg commented Sep 26, 2019

Thanks @benjaminclot - I think we got you covered.

  1. we prefer minViewPort for the same reason.
  2. consider duplicate adunits a thing
  3. excluding the adunit based on size was part of the 'leaderboard' example. Here, the adunit is only relevant 750px and up:
    code: 'leaderboard', // adunit has diff sizes for >750 and >1200
    mediaTypes: { banner: { sizeConfig:
      { minViewPort: [0,0], sizes: [] },
      { minViewPort: [750,0], sizes: [[728, 90]] },
      { minViewPort: [1200,0], sizes: [[728, 90], [728, 450]] }
    }},

The remaining 2 questions:

  • whether we need the 'macro' idea suggested (indirectly) by @GLStephen - I would propose that we save that feature for later phases.
  • who's actually going to build this. It was clearly on @jsnellbaker 's queue, but then we bulldozed his plans, so wouldn't blame him for pushing it back to us. Rubicon may be able to cover it 2nd part of Q4.

@jsnellbaker
Copy link
Collaborator Author

I am still willing to make the changes for sizeMapping. I'm trying to consolidate the feedback provided here (thanks all for the varied perspectives, please keep it coming) to iron out what should be included and key scenarios to verify.

My rough plans are to start working on the proposed changes in the next week or so.

@benjaminclot
Copy link
Contributor

@bretg I may not have been clear with (3): I still want to be able to disable an adunit whatever its mediatype is, not only if it's a banner. Having a sizeconfig per mediatype is nice, but there should also be the possibility to define one for the adunit itself.

@jsnellbaker
Copy link
Collaborator Author

@bretg

In looking overall at the collected feedback, there are points about the scope of feature in how it interacts with an adUnit and its mediaType(s) that need to be clarified.

Imagine if you had the following type of adUnit using the new logic:

var adUnit = [{
  code: 'banner-video-native-test',
  mediaTypes: {
    banner: {
      sizeConfig: [
        { minViewPort: [0,0], sizes: [] },
        { minViewPort: [500,0], sizes: [[300, 250]] },
        { minViewPort: [750,0], sizes: [[300, 250], [300, 600]] }
      ]
    },
    video: {
      sizeConfig: [
        { minViewPort: [0, 0], playerSize: [] },
        { minViewPort: [750, 0], playerSize: [300, 250] }
      ]
    },
    native: {
      // normal native params here
    }
  },
  bids: [{
    bidder: 'A',
    params: { ... },
    sizeConfig: [
      { minViewPort: [0,0], sizes: [] },
      { minViewPort: [500,0], sizes: [[300, 250]] },
      { minViewPort: [750,0], sizes: [[300, 250], [300, 600]] }
    ]
  }, {
    bidder: 'B'
    params: { ... }
  }]
}]

How should the different mediaTypes work together (or work separately) when one qualifies and the other doesn't (especially around native)? How can a bidder decide which mediaType they want to participate and filter?

For instance:

  1. In the [500, 0] range, you have a banner size available, but no valid video sizes. This would assume the video part of the adUnit is excluded, and the banner part go through. But where does native fit in this logic? Should it be automatically included because it's not size-relevant? Should there be some field to designate which screen-sizes should include/exclude the native part of the request?
  2. The current api for bidder focuses on the banner sizes. If bidder A wanted to limit certain playerSizes how would they do so? Should we replicate the mediaType middle-layer (ie banner, video, etc) into the bidder config so they control which sizes/types they want to participate?

As a potential suggestion to 1, perhaps we could setup a sizeConfig object for native and use the size [1,1] in the different size objects to signify when that native mediaType should be included/excluded for that adUnit? Though a bit involved setup-wise, setting up the logic in all the mediaTypes would allow the publisher to shut-off the adUnit once it reaches screen-sizes.

Tangent Thought
As another alternative (something along the lines of what @benjaminclot was mentioning), I was wondering if we could invert the structure a bit to have a single sizeConfig object per each adUnit that groups the mediaTypes/sizes under different size tiers/groups.

The main idea here would be to put a focus on the size tiers organizing and driving the logic. If you for example create a tier that had no mediaTypes/sizes defined, that adUnit would not show at all. Alternatively - if you include only the banner/native mediaTypes for a small-sized tier and all 3 mediaTyps for larger tiers, then it know to include/exclude those types as needed.

What are your thoughts about this type of structure? It may clash a bit more with the existing mediaTypes object, but it could consolidate the relevant information and could easily show what's going to happen when to one/more mediaTypes.

@harpere
Copy link
Collaborator

harpere commented Oct 2, 2019

@jsnellbaker could you provide an example of what you're thinking in the Tangent Thought section?

@bretg
Copy link
Collaborator

bretg commented Oct 2, 2019

Agree with Eric that an example counter-counter proposal would be helpful.

Let me see if I understand the scenario:

  1. at small screen sizes, some media types and bidders are relevant
  2. at medium screen sizes, different media types and bidders are relevant
  3. at large screen sizes, still different media types and bidders are relevant

Honestly, I'm not qualified to talk about Native use cases in particular, but will just generalize and assume that every mediatype and every edge case are precious.

Back to basics, there are really two completely separate configurations we're talking about here:

  1. for each mediatype, define which ad/player sizes are relevant for this adunit given the screen size. These sizes are important because they're passed to the bidder adapters and set the scope for what sizes are accepted in bid responses.
    1a) if there aren't any ad/player sizes relevant for a given screen size and mediatype, then that mediatype is removed from consideration
    1b) if there aren't any media types left in an adunit, no auction should occur
  2. which bidders are relevant for a given screen size and mediatype. We do not necessarily need to support defining custom mediatype-sizes for each bidder -- boolean relevance is sufficient. i.e. if the adunit defines a list of sizes, the bidder will get that list in any auctions its included in

I think #1 is covered by what we've defined already. One way to achieve #2 (and eliminate the confusion over bidder-specific sizes) would be to have an explicit relevantMediaTypes setting. e.g.

  bids: [{
    bidder: 'A',
    params: { ... },
    sizeConfig: [
      { minViewPort: [0,0], relevantMediaTypes: ["none"] }, // turns off this bidder
      { minViewPort: [500,0], relevantMediaTypes: ["banner", "native"] }, // only banner or native
      { minViewPort: [750,0], relevantMediaTypes: ["banner", "video", "native"]} // any type
    ]
  }

@benjaminclot
Copy link
Contributor

Based on the latest blog post, are we to understand that this feature (sadly) won't make it to 3.0?

@jsnellbaker
Copy link
Collaborator Author

@benjaminclot It's been scoped out of 3.0 as the new design being discussed wouldn't be considered a breaking change. It will instead be part of a regular release as a new feature. It should be coming sooner rather than later, so I hope that helps.

@bretg @harpere
I haven't yet had the chance to review/respond due to something else coming up. I'll try to follow-up soon so we can keep this moving.

@jsnellbaker
Copy link
Collaborator Author

jsnellbaker commented Oct 10, 2019

@bretg @harpere
Thanks for the feedback on the multi-media type question. I think the idea you proposed for the bidder level config should work out. If there's a use-case later on for specific sizes, we can review it then and may make some additional updates down-the-road.

I still think we should have some flag for the native field to allow some control how that's handled. If we're continuing with the existing logic - the native part of the request would always be included unless the label check failed. Given the requests made earlier in the thread to be able to shut-off the adUnit under certain screen-sizes, I'm not sure the existing logic would be something to easily work with here.

In regards to the other thought I mentioned, I was thinking something along the lines of this:

mediaTypes: { 
  sizeConfig:[
    {
      minViewPort: [0,0]
    },	
    { 
      minViewPort: [500,0],
      banner: { sizes: [[300, 250]] },
      native: { // something here? }	// or perhaps a `native: true` boolean flag instead of an obj?
    },
    { 
      minViewPort: [1200,0],
      banner: { sizes: [[300, 250], [300, 600]],
      video: { playerSize: [300, 250],
      native: ...
    }
  ]
},

The main idea was to group the mediaTypes that should be active within a specific tier; their inclusion into the tier would set the logic for when that mediaType should/shouldn't be used.

Working with the example:

  • in the first tier, no mediaTypes are listed - adUnit doesn't show at all
  • in the second tier, we see the banner+native fields so they get included; video is missing, so it's blocked outright. Note - If the banner failed the size filtering, then native would still proceed into the auction.
  • in the third tier, all three types are included. The banner + video types would be filtered against the listed sizes and playerSize fields; native is (again) automatically included.

@bretg
Copy link
Collaborator

bretg commented Oct 22, 2019

I don't understand why we'd want to make size primary over mediatype. The sense I got from this rather long thread is that we shouldn't be making any assumptions that pubs line up screen size behavior in a clean way. If they did, then the current global approach should work just fine. i.e. it's not necessarily the case that banner/video/native treatments all fall on the same neat screen size boundaries. Instead, maybe they want banner sizes to differ in the ranges 0-621px / 622-864px / 865+px while the video playerSize range is 0-703px / 704+px

For that reason, I pretty strongly prefer mediaTypes.TYPE.sizeConfig rather than mediaTypes.sizeConfig.TYPE

be able to shut-off the adUnit under certain screen-sizes

I don't see that as a problem in the mediaTypes.TYPE.sizeConfig model - if there aren't any active mediaTypes, the AdUnit can be dropped.

we should have some flag for the native field to allow some control how that's handled

Again, I don't understand what controls native needs. If it's just a boolean, then a simple active flag would work:

native: {
      sizeConfig: [
        { minViewPort: [0, 0], active: false },
        { minViewPort: [750, 0], active: true }
      ]
    },

Else, if different components of native need to vary, then it's a little more complicated, but maybe something like this would work:

native: {
      sizeConfig: [
        { minViewPort: [0, 0], image: { sizes: [[150,50]] }, icon: { sizes: [[30,30]] }},
        { minViewPort: [750, 0], image: { sizes: [[200,50]] }, icon: { sizes: [[50,50]] }},
      ]
    },

(note: the Prebid.org native doc shows sizes as a single array rather than an array of arrays. That sounds like a mistake?)

So putting it all together in a single example:

adUnits: [{
    code: 'banner-and-outstream',     // adunit only present for >= 750px
    mediaTypes: {
      banner: {
        sizeConfig: [
            { minViewPort: [0,0], sizes: [] },    // remove if < 750px
            { minViewPort: [750,0], sizes: [[300, 250], [300, 600]] }
         ]
      },
      video: { 
         context: 'outstream',
         sizeConfig: [
             { minViewPort: [0,0], playerSize: [] },    // no video if < 800px
             { minViewPort: [800,0], playerSize: [640,480] },
         ],
         renderer: { ... }
      }
    },
    bids :[{
        bidder: 'bidderD',
        params: {...}
    }]
}, {
    code: 'instream1', // adunit only present for > 800px
    mediaTypes: {
       video: { 
         context: 'instream',
         sizeConfig: [
             { minViewPort: [0,0], playerSize: [] },    // no video if < 800px
             { minViewPort: [800,0], playerSize: [640,480] },
         ],
         mimes: ['video/mp4'],
         ... other video params ...
      }
    bids :[{
        bidder: 'bidderD',
        params: {...}
    }]
}, {
    code: 'banner-native',
    mediaTypes: { 
      banner: { 
          sizeConfig: [
               { minViewPort: [0,0], sizes: [] },
               { minViewPort: [750,0], sizes: [[728, 90]] },
               { minViewPort: [1200,0], sizes: [[728, 90], [728, 450]] }
          ]
      },
     native: {   // no native under 600
         sizeConfig: [
            { minViewPort: [0,0], active: false },
            { minViewPort: [600,0], active: true }
         ],
         image: { sizes: [[150,50]] },
         ... other native params ...
     }
   },
    bids :[{
        bidder: 'bidderA', // only bids on banner if screen >= 850 
        params: {...},
        sizeConfig: [
                     { minViewPort: [0,0], relevantMediaTypes: ["none"] },
                     { minViewPort: [850,0],relevantMediaTypes: ["banner"] }
        ]
    }, {
        bidder: 'bidderB',  // only bids on native between 850 and 1200px
        params: {...},
        sizeConfig: [
                     { minViewPort: [0,0], relevantMediaTypes: ["none"] },
                     { minViewPort: [850,0], relevantMediaTypes: ["native"] },
                     { minViewPort: [1200,0], relevantMediaTypes: ["none"] }
        ]
    }]
}]

@benjaminclot
Copy link
Contributor

I'm good with @bretg's suggestions.

@jsnellbaker
Copy link
Collaborator Author

Thanks @bretg for the feedback and putting together the updated example. I agree with your points and we'll start to work on the changes going with this model.

@Fawke Fawke mentioned this issue Dec 2, 2019
@Fawke Fawke mentioned this issue Jan 4, 2020
1 task
@bretg
Copy link
Collaborator

bretg commented Nov 25, 2020

Closing -- this was the issue for the 'Advanced Size Mapping' module.

@bretg bretg closed this as completed Nov 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants