On iPhone, HLS plays through Safari’s native <video> element — not through
hls.js, which the iOS Media Source path doesn’t support for HLS. Most breakage
comes from four things: forcing hls.js on iOS, a missing playsinline
attribute, the wrong MIME type on the .m3u8, or an autoplay that isn’t muted.
Serve application/vnd.apple.mpegurl, add playsinline, and let Safari play
the URL directly.
The core gotcha: don’t use hls.js on iOS
hls.js is the right tool almost everywhere — except iPhone. iOS Safari doesn’t
expose Media Source Extensions for HLS, so hls.js can’t attach its SourceBuffer
there. What it can do is play HLS natively: hand the .m3u8 straight to a
<video> element and Safari handles adaptive streaming itself. The standard
pattern is to feature-detect and let native win:
if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = playlistUrl; // iOS Safari: native HLS
} else if (Hls.isSupported()) {
new Hls().loadSource(playlistUrl); // everyone else: hls.js
}
If you skip the check and always call hls.js, iPhones get a black player.
The checklist
Serve the right MIME type
The .m3u8 must be sent as application/vnd.apple.mpegurl (or application/x-mpegURL). A generic text/plain makes Safari refuse it.
Add playsinline
Without it, iPhone forces fullscreen playback and inline autoplay silently fails. Pair it with muted if you autoplay.
Muted for autoplay
iOS only autoplays muted, inline video. An unmuted autoplay is blocked outright — require a tap, or start muted.
HTTPS, CORS, and Range
Serve over HTTPS, and make sure segments answer Range requests — Safari relies on byte-range seeking. (See the hls.js CORS fix.)
The subtler ones
- Codec support. iOS is strict: H.264/AAC in an HLS playlist is safe. An HEVC or AV1 rendition without an H.264 fallback rung can leave iPhone with nothing to play even though the manifest loads.
- Signed URL expiry mid-session. Safari re-requests the playlist during long sessions; if your signed token expires between requests, playback stops. Tokens need a lifetime longer than the video, or a renewal scheme — the reason token renewal matters is covered in how signed playback tokens work.
- Low Power Mode. iOS blocks autoplay entirely in Low Power Mode — always give users a tap-to-play control as the fallback.
The short version
On iPhone, get out of hls.js’s way and let Safari play the URL: correct MIME type,
playsinline, muted for autoplay, HTTPS with Range support. Do that and native
HLS is rock-solid.
rehelios emits standards-compliant HLS with an H.264 base rung and the correct MIME type, so it plays natively on iOS out of the box — and MPEG-DASH alongside it for everywhere else. More on the formats in HLS vs DASH, and the delivery setup in the docs.