MEDIA GUIDES / Live Streaming Video

HTML5 HLS: How to Add Adaptive Streaming to a Web Video Player

Key Takeaways

  • HTML5 HLS combines the HTML5 video element with HTTP Live Streaming (HLS) to deliver adaptive video playback through web browsers.
  • HLS divides video into smaller segments and provides multiple quality levels, allowing the player to adjust playback based on network conditions.
  • The HTML5 <video> element supports native HLS playback in Safari, while other browser environments commonly rely on JavaScript libraries such as HLS.js.
  • Cloudinary can automatically generate HLS streams from original video assets and deliver them through its HTML5 video player.

Video playback in a browser seems simple enough. You add a video element to a page, provide a source, and let visitors press play. But what happens when the video needs to adapt to different internet speeds, screen sizes, and devices without interrupting playback?

HTML5 HLS combines the browser’s native video capabilities with HTTP Live Streaming, an adaptive streaming protocol originally developed by Apple. Instead of delivering one large video file, HLS breaks content into smaller segments and provides multiple versions at different quality levels. A compatible player can switch between these versions depending on the viewer’s network conditions.

For developers, implementing this involves more than adding an HLS URL to a video element. You also need to consider browser support, playback libraries, stream encoding, and how the video segments are delivered.

In this guide, we’ll explore how HTML5 HLS works, how to implement it using HLS.js, what can affect browser compatibility, and how to deliver adaptive streams through Cloudinary.

In this article:

What Is HTML5 HLS?

HTML5 HLS refers to using the HTML5 video element to play content delivered through HTTP Live Streaming (HLS). HTML5 provides the browser interface for playing, controlling, and displaying video. HLS handles how video content is packaged, segmented, delivered, and adapted to changing network conditions.

The HTML5 <video> element can display the stream, but not every browser can interpret an HLS playlist natively. JavaScript playback libraries help provide broader compatibility.

A basic HTML5 video element looks like this:

<video
  controls
  width="800"
  playsinline
  src="https://example.com/video.mp4">
</video>

For an HLS stream, the source typically points to an .m3u8 playlist rather than a single MP4 file.

<video
  controls
  playsinline
  src="https://example.com/stream/master.m3u8">
</video>

This direct approach works in browsers with native HLS support, which excludes Edge and Firefox. For broader browser compatibility, developers generally use a player library such as HLS.js.

How HLS Works With HTML5 Video

HLS uses adaptive bitrate streaming to deliver video at an appropriate quality for the viewer’s current network conditions.

Instead of downloading one complete video file, the player requests small segments throughout playback.

The process looks like this:

Original video
      ↓
Transcoding into multiple quality levels
      ↓
Video divided into segments
      ↓
Master playlist generated
      ↓
Segments delivered over HTTP
      ↓
HTML5 video player plays the stream
      ↓
Quality adjusts to network conditions

An HLS stream typically contains three important components.

1. Multivariant Playlist

An HLS multivariant playlist is an .m3u8 file that describes the available video versions.

For example, a stream might offer multiple versions, ranging from 480p to 1080p. The player reads the playlist and uses the available bandwidth, playback buffer, and device capabilities to select an appropriate version.

2. Media Playlists

Each quality version has its own media playlist. These files describe the individual segments that make up that version of the video. A media playlist contains information such as segment duration, file locations, and playback metadata.

3. Video Segments

Depending on the HLS packaging, these segments may use MPEG-TS (.ts) or fragmented MP4 formats, including CMAF-compatible media segments. Because the segments are delivered separately, the player can switch between quality levels without downloading an entirely new video file.

Does HTML5 Support HLS Natively?

Not universally.

All modern browsers support the HTML5 video element, but native HLS support varies.

Safari has built-in HLS playback across its supported platforms. Other browsers commonly require a JavaScript playback engine.

A simplified compatibility overview:

Browser Typical HLS Playback Approach
Safari on macOS Native HLS or HLS.js
Safari on iPhone and iPad Native HLS, with newer Managed Media Source support in applicable versions
Google Chrome Native as of Version 142
Firefox HLS.js
Microsoft Edge HLS.js
Android browsers HLS.js or platform-specific playback support

The important distinction is that supporting HTML5 video does not automatically mean supporting HLS.

How to Play HLS in HTML5 Using HLS.js

HLS.js is an open-source JavaScript library that enables HLS playback in browsers with supported media APIs. It works with the standard HTML5 video element and uses Media Source Extensions to handle stream delivery.

Instead of implementing playlist parsing, segment loading, and quality switching yourself, you let HLS.js manage those operations.

Step 1: Install HLS.js

For a JavaScript application, install and import the library to your project.

Step 2: Add the HTML5 Video Element

Create a video element where the stream will appear.

<video
  id="hls-player"
  controls
  playsinline
  preload="metadata"
  width="100%">
</video>

<p id="playback-message" role="status"></p>

The controls attribute provides the browser’s standard playback controls, while playsinline helps prevent unwanted fullscreen playback behavior on supported mobile devices.

Step 3: Connect the HLS Stream

Use HLS.js to load the .m3u8 playlist and attach it to the video element.

import Hls from "hls.js";

