-
Notifications
You must be signed in to change notification settings - Fork 4k
Description
Summary
We intend to move story ads from an algoritm that simply counts pages to an algorithm that will determine the number of ads per story (weighted by story length) and their positioning upon initialization.
Design document
Background
Story ads are managed by the extension. This extension is responsible for fetching the ad from the publisher specified ad server, preloading the ad , and placing the ad into the story.
The current placement algorithm counts unique pages viewed, after 7 pages have been seen it will place the ad as the next page in the story as long as the ad has been preloaded, and it is not the last page in the story.
This logic has a few main drawbacks in that it is impossible for short stories to be monetized, and a user that sees < 8 pages is guaranteed to never see an ad.
Goals
- Expand eligibility of monetizable Stories to Stories with >= 4 pages
- Minimize story ads impact on user experience (e.g. bounces)
- Maximize the # pages between Stories subject to a target ad density
- Ensure ads do not show too early in the story
- Respect the next-page-no-ad signal given by pubs
- There should not be a high ads to story pages ratio
- Ensure UX in viewer sessions with multiple Stories
- Maintain predictability of ad impressions at scale for publishers / advertisers
- Make it easy to increase/decrease ad density with minimal code changes
- Be able to test algorithm changes experimentally
Non-Goals
- Monetization of less than 4 page stories
Options considered
- Platform controlled counter
- We could maintain logic very similar to the current implementation, by moving the page counting logic to the viewer/player and showing ad after X pages seen within a viewer session (across multiple stories)
- [+] Algorithm is easy to reason about
- [-] Needs runtime ⇔ viewer communication
- [-] All viewers will need to implement logic
- [CHOSEN] Probabilistic approach
- Using a statistical model we can guarantee that a population will see an add every X number of pages
- [+] Can be completely stateless
- [+] Can be implemented purely AMP side
- [-] Looking at one user, the journey may not be ideal
- Last page
- We could always insert the ad as the last page in the story regardless of story length. Also we could hijack the swipe to always show the ad, regardless of context.
- [+] From user perspective feels similar to existing experiences
- [-] Incentivizes pubs to make content to swipe
- [-] Unclear how to pay people in a viewer context without revenue share
- [-] CTRs will be impacted
Algorithm detail
All the algorithms contain a coefficent ($DENSITY) which is designed to be easily changed such that we can quickly tweak this setting in order to increase/decrease ad load.
To try to optimize our algorithm before launching the changes against users we ran the following against historical user journey logs.
Existing algorithm
The existing algorithm simply tries to insert an ad every $DENSITY pages.
Random Number algo
This algorithm will "roll a die" to determine where an ad should be placed based when a user visits a story and places the ad. After the user sees $DENSITY pages we will repeat the process.
// first ad
ad_position = random_int(1, $DENSITY)
// roll again after $DENSITY pages
ad_position = random_int(1, $DENSITY) + $DENSITY(number_of_rolls)While this algorithm does a good job of increasing monetization of shorter stories and maintaining our overall $DENSITY value, there were some concerns about the large number of users that will see ads without many content pages in between.
Predetermined Placement algo
This algorithm will determine the number of ads to show when a user starts a story, and then try to evenly distribute the number of chosen ads in the story. When placing the ads it will never show an ad in the first 2 pages, nor the last 2 pages.
// choose # of ads
// one ad for every $DENSITY pages, and a chance for extra ad.
full_segments = Math.floor(page_count / $DENSITY);
remainder_pages = page_count % $DENSITY
// if $DENSITY == 7 there is a remainder_pages / 7 chance of extra ad.
// In shorter stories this means there is a page_count / 7 chance of any ad showing.
extra_ad = random.random() < (remainder_pages / $DENSITY) ? 1 : 0
num_ads_to_show = full_segments + extra_ad
// determine position of ads
available_slots = [3 … num_pages - 2]
ad_positions = evenly_distribute(num_pages, num_ads, available_slots)We were pretty happy with the general direction of this algorithm. The following iterations were tweaks of this logic to get a bit closer to our ideal distributions.
Predetermined Placement (variant 1)
This is the same as the original predetermined placement algo but when placing an ad will not allow an ad on the first three pages, and wil allow the ad to be shown on the second to last page.
available_slots = [4 … num_pages - 1][Chosen as starting experiment] Predetermined Placement (variant 2)
This is the same as the original predetermined placement algo but adjusts the $DENSITY number to be 8 instead of 7, and limits the maximum number of ads per story to 4.
This algorithm gave us a desirable mix of overall ad density, ad positions viewed, and spacing of ads.
Next Steps
We still need to test how this will affect live traffic. We will start an experiment to monitor ad performance metrics, and things like story completion rate to determine tradeoffs.