Home / Guides / Correct MIME Type for .m3u8 and .ts Files

Correct MIME Type for .m3u8 and .ts Files

Serve .m3u8 playlists as application/vnd.apple.mpegurl (or the widely accepted application/x-mpegURL) and .ts segments as video/mp2t. If you use fragmented MP4 segments instead, the correct type is video/mp4. Getting this right is a server configuration issue, not a player setting, and it is one of the first things to check when a stream works on one host but fails on another.

Why the content type matters

An HLS client fetches the playlist with a normal HTTP request, then fetches each segment listed inside it. Most players identify a playlist by parsing its text rather than by trusting the header, which is why a stream often appears to work even when the MIME type is wrong. The problems show up at the edges instead. A CDN may apply text compression to a playlist it believes is text/plain, a proxy may refuse to cache a segment with an unknown type, and a page with X-Content-Type-Options: nosniff blocks the browser from guessing the correct type. Mobile browsers and native players are generally stricter than desktop hls.js, so a stream that passes your laptop test can fail on a phone.

A related mistake is serving the playlist as application/octet-stream. Some browsers respond by downloading the file instead of handing it to the player, which looks exactly like "the stream won't play".

nginx configuration

The types block in nginx usually already maps .ts, but rarely maps .m3u8. Add both explicitly inside the server or location block that serves your HLS directory:

types {
    application/vnd.apple.mpegurl  m3u8;
    video/mp2t                     ts;
    video/mp4                      m4s mp4;
}

location /hls/ {
    add_header Cache-Control "public, max-age=2" always;   # live playlists
    add_header Access-Control-Allow-Origin "*" always;     # if players are on another domain
}

Keep the playlist cache lifetime short for live streams. A stale playlist makes the player request segments that have already rotated out of the sliding window, producing repeated 404s that look like a bandwidth problem. VOD playlists, which end with #EXT-X-ENDLIST, can be cached for much longer.

Other common hosts

Verify with curl

Check both the playlist and one segment, and include the Origin header when the player lives on a different domain:

curl -I https://example.com/hls/index.m3u8
curl -I https://example.com/hls/seg0.ts
curl -I -H "Origin: https://player.example.com" https://example.com/hls/index.m3u8

You want HTTP/2 200, the correct content-type, and an Access-Control-Allow-Origin that matches your player origin. A content-encoding: gzip on a binary segment is a red flag.

Troubleshooting checklist

Related reading