AWS Elemental MediaTailor: Minimizing Data Transfer Out by Compressing Manifests and Tracking Responses
Learn how to ensure AWS Elemental MediaTailor's built-in gzip compression is preserved end-to-end when a CDN sits in front, and reduce client-side tracking Data Transfer Out with pagination and polling best practices.
This article is part of a series on getting the most out of your AWS Elemental MediaTailor integration. If you are interested in other articles in this series, see articles on my profile page .
TL;DR
AWS Elemental MediaTailor will gzip‑compress the text responses it serves — personalized manifests (HLS
.m3u8, DASH .mpd) and client‑side ad‑tracking (GetTracking) JSON — but only when the request that reaches MediaTailor carries Accept-Encoding: gzip. In many real deployments a CDN sits in front of MediaTailor and doesn't forward that header on its origin fetch, so MediaTailor receives the request without it and returns the response uncompressed. Because these responses are highly repetitive text, preserving compression end‑to‑end can reduce their Data Transfer Out (DTO) by roughly 5–16×. Since there's no functional symptom either way, it's an easily missed efficiency — and a straightforward win once confirmed.This article explains how the compression negotiation works, why it is so often missed, how to check whether it is happening, and how to fix it — with a concrete CloudFront configuration and the general principle that applies to any CDN. It also covers two tracking‑specific levers —
GetTracking NextToken paging and polling frequency — that reduce tracking DTO independently of compression.Why this matters
Manifests and tracking payloads are requested very frequently and are very compressible:
- A live HLS/DASH player re‑requests the manifest every segment duration (often every 2–6 seconds), for the whole session, for every viewer.
- Client‑side tracking players poll the
GetTrackingendpoint on a similar cadence. - Both payloads are repetitive ASCII/JSON (segment URLs,
#EXTINFtags, ad‑beacon URLs), which gzip compresses extremely well.
MediaTailor compresses these responses automatically whenever the request negotiates it — so for most direct player integrations, compression already "just works" with no extra effort. The goal is to ensure that built‑in compression is preserved end‑to‑end, especially when a CDN sits in front.
Because the benefit scales with request volume, confirming compression is one of the highest‑leverage, lowest‑effort efficiencies available to a high‑traffic MediaTailor workload: it's a configuration‑only check, with no impact on playback. For high‑traffic deployments, this translates into a meaningful, ongoing reduction in Data Transfer Out costs — and because there's no functional symptom either way, it's worth verifying rather than assuming.
How MediaTailor decides to compress
MediaTailor performs standard HTTP content negotiation:
- The client (or, more often, the CDN fetching on the client's behalf) sends a request with
Accept-Encoding: gzip. - MediaTailor generates the manifest or tracking response, compresses it with gzip, and returns it with
Content-Encoding: gzip. - If the incoming request does not advertise
Accept-Encoding: gzip, MediaTailor returns the response uncompressed.
MediaTailor supports gzip only — it does not support Brotli (br). The request that reaches MediaTailor must advertiseAccept-Encoding: gzip. If it advertises onlybr, MediaTailor has no supported encoding to apply and returns the response uncompressed.
That third point is what everything hinges on. MediaTailor is doing exactly the right thing — it can only compress for clients that say they can decompress. The question is always: does the request that actually arrives at MediaTailor carry
Accept-Encoding: gzip?In a direct player‑to‑MediaTailor topology, modern players (browsers, smart‑TV apps) advertise gzip natively, so compression "just works". The case to check is when a CDN is the origin‑fetch client.
Visualizing the problem
Problem —
Accept-Encoding not forwarded, so the response comes back uncompressed:
Correct —
Accept-Encoding: gzip reaches MediaTailor, so the response is gzipped:
The only differences that matter are on the CDN → MediaTailor hop (the
Accept-Encoding header) and the MediaTailor → CDN response (~30 KB uncompressed vs ~2 KB gzipped). Sizes are illustrative — a full HLS media playlist of ~30 KB typically gzips to ~2 KB (~15×); a large tracking JSON response of ~450 KB compresses to ~65 KB (~7×).Why a CDN in front of MediaTailor can affect compression
When a CDN fronts MediaTailor, the CDN — not the end‑user device — is the entity making the request to MediaTailor. What the CDN forwards on that origin fetch is governed by CDN configuration, and some common defaults don't pass
Accept-Encoding through to the origin:CloudFront
MediaTailor's personalized manifest and tracking responses are per‑session and dynamic, so CloudFront should not cache them. That has a direct consequence for compression: "Compress objects automatically" is a caching feature — CloudFront only compresses responses it caches — so when caching is disabled it does not apply, and you cannot rely on CloudFront to compress these responses at the edge. The objective instead is to forward
Accept-Encoding through to MediaTailor so MediaTailor compresses at the origin.Whether a header reaches the origin is governed by the origin request policy, not the cache policy.
Recommended configuration for the
/v1/* behavior:- Cache policy:
Managed-CachingDisabled— these per‑session responses must not be cached. - Origin request policy: one that forwards all viewer headers to the origin — for example the managed
AllViewerpolicy. This passes the viewer'sAccept-Encoding: gzipthrough to MediaTailor, which then returns a gzip‑compressed response.
You cannot listAccept-Encodingexplicitly in an origin request policy. CloudFront treats it as a special header and rejects it with "The parameter Headers contains Accept-Encoding that is not allowed." The supported way to getAccept-Encodingto the origin is therefore to forward all viewer headers (e.g. theAllViewermanaged policy), rather than enumerating headers by name.
If the origin request policy forwards only a restricted header set and omits
Accept-Encoding, MediaTailor never sees it and returns the response uncompressed.A common pitfall — forcing Brotli (br)
Some CDNs try to minimize response size by changing the encoding they request from the origin. A frequent pattern: the viewer sends
Accept-Encoding: br, gzip, but the CDN forwards only Accept-Encoding: br to the origin in an attempt to force a Brotli response.Because MediaTailor supports gzip only and not Brotli, an origin fetch that offers only
br leaves MediaTailor with no usable encoding — so the response comes back uncompressed, the least desirable outcome.The fix is to ensure the origin fetch always offers gzip: forward the viewer's
Accept-Encoding through unchanged so gzip remains present, and don't let the CDN rewrite it to br‑only.Other CDNs / proxies
The principle is identical for any CDN: the origin fetch to MediaTailor must present
Accept-Encoding: gzip, and no intermediary (origin shield, proxy, SDK networking layer) may strip it. Watch for two common CDN behaviors — not forwarding Accept-Encoding to the origin by default (some require explicitly forwarding viewer headers / enabling origin compression), and dropping it at an origin‑shield hop. Configure the back‑end/origin request to forward Accept-Encoding (with gzip preserved) and verify that any shield tier keeps it.What "good" looks like — typical compression ratios
These payloads are text, so compression is dramatic — but it is size‑dependent, which matters when you estimate savings:
| Response type | Typical pre‑gzip size | Typical gzip ratio | Notes |
|---|---|---|---|
| HLS master playlist | ~0.5–3 KB | ~3–5× | Small; gzip overhead limits gains |
| HLS media playlist (small / short window) | ~1–3 KB | ~4–6× | Tiny manifests compress modestly |
| HLS media playlist (full sliding window) | ~25–40 KB | ~15–18× | Lots of near‑identical segment lines |
| DASH MPD | ~30–60 KB | ~10–14× | Repetitive XML |
Client‑side tracking (GetTracking) JSON | tens–hundreds of KB | ~6–8× | JSON, less repetitive than m3u8 |
Two practical implications:
- Small manifests still benefit, but modestly. A 1.5 KB manifest gzips to ~300–400 B (~4–5×). Worth doing fleet‑wide, but the per‑request absolute saving is small.
- Large manifests and tracking are where the big DTO lives. A 60 KB DASH manifest → ~5 KB, and a 450 KB tracking response → ~65 KB. Those are tens‑to‑hundreds of KB saved per request.
A useful heuristic: gzip needs enough repetitive bytes to "warm up" its dictionary, so compressibility rises with payload size up to a point. JSON tracking tops out lower than m3u8/MPD because it is less repetitive.
Don't forget the tracking endpoint
Compression is usually discussed in the context of manifests, but client‑side ad tracking (
GetTracking) responses are frequently the larger DTO contributor — they are large JSON documents polled throughout a session. Two things to check:- Is
GetTrackingcompressed? It obeys the sameAccept-Encodingrule as manifests. It is entirely possible to have manifests compressed but tracking uncompressed (or vice‑versa), if they travel different CDN paths or behaviors. Check them independently. - Beyond compression, reduce tracking volume itself:
NextTokenpaging.GetTrackingreturns aNextTokenyou can use to page through ad beacons. On a wide live manifest window the first response contains all beacons in the window, which can be large; paging withNextTokenlets the player request only the beacons it still needs, shrinking each response. See the AWS docs on paging through ad beacons with GetTracking .- Right‑size polling. AWS guidance is to poll every target duration (HLS) / minimum update period (DASH) for live, but for VOD / live‑to‑VOD you generally only need to call the tracking endpoint once after session init — all avails are known up front, so continuous polling adds DTO without adding value.
- Player‑SDK tracking controls. Player SDKs expose settings that map directly to these levers. For example, the Datazoom MediaTailor SDK's
adTrackingUpdateModecontrols howGetTrackingrequests are managed:pagination(the default) — sends a pagination token so the server avoids re‑sending tracking info it already returned, giving smaller incremental responses.playhead— sends the current playhead position so the server returns only the ads closest to the playhead (up to the two nearest avails) — the smallest responses for live. This mode requires AWS to enable the feature on the MediaTailor playback configuration (open an AWS Support case ).full— returns tracking info for all ads in the manifest window (the largest responses); best avoided for wide windows.
The same SDK also exposes defaultTrackingRequestInterval — widen the polling interval, or set it to a negative value to suspend periodic polling entirely (well suited to VOD once the avails are captured) — and an AD_TRACKING_INFO_RESPONSE event the app can use to stop polling once it has what it needs. Equivalent controls exist in other client implementations.
Compression and these tracking‑volume levers are complementary — apply both where appropriate.
How to check whether compression is applied
You can confirm this directly from the response — no internal tooling required.
Inspect a response served through your CDN. Request a manifest (or tracking) URL with
Accept-Encoding: gzip and look at the response headers and size:1
2
curl -s -H "Accept-Encoding: gzip" -o /dev/null -D - \
"https://<your-cdn-domain>/v1/.../manifest.m3u8"- A compressed response includes a
Content-Encoding: gzipheader, and the transferred size is much smaller than the raw body. - An uncompressed response has no
Content-Encodingheader, and the transferred size equals the full body.
Browser developer tools show the same thing in the Network tab: the
Content-Encoding response header, and the "transferred" vs "resource/decompressed" sizes — a large gap means compression is working; equal values mean it isn't.Confirm it end‑to‑end. Because the negotiation happens on the CDN→MediaTailor hop, the question is whether the viewer ultimately receives
Content-Encoding: gzip. If they do, compression is working through the whole path. If they don't, check that the CDN forwards Accept-Encoding to the origin (for CloudFront, the origin request policy described above). Your CDN's access logs can also show the edge response sizes if you want to quantify it at scale.Check manifests and tracking separately (
…m3u8 / .mpd, and the /v1/tracking URL) — they can travel different CDN paths or behaviors, so one can be compressed while the other isn't.A small amount of uncompressed traffic is normal: some clients (for example certain
AirPlay devices) don't send Accept-Encoding, so MediaTailor correctly returns those responses uncompressed. It's a high, broad proportion of uncompressed responses that's worth looking into.Uncompressed delivery may indicate a configuration opportunity, but isn't necessarily a misconfiguration — there may be a deliberate reason for it. Confirm before assuming.
Remediation checklist
- Confirm the current behavior: request a manifest/tracking URL through the CDN with
Accept-Encoding: gzipand check the response — a missingContent-Encoding: gzipheader (and full‑size body) means it's being delivered uncompressed. - Identify the delivery path — direct‑to‑MediaTailor, CloudFront, or another CDN — and whether it differs for manifests vs tracking.
- Enable origin compression negotiation:
- CloudFront: these per‑session responses should not be cached — on the
/v1/*behavior use theManaged-CachingDisabledcache policy and attach an origin request policy that forwards all viewer headers (e.g. the managedAllViewerpolicy) soAccept-Encodingreaches MediaTailor. Note you can't nameAccept-Encodingindividually in an origin request policy (CloudFront rejects it) — forward all viewer headers instead. "Compress objects automatically" is a caching feature and does not apply here. - Other CDNs: forward
Accept-Encodingto the origin withgzippreserved (some CDNs don't forward viewer headers by default, and origin‑shield tiers can strip it). Don't let it be rewritten tobr‑only — MediaTailor is gzip‑only and would then return uncompressed.
- CloudFront: these per‑session responses should not be cached — on the
- For tracking, additionally consider
NextTokenpaging and reduced polling (especially VOD). - Validate by re‑checking the response: the same request should now return
Content-Encoding: gzipwith a much smaller transferred size.
Key takeaways
- MediaTailor compresses manifests and tracking responses only when the origin fetch sends
Accept-Encoding: gzip— and a fronting CDN is the most common reason it doesn't. - MediaTailor is gzip‑only (no Brotli). Watch for CDNs that forward
Accept-Encoding: br‑only to "force" Brotli — that makes MediaTailor return uncompressed. Keepgzipin the header that reaches MediaTailor. - Treat manifests and tracking as separate checks; one can be compressed while the other isn't.
- Savings are size‑dependent: huge for full manifests and tracking JSON, modest for tiny manifests.
- For tracking,
NextTokenpaging and polling discipline (poll once for VOD) reduce DTO on top of compression. - It's a configuration change in your CDN or player — MediaTailor itself needs no change.
References
- Client-side ad tracking — AWS Elemental MediaTailor User Guide (incl. GetTracking / NextToken paging and live/VOD polling best practices)
- Datazoom MediaTailor SDK — SessionConfiguration.adTrackingUpdateMode
- Datazoom MediaTailor SDK — Session (stop updating tracking info)
- Datazoom MediaTailor SDK — SessionUiEvent.AD_TRACKING_INFO_RESPONSE
Compression ratios quoted here are typical observed values for HLS/DASH manifests and client‑side tracking JSON, and will vary with payload size and content.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article