const video = document.querySelector("#hls-player");
const message = document.querySelector("#playback-message");

const videoSrc = "https://example.com/stream/master.m3u8";

if (!(video instanceof HTMLVideoElement)) {
  throw new Error("Video element not found.");
}

if (Hls.isSupported()) {
  const hls = new Hls();

  hls.loadSource(videoSrc);
  hls.attachMedia(video);

  hls.on(Hls.Events.ERROR, (_event, data) => {
    if (data.fatal) {
      message.textContent =
        "The video stream could not be played.";

      hls.destroy();
    }
  });

} else if (
  video.canPlayType("application/vnd.apple.mpegurl")
) {
  video.src = videoSrc;

} else {
  message.textContent =
    "Your browser does not support HLS playback.";
}

The implementation checks whether HLS.js can run in the browser. If supported, it loads the playlist and connects the stream to the video element. If the JavaScript engine is unavailable, the code checks for native HLS playback.

For production applications, you’ll also want to implement more detailed network and media error recovery rather than simply displaying an error message.

Step 4: Test the Stream

Once connected, test the player across different browsers and devices. Check that:

  • The playlist loads successfully.
  • Video segments return valid responses.
  • Playback starts without unnecessary delays.
  • Quality changes work when network conditions change.
  • Seeking works correctly.
  • Audio and video remain synchronized.
  • The player recovers appropriately from interruptions.

HTML5 HLS vs. Regular MP4 Playback

Both approaches use the HTML5 video element, but the delivery process is different.

HTML5 HLS vs. Regular MP4 Playback

Both approaches use the HTML5 video element, but the delivery process is different.

Category Progressive MP4 HLS
Delivery One video file Playlist and video segments
Adaptive quality Not built into basic progressive playback Yes
Network adaptation Requires separate handling Supported by compatible players
Initial setup Simpler Requires HLS packaging and compatible playback
Seeking Supported Supported through stream segments
Live streaming Not typically used as a live segmented protocol Supports live and on-demand
Best for Short clips and straightforward playback Long-form video, live streams, and adaptive delivery

Regular MP4 delivery is often sufficient for short clips, background videos, and simple web playback. HLS becomes more useful when video quality needs to adapt to varying network conditions, particularly for longer videos and live broadcasts.

One tradeoff is startup time. HLS requires a playlist request before the relevant segments can play, adding an extra step compared with progressive delivery. For short clips, that additional complexity may not be worthwhile.

Common HTML5 HLS Implementation Problems

Even when the player code is correct, HLS playback can fail because of issues elsewhere in the delivery chain.

CORS Configuration

When the playlist or segments are hosted on another domain, the browser needs permission to access them. HLS.js requires the playlist and media resources to include appropriate CORS headers permitting GET requests.

Check:

  • The master playlist
  • Individual media playlists
  • Video segments
  • Encryption keys, when applicable

A CORS issue affecting just one resource can interrupt playback.

Incorrect MIME Types

Servers should return appropriate content types for HLS resources.

Common examples include:

Resource Typical MIME Type
.m3u8 playlist application/vnd.apple.mpegurl
.ts segment video/mp2t
MP4 media segment video/iso.segment
MP4 initialization or video file video/mp4

Incorrect server configuration can prevent some browsers or playback engines from interpreting stream resources correctly.

Unsupported Codecs

A browser may support HLS playback but still fail to decode the codecs used in the stream. Check the video and audio codecs against your target devices.

Broken Playlists or Missing Segments

A multivariant playlist may load correctly while one of its referenced media playlists or segments is unavailable. Inspect the browser’s Network panel and verify that every referenced resource returns a valid response.

Poor Adaptive Bitrate Configuration

A stream with poorly selected quality levels may switch too frequently, buffer unnecessarily, or deliver more data than the device can handle.

Encoding profiles should account for:

  • Resolution
  • Bitrate
  • Frame rate
  • Codec
  • Keyframe alignment
  • Segment duration
  • Available bandwidth

Live Streaming Latency

Standard HLS prioritizes reliable delivery over extremely low latency. For interactive broadcasts, live auctions, or real-time events, Low-Latency HLS (LL-HLS) may be more suitable. The choice depends on how much delay viewers can tolerate.

Using Cloudinary for HTML5 HLS Delivery

Implementing HLS involves more than configuring a video player. You also need to prepare the video, generate the required quality levels, create playlists, store segments, and deliver everything reliably. Cloudinary can handle much of that processing.

Automatically Generate HLS Streams

Cloudinary can generate HLS or MPEG-DASH adaptive streaming versions from a single original video asset.

With automatic streaming profile selection, you can use the sp_auto transformation parameter and request an .m3u8 output.

For example:

https://res.cloudinary.com/<cloud_name>/video/upload/sp_auto/<public_id>.m3u8

Cloudinary generates the required representations and supporting streaming files. The adaptive streaming workflow can also be configured with a maximum output resolution.

Deliver HLS With the Cloudinary Video Player

Cloudinary’s HTML5-based Video Player supports HLS and MPEG-DASH playback.

