▶M3U8 SPACE

How to Test an HLS Stream Online

The fastest way to test an HLS stream without installing anything is to paste the playlist URL into a browser-based player, then work down a short checklist if it fails. A good check covers the HTTP response, the playlist syntax, every

The fastest way to test an HLS stream without installing anything is to paste the playlist URL into a browser-based player, then work down a short checklist if it fails. A good check covers the HTTP response, the playlist syntax, every variant, a sample of segments, the CORS headers, and any encryption key. Skipping straight to "does it play" hides which layer is broken.

How it works

An HLS delivery chain has four layers. First, the playlist request must return HTTP 200 with a playlist MIME type. Second, the text must be a valid UTF-8 playlist with the required tags: #EXTM3U on the first line, #EXT-X-VERSION, #EXT-X-TARGETDURATION, #EXTINF entries, and #EXT-X-ENDLIST for VOD. Third, every referenced URL - variants, segments, and #EXT-X-KEY URIs - must resolve and return the expected bytes. Fourth, if a web player reads them through JavaScript, each response needs CORS headers.

A master playlist looks like this:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=1600000,RESOLUTION=1280x720,CODECS="avc1.4d401f,mp4a.40.2"
v1600/index.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=854x480,CODECS="avc1.4d401e,mp4a.40.2"
v800/index.m3u8

Relative paths are resolved against the playlist URL, not against the page that embeds the player. That single rule explains most "works locally, 404 in production" reports.

Step-by-step: a repeatable test

1. Check the response headers.

URL="https://cdn.example.com/vod/master.m3u8"
curl -s -D - -o /dev/null -H "Origin: https://m3u8.space" "$URL" \
  | grep -iE "HTTP/|content-type|access-control|cache-control"
curl -s "$URL" | head -12

Expect application/vnd.apple.mpegurl (or audio/mpegurl) and an Access-Control-Allow-Origin line. If the body is HTML, you are looking at a login page, a geo block, or a hotlink-protection redirect.

2. Validate variants and segments. Fetch the first media playlist, then the first two segments:

curl -s "$URL" | grep -E "^#EXT-X-STREAM-INF|^[^#]" | head -8
curl -s -o /dev/null -w "status=%{http_code} type=%{content_type} time=%{time_total}\n" \
  "https://cdn.example.com/vod/v1600/seg_00000.ts"
ffprobe -v error -show_entries format=duration -of csv=p=0 \
  "https://cdn.example.com/vod/v1600/seg_00000.ts"

3. Test playback in a real browser engine. Open the online HLS player, paste the URL, and watch the console. Use the stream inspector to list variants, segment durations, and encryption tags. A hosted player is a better signal than ffprobe because it exercises MSE, CORS, and codec support exactly as a viewer would.

4. Record the result in a checklist so a regression can be spotted on the next deploy:

CheckExpectedWhat a failure means
Playlist status200Auth, geo rule, or wrong path
Content-TypeHLS MIME typeServer falls back to text/plain
First line#EXTM3UWrong file or truncated response
TARGETDURATION>= longest EXTINFInvalid playlist, player may stall
Variant URLs200 for allLadder references missing renditions
First 2 segments200, correct bytesRelative path or CDN purge problem
BANDWIDTHMatches measured bitrateABR picks an unsustainable level
#EXT-X-KEY URI200, 16 bytesEncrypted segments will fail to decode
CORS headersPresent on all hostsBrowser player blocked
ENDLISTPresent for VODPlayer waits forever at the end

Common mistakes and parameters

ToolAnswersLimitation
curl -IStatus, MIME, CORS, cacheDoes not decode media
ffprobeCodecs, duration, timestampsDoes not test browser CORS
Browser playerReal user experienceNeeds a public URL
Stream inspectorLadder and segment mapNeeds CORS to read the playlist
StatusTypical causeFirst action
403Hotlink rule, token expiry, referer checkCompare with and without Referer
404Relative path resolutionPrint absolute URLs resolved from the playlist
206Range requestNormal for media bytes, not an error
301 / 302Redirect to another hostCheck CORS on the final host too
200 with HTMLAuth or error pageInspect the body, not just the status

Troubleshooting

  • Safari plays but Chrome stalls: Safari may use native HLS while Chrome needs hls.js, so check CORS on every host in the chain.
  • The first segment loads and the rest 404: the media playlist is stale relative to a live sliding window; refetch the playlist instead of caching it.
  • ffprobe reports a valid duration but the browser shows a black frame: codec or profile is outside browser support; check CODECS in the master playlist.
  • Everything works with curl but not in the player: an OPTIONS preflight is failing, or the header is missing on 206 and 404 responses.
  • Encrypted playlists fail with a key error: confirm the key URI is reachable, returns exactly 16 bytes, and is served with CORS headers.
  • Intermittent failures only for some viewers: a CDN edge is caching an error or an older playlist; purge it and retest with a cache-busting query string.

Related reading