# videojs/http-streaming (VHS): playing HLS and DASH in video.js where the browser will not

> VHS is the HTTP streaming engine bundled into video.js 7 and 8. It exists for browsers that lack native HLS or DASH support, and its main cost is that it ties your player to Media Source Extensions.

**videojs/http-streaming** — HLS, DASH, and future HTTP streaming protocols library for video.js

- Repository: https://github.com/videojs/http-streaming
- Website: https://videojs-http-streaming.netlify.app/
- Stars: 2,663 · Forks: 437
- Language: JavaScript
- License: NOASSERTION
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/videojs-http-streaming

## What VHS solves, and for whom

Browsers disagree about streaming formats. Safari on macOS and iOS plays HLS natively. Chrome, Firefox and Edge generally do not, and MPEG-DASH support varies. The README frames the project as a way to "Play HLS, DASH, and future HTTP streaming protocols with video.js, even where they're not natively supported." That sentence is the whole scope. VHS is not a general HTTP streaming library, and the related searches that mix it up with Server-Sent Events, WebSockets or long polling are looking for something this project does not do.

The audience is narrow and specific. If you already use video.js as your player and your audience includes Chrome or Firefox, VHS is the piece that makes an HLS manifest play there. The README states the library is included in the default build of video.js since version 7, so most teams are already running it without installing anything. The README adds that separate installation is only needed for "a specifc combination of video.js and http-streaming versions", and that in that case you should pair it with the core build of video.js rather than the bundled one.

## The MSE dependency is the architecture

VHS does not decode video. It fetches a manifest, parses it, picks a rendition, pulls segments, and feeds those segments into the browser's Media Source Extensions API, which the video element then plays. The README is blunt about the requirement: "The Media Source Extensions API is required for http-streaming to play HLS or MPEG-DASH." Everything else in the design follows from that.

The compatibility table splits browsers into three groups. Chrome, Firefox and Internet Explorer 11 on Windows 10 or 8.1 support MSE and are listed as supported. Chrome Android, Firefox Android and Edge have some native HLS support, but the README notes that the overrideNative option defaults to true everywhere except Safari, so MSE playback is used anyway. Mac Safari and iOS Safari are listed as native only, with the README recommending native HLS on Mac and iPad Safari even though those browsers do have MSE.

That last point is a design decision worth pausing on. The library is capable of running on Safari, but the maintainers steer you away from it. If your product is Safari-first, VHS is not the layer you want to be debugging.

The README also documents a set of runtime properties the player exposes, including vhs.playlists.main, vhs.playlists.media, vhs.systemBandwidth, vhs.bandwidth, vhs.throughput, vhs.selectPlaylist, vhs.representations, vhs.xhr and vhs.stats. These are the hooks for understanding what the engine actually chose. vhs.selectPlaylist in particular is where adaptive bitrate decisions live, and it is exposed rather than hidden.

## Installing VHS and playing a first manifest

For most projects there is nothing to install. The README states plainly: "In most cases it is not necessary to separately install http-streaming", because it has been part of the default video.js build since version 7. Only install it if you need a specific pairing of video.js and VHS versions, and in that case use the core build of video.js, without the bundled copy.

When you do need it, the npm command in the README is:

```bash
npm install --save @videojs/http-streaming
```

The package is scoped, so the name is @videojs/http-streaming, not videojs-http-streaming. The README also points at a CDN directory under unpkg for the dist build and at the GitHub releases page for downloads.

The README's Getting Started example loads the core video.js build and the VHS bundle together, then declares the source on the video-js element. The manifest URL and the type attribute are the two parts that matter:

```html
<video-js id=vid1 width=600 height=300 class="vjs-default-skin" controls>
  <source
     src="https://example.com/index.m3u8"
     type="application/x-mpegURL">
</video-js>
<script src="video.core.min.js"></script>
<script src="videojs-http-streaming.min.js"></script>
<script>
var player = videojs('vid1');
player.play();
</script>
```

Note the type value: application/x-mpegURL for an HLS manifest. The README then gives a recommendation that is easy to skip over: use the video-js element or load a source with player.src(sourceObject) "in order to prevent the video element from playing the source natively where HLS is supported". If you set the src attribute directly on a plain video element, Safari may take over and bypass VHS entirely, which means your VHS options silently stop applying.

What you should see after this is a playing video and, in the console, a player object whose vhs property exists. The README documents an xhr-hooks-ready event and a loadedmetadata event as the points at which the internals become inspectable. The README does not document what the player renders if the manifest fails to parse, so error handling is something you will need to work out from the troubleshooting guide rather than the main README.

## Where VHS is the wrong tool

The MSE requirement is a hard boundary, not a preference. Any environment without Media Source Extensions cannot use VHS for HLS or DASH, and the README does not offer a fallback path. If your target is an embedded browser, a smart TV runtime or a webview that lacks MSE, this library cannot help you, and no configuration option changes that.

The README keeps a Known Issues and Workarounds section with three entries: Fragmented MP4 Support, Assets with an Audio-Only Rate Get Stuck in Audio-Only, and DASH Assets with $Time Interpolation and SegmentTimelines with No t. The existence of that section is the honest signal here. These are cases where the library's behaviour does not match what a stream author might expect, and the workarounds live in documentation rather than in code that fixes them.