It provides more than basic video controls, including:

  • Adaptive bitrate streaming
  • Customizable player appearance
  • Responsive playback
  • Video analytics
  • Playlists and recommendations
  • Subtitles and captions
  • Accessibility features
  • Video transformations

For teams building video experiences into websites or applications, this can reduce the amount of custom playback infrastructure required.

Final Thoughts

HTML5 HLS makes adaptive video streaming possible through standard browser-based playback workflows.

The HTML5 video element handles playback, while HLS manages the delivery of video segments and multiple quality levels. HLS.js bridges browser compatibility gaps by connecting HLS streams to the browser’s media APIs.

For developers, the important part is understanding that successful HLS playback depends on the entire delivery chain. The playlists, segments, codecs, browser APIs, CORS configuration, and player implementation all need to work together.

Cloudinary simplifies the processing and delivery side by automatically generating HLS streams from original video assets and providing an HTML5 video player with adaptive streaming support.

This gives development teams more time to focus on building the actual viewing experience instead of managing every part of the streaming pipeline.

Frequently Asked Questions

Does HTML5 support HLS?

The HTML5 video element is supported across modern browsers, but native HLS playback is not universal. Safari supports native HLS, while other browsers commonly use JavaScript libraries such as HLS.js.

What is the difference between HLS and HTML5 video?

HTML5 video is the browser element responsible for playback. HLS is a streaming protocol that defines how video is segmented, organized into playlists, and delivered adaptively.

Does HLS support live streaming?

Yes. HLS supports both live broadcasts and video-on-demand content. Low-Latency HLS is available for applications that need to reduce the delay between the live event and viewer playback.

Can Cloudinary generate HLS streams?

Yes. Cloudinary can automatically generate HLS and MPEG-DASH adaptive streaming representations and supporting files from a single original video asset.

QUICK TIPS
Tali Rosman
Cloudinary Logo Tali Rosman

In my experience, here are 10 tips that can help you optimize HTML5 HLS streaming, improve playback reliability, and deliver a better viewing experience across browsers and devices.

  1. Use content-aware encoding to optimize your bitrate ladder.
    Instead of applying identical bitrate profiles to every video, analyze each asset’s motion, texture, and visual complexity. A static interview requires significantly less bandwidth than a fast-moving sports broadcast at the same resolution. Content-aware encoding can reduce delivery costs while maintaining perceptual quality.
  2. Prevent CDN cache fragmentation with consistent segment URLs.
    Frequently changing query parameters, authentication tokens, or transformation URLs can create multiple cache entries for identical video segments. Where your CDN and security model permit, normalize cache keys and separate authorization from immutable media identifiers to improve cache-hit ratios.
  3. Use independent segments to make quality switching more reliable.
    Ensure each video segment starts at a suitable random-access point, ideally an IDR frame for H.264 streams. When encoding multiple representations, keep GOP boundaries aligned across variants. This helps prevent decoding glitches and unnecessary buffering during bitrate transitions.
  4. Tune startup behavior separately from steady-state playback.
    A bitrate selection that works well after 30 seconds of playback may be too aggressive during startup, when bandwidth estimates are unreliable. Consider beginning with a conservative representation and allowing faster quality upgrades once throughput measurements stabilize. Track startup delay and early rebuffering independently.
  5. Monitor quality of experience rather than just video delivery errors.
    HTTP 200 responses do not guarantee smooth playback. Instrument startup time, rebuffering ratio, bitrate-switch frequency, playback failures, and watch duration. Segment these metrics by browser, device, connection type, and CDN region to uncover problems that aggregate dashboards can hide.
  6. Use timed metadata for synchronized interactive experiences.
    HLS timed metadata, including ID3 metadata where supported, can synchronize quizzes, product overlays, chapter markers, and interactive advertisements with video playback. Validate metadata handling across native and JavaScript-based players because event exposure and timing behavior can differ.
  7. Design an explicit strategy for expiring playback credentials.
    Signed URLs and short-lived authentication tokens can expire while someone watches a long video or live stream. Make sure playlist refreshes, segment requests, and encryption-key retrieval remain authorized throughout the viewing session. Test token renewal without forcing viewers to restart playback.
  8. Optimize seek-heavy workloads with segment indexing and CDN prewarming.
    Educational platforms and video editors often have users jumping repeatedly between timestamps. Analyze seek patterns to identify frequently accessed regions and consider targeted cache warming for popular content. Avoid warming every representation indiscriminately, as the additional origin traffic may outweigh the benefits.
  9. Test discontinuities and timestamp rollover in long-running live streams.
    Continuous live broadcasts can encounter encoder restarts, timestamp discontinuities, and changes in media configuration. Verify that playlist discontinuity markers and timestamp handling remain correct during these events. A stream that works for an hour may still fail after several days of uninterrupted operation.
  10. Separate playback analytics from CDN delivery analytics.
    Player analytics explain what viewers experience, while CDN logs reveal how playlists and segments are requested and served. Correlate the two using privacy-conscious session identifiers and request timing. This makes it easier to distinguish network congestion, cache misses, encoding problems, and player-level failures without relying on guesswork.
Last updated: Nov 5, 2026
★★★★★
4.5 (21 reviews)
Talk to Sales Talk to Sales