Understanding Bumpers, Ad Break Fill, and Fill-Rate Metrics in AWS Elemental MediaTailor
MediaTailor fills an ad break with bumpers, ads, and slate. This guide covers how they fit together in one break: how much time bumpers leave for ads, what plays when ads don't fill the break, when the personalization threshold drops the break back to regular content, and which avail metric tells you what actually aired. It's a quick reference for anyone running SSAI who needs to size ad breaks or figure out why fill looks off.
AWS Elemental MediaTailor fills an ad break with three kinds of content: bumpers, personalized ads, and slate. Each is documented on its own page, but the way they interact inside a single ad break - how much time is left for ads after bumpers, what happens when ads do not fill the break, and which CloudWatch metric tells you what actually played - is not consolidated anywhere. That gap leads to recurring confusion: teams over- or under-estimate how many ads a break will hold, and they pick the wrong fill-rate metric when measuring results.
This guide is written for two audiences:
- If you are new to ad breaks, Part 1 explains how a break is filled from scratch.
- If you are measuring or troubleshooting fill, Parts 3 and 4 are the field notes: what the metrics actually mean and how to read them.
Every behavioral claim below is grounded in AWS documentation, linked in the References section at the end.
Part 1 - How an ad break gets filled
An ad break (an "avail") has a duration that MediaTailor reads from the origin manifest - from the #EXT-X-CUE-OUT:DURATION / #EXT-X-DATERANGE tags in HLS, or from the Event duration / scte35:BreakDuration / segmentation duration in DASH.
Inside that fixed window, MediaTailor places content in this priority order:
- Start bumper (optional) - a short, non-skippable clip at the start of the break.
- Personalized ads - as many as fit, returned by your ad decision server (ADS).
- End bumper (optional) - a short, non-skippable clip directly before the break ends.
- Slate - a default MP4 that fills any time still unfilled after bumpers and ads.
Bumpers are 10 seconds or less, can be placed at the start, before the end, or both, are transcoded to match your content, and are not billed. Slate is the filler of last resort - if ads plus bumpers do not fill the avail, MediaTailor inserts slate; if no slate is configured, it shows the underlying content. A related setting, the personalization threshold (personalizationThresholdSeconds), caps how much underfilled ad time a break may contain in ad-replacement workflows; if the unfilled portion exceeds the threshold, MediaTailor abandons personalization for that break and shows the underlying content instead of inserting ads, bumpers, and slate.
Figure 1 - A 120-second ad break filled as start bumper, ads, end bumper, and slate. Bumpers consume time within the break (they are not billed), slate fills any time ads do not, and each CloudWatch avail metric maps to the span it measures.
Part 2 - Bumpers consume the break; they do not extend it
The single most common question: if I have a 120-second break and 5-second start and end bumpers, does MediaTailor ask the ADS for 120 seconds or 110 seconds?
Bumpers occupy time inside the break - they do not lengthen it. The AWS bumpers documentation shows this directly: in its worked example, a 70-second break with a 10-second start bumper and a 10-second end bumper leaves 50 seconds for ads (10 + 50 + 10 = 70).
Applying that to the 120-second example: with 5-second start and end bumpers, 110 seconds of the break is available to be filled with ads, and the break still ends at 120 seconds. The bumpers do not push the schedule out to 130 seconds.
The practical consequence: the time available for ads = break duration minus total bumper duration. Size your expectations (and your ADS pod request) around the post-bumper figure, not the raw SCTE-35 duration.
Note: this guide describes the time budget inside the break. The exact duration value MediaTailor sends in the ADS request (the
[session.avail_duration_ms]variable) and any per-format nuances are governed by the session variables documentation; validate the value your own configuration sends by inspecting the outgoing ADS request URL.
What is configurable, and what is not
Bumpers are designed to play before and after the ads, with slate as the filler when ads plus bumpers do not fill the avail. When an ad break is longer than the available ad content, the resulting order is:
start bumper -> ads -> end bumper -> slate (remaining unfilled time)
MediaTailor does not currently expose a configuration option to reorder this - for example, to place slate before the end bumper so the end bumper becomes the transition back into content. If your workflow requires a different order, treat it as a feature request rather than a setting to find.
Because the end bumper is reserved within the break, it takes precedence over filling every last second with ads: if ads plus bumpers would exceed the avail, the overflow ad is the part that does not get inserted, not the bumper. Confirm what actually played for any given break using the observed metrics in Part 3.
Part 3 - Reading fill: planned vs observed (and which metric to trust)
MediaTailor publishes two families of avail metrics, and mixing them up is the root of most "the numbers do not match" confusion. The distinction is planned (computed when ads are requested) versus observed (measured at the end of the break from the segments actually in the manifest). All definitions below are from the CloudWatch metrics reference.
| Metric | Family | What it measures |
|---|---|---|
Avail.Duration | Planned | Total planned ad-avail time, from the avail durations in the origin manifest |
Avail.FilledDuration | Planned | Ad-avail time MediaTailor plans to fill with ads |
Avail.FillRate | Planned | Planned simple-average fill rate across avails |
Avail.ObservedDuration | Observed | Total avail time that actually occurred, emitted at the end of the avail, based on the segment durations in the manifest |
Avail.ObservedFilledDuration | Observed | Avail time MediaTailor actually filled with ads |
Avail.ObservedFillRate | Observed | Observed simple-average fill rate; HLS only, emitted at the first CUE-IN. No CUE-IN, no metric |
Avail.ObservedSlateDuration | Observed | Slate time actually inserted |
AdDecisionServer.FillRate | ADS | How much of the avail the ADS response covered |
Three rules that resolve most questions:
- "How much did I plan to fill?" ->
Avail.FillRate/Avail.FilledDuration. - "How much actually landed in the served manifest?" -> the
Observed*metrics. To check whether the ad time you planned to insert was actually served, compareAvail.FilledDuration(planned) againstAvail.ObservedFilledDuration(observed). A shortfall in the observed value indicates planned ad time that did not make it into the served manifest; use theSkippedReason.*metrics to attribute why, and checkAvail.ObservedDurationagainstAvail.Durationto rule out the avail simply being shorter than planned. - "Why is my fill rate capped?" ->
Avail.FillRatecan never exceedAdDecisionServer.FillRate. If avail fill is low, check the ADS fill rate first - a low ADS fill rate means your ad server is not returning enough ad time for the avail durations.
Slate is measured separately by Avail.ObservedSlateDuration, so unfilled time that fell back to slate shows up there rather than in the filled-duration metrics. If whole breaks unexpectedly revert to the underlying content instead of showing ads or slate, check SkippedReason.PersonalizationThresholdExceeded - the underfilled ad time exceeded the configured personalization threshold.
HLS Interstitials (SGAI) caveat: for HLS Interstitials sessions,
Avail.ObservedFilledDurationequalsAvail.FilledDurationbecause MediaTailor cannot observe client-side playback, and "Observed" metrics are estimates. Keep this in mind if you run guided sessions.
Simple vs weighted fill rate
Avail.FillRate and AdDecisionServer.FillRate are simple averages - the mean of each avail's fill percentage, ignoring how long each avail was. For a weighted view that accounts for avail length, compute Avail.FilledDuration * 100 / Avail.Duration (and AdDecisionServer.Duration * 100 / Avail.Duration for the ADS). With a mix of long and short breaks, the weighted number is the more honest one.
Worked example (the Figure 1 scenario)
A 120-second break with 5-second start and end bumpers, where the ADS returns 90 seconds of ads:
Avail.Duration= 120 s - the whole break.- Bumpers consume 10 s, leaving 110 s available for ads.
Avail.FilledDuration/Avail.ObservedFilledDuration= ~90 s - the ads actually placed.Avail.ObservedSlateDuration= 20 s - the remainder, because 90 s of ads is less than the 110 s available, so slate fills the gap.
This maps directly to Figure 1. A fill-rate percentage is intentionally omitted: how MediaTailor accounts for bumper time in the Avail.FillRate denominator is not documented, so confirm any percentage against your own CloudWatch data.
Part 4 - "Fill rate" is not the same as your ad server's number
A frequent point of confusion: a customer sees a healthy Avail.FillRate in MediaTailor but a lower fill or impression number in their ad server's reporting, and assumes something is broken.
These measure different things:
- MediaTailor's
Avail.FillRatemeasures how much of the ad-avail time was filled with ad content in the stream MediaTailor produced. - An ad server's reported fill is based on how many ad requests it answered with an ad, which is a different denominator. For live streaming especially, the ad server's own count is not a reliable proxy for what played.
Where prefetch fits. Ad prefetch lets MediaTailor retrieve and pre-transcode ads ahead of the break. That protects the ADS from large request spikes (which otherwise cause timeouts and lower served fill) and ensures ads are transcoded and ready in time. The trade-off is in reporting: because prefetched ad requests can be made ahead of the actual viewer, some ad servers attribute those requests differently, which can depress the ad-server-side number even though the in-stream fill is strong.
The optimization when ad-server-side reporting matters: prefer single (time-window) prefetch scheduled close to the ad break over retrieving ads far in advance, so the ADS call lands near real viewing time.
Part 5 - Monitoring cheat-sheet
A practical CloudWatch starting point for any SSAI workflow with bumpers and slate:
- [ ] Alarm on a sustained drop in
Avail.FillRate(planned fill falling). - [ ] Compare
Avail.FilledDuration(planned) againstAvail.ObservedFilledDuration(served) - a persistent gap means ads are planned but not landing in the manifest. - [ ] Track
Avail.ObservedSlateDuration- rising slate time means breaks are not being filled with ads. - [ ] When
Avail.FillRateis low, checkAdDecisionServer.FillRatefirst; it is the ceiling. A low ADS fill rate points back to the ad server, not MediaTailor. - [ ] Watch the
SkippedReason.*metrics (for exampleDurationExceeded,NewCreative,TranscodeInProgress,NoVariantMatch) to attribute why ads were skipped. - [ ] Size ad expectations on break duration minus total bumper duration, not the raw SCTE-35 duration.
- [ ] If you run HLS Interstitials (SGAI) sessions, remember the
Observed*metrics are estimates there, not true client-side measurements.
References
- Bumper ad insertion - https://docs.aws.amazon.com/mediatailor/latest/ug/bumpers.html
- Slate ad insertion - https://docs.aws.amazon.com/mediatailor/latest/ug/slate-management.html
- DASH ad avail duration - https://docs.aws.amazon.com/mediatailor/latest/ug/dash-ad-avail-duration.html
- CloudWatch metrics reference (avail and fill-rate metric definitions) - https://docs.aws.amazon.com/mediatailor/latest/ug/monitoring-cloudwatch-metrics.html
- Ad skipping monitoring and alerts - https://docs.aws.amazon.com/mediatailor/latest/ug/monitoring-ad-skipping-issues.html
- Session variables for ADS requests - https://docs.aws.amazon.com/mediatailor/latest/ug/variables-session.html
- Ad prefetch (CreatePrefetchSchedule) - https://docs.aws.amazon.com/mediatailor/latest/ug/prefetching-ads.html
- Language
- English
Relevant content
asked 2 years ago