The second entry is the one to read before shipping an audio product. An asset whose renditions include an audio-only rate can get stuck in audio-only, which means the adaptive bitrate logic and the manifest's rendition list interact in a way that can strand playback. If your ladder includes an audio-only rung for low-bandwidth users, that is exactly the configuration the README warns about.

There is also a version-coupling cost. Because VHS ships inside video.js 7 and 8, upgrading the player can move the streaming engine underneath you. The README's own instruction to install separately only for "a specifc combination of video.js and http-streaming versions" is an acknowledgement that the two move together by default and that untangling them is the exception, not the normal path.

## How hls.js differs in approach

hls.js is the obvious comparison for anyone evaluating HLS playback in the browser, and the difference is structural rather than cosmetic. hls.js is an HLS engine you attach to a plain HTML video element through MediaSource. VHS is an HLS and DASH engine that plugs into video.js, which owns the player UI, the control bar, the plugin system and the source-selection logic.

That means the two libraries answer different questions. If you have no player and want to keep your DOM minimal, hls.js gives you HLS without a player framework. If you already have video.js, adopting hls.js means either running two player abstractions or replacing video.js, and you lose the option plumbing that VHS exposes. VHS also covers DASH, which hls.js does not, so a project with both manifest types has one fewer dependency to manage under VHS.

The trade-off runs the other way too. VHS inherits video.js's release cadence and its compatibility matrix, and the README pins that matrix to Video.js 7.x and 8.x. A team that wants to stay on an older video.js major, or that wants a streaming engine it can upgrade independently of the player, will find that coupling inconvenient. Neither library removes the MSE requirement, so that constraint does not decide between them.

## Maintenance, releases and the licence question

The README labels the project's maintenance status as Stable, and the repository is not archived. The last push was on 2026-08-12, and the most recent release listed is v3.17.5 on 2026-06-26. The gap before that is wider: v3.17.2 and v3.17.1 both landed on 2025-07-22. So the release history is not a steady drumbeat, and a team planning an upgrade should look at the CHANGELOG.md in the repository rather than assume frequent point releases.

Upgrade cost is shaped by the bundling. Since VHS is included in video.js 7 and 8 by default, the practical upgrade path is usually a video.js upgrade, and the streaming engine comes along. The README's compatibility line (Video.js 7.x, 8.x) tells you which player majors this version is tested against. If you have installed VHS separately, you are responsible for keeping the pair in step, and the README's warning to use the core video.js build in that case is the thing to get right.

The licence needs a direct look. The repository holds a LICENSE file, but the package metadata carries NOASSERTION rather than a recognised SPDX identifier, so this article will not tell you what terms apply. Read LICENSE in the repository and have whoever handles licensing on your team confirm it against your distribution model before you ship. That is a documentation gap, and it is the kind of gap that matters more for a library embedded in a player than for a standalone tool.

## Conclusion

Adopt VHS if you already build on video.js and need HLS or DASH on Chrome, Firefox or Edge, and if you can accept the MSE requirement. Do not adopt it as a general HTTP streaming library: the README describes HLS, DASH and future HTTP streaming protocols, not SSE, not WebSockets, and not long polling, and nothing in the documentation covers server-push use cases. Before wiring it into a product, check the compatibility table against your target browsers, read the Known Issues and Workarounds section for the fragmented MP4 and audio-only cases, and confirm the licence text in the repository, since the package metadata does not state a standard SPDX identifier.

## FAQ

### Does videojs/http-streaming need to be installed separately from video.js?

In most cases no. The README states that VHS has been included in the default build of video.js since version 7, and that you should only install it separately if you need a specific combination of video.js and http-streaming versions. When you do install it separately, use the core build of video.js without the bundled VHS.

### Which browsers can videojs/http-streaming play HLS or DASH in?

The README requires Media Source Extensions, and lists Chrome, Firefox and Internet Explorer 11 on Windows 10 or 8.1 as MSE-supporting browsers. Chrome Android, Firefox Android and Edge have some native HLS support but default to MSE playback through the overrideNative option, while Mac Safari and iOS Safari are listed as native only.

### Is videojs/http-streaming the same thing as HTTP streaming with Server-Sent Events or WebSockets?

No. The README describes VHS as a way to play HLS, DASH and future HTTP streaming protocols with video.js. It is a media playback engine built on Media Source Extensions, and the documentation does not cover Server-Sent Events, WebSockets or long polling.

### What does the README say about DRM in videojs/http-streaming?

DRM is supported through the videojs-contrib-eme plugin rather than by VHS itself. The README says to include that plugin, initialize it, and add options to either the plugin or the source.

### What are the known issues in videojs/http-streaming?

The README keeps a Known Issues and Workarounds section listing Fragmented MP4 Support, assets with an audio-only rate getting stuck in audio-only, and DASH assets with $Time interpolation and SegmentTimelines with no t. These are documented as workarounds rather than fixed behaviour.

## Sources

- [Issues](https://github.com/videojs/http-streaming/issues)
- [Project website](https://videojs-http-streaming.netlify.app/)
- [README](https://github.com/videojs/http-streaming/blob/main/README.md)
- [Releases](https://github.com/videojs/http-streaming/releases)
- [videojs/http-streaming on GitHub](https://github.com/videojs/http-streaming)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/videojs-http-streaming
