Building a WHEP Viewer with Video.js


Learn how the standardization of WebRTC Playback with WHEP makes it simple to integrate with Video.js.

We at believe that streaming web content via WebRTC is the future, as by viewing content in real-time, enabling interactivity is valuable across many experiences. To be the change we want to see, we have created more opportunities to start building WebRTC based content. In this particular instance, we wanted to create more options for WHEP broadcast viewers using popular, open source technologies that anyone could use for their own solution. Video.js is an extremely popular open source HTML5 player framework, which we thought would be a perfect choice for a new integration.

Quick Recap of WHEP

For those who have yet to read our blog on explaining WHEP, in short WHEP is a new set of open web standards designed to make egressing and decoding WebRTC based content easier and consistent between multiple providers. This way, your phone, your laptop, and your cable provider all use the same way to receive content, standardizing the way they communicate. This makes WebRTC easy to playback from any WebRTC based vendor, which in this example is as simple as pointing the viewer to a single URL, akin to a HLS manifest.

Video.js comes in as one option for one of these different viewing platforms to utilize as the framework for taking the WHEP broadcast data and converting it into a user consumable video stream. Chrome would be able to understand a Video.js application, but not the raw datastream.

Getting Started with the Video.js Integration

To help developers use Real-time Streaming APIs integrate with Video.js, we have built a NPM plugin to directly integrate the two together, of which you can see the GitHub repo here. This repository by itself represents the plugin, but within it, we also include a sample application, demonstrating how to use it in a real world scenario using Vite.

We can take a look at what our finished project will look like first at this URL.

Clone the repo and navigate to the sample app folder with the following command in your terminal:

# /path/to/videojs-plugin-millicast-whep
cd example

Next, lets install all of the dependencies with a simple:

npm install

And while waiting for it to finish, login or sign up for a free account to use for credentials. After creating a publishing token in the dashboard, navigate to the Playback tab and take note of the “WHEP endpoint” section:

WHEP Endpoint

Back in the cloned repo, we can then copy or rename .env.sample to just .env and copy the above URL to the file:

VITE_WHEP_URL = '<your_url_here>'

Beginning a WHEP-Compatible Broadcast

With the WHEP viewer sample app set up, we now need to generate a broadcast that is compatible with WHEP for us to test with.

The easiest way to do this is to simply click “BROADCAST” in the Streaming Dashboard, but that isn’t as fun, nor applicable in real world situations. Instead, I suggest testing this with OBS Studio, an extremely popular software used for software based live streaming. Currently, mainline OBS is not compatible with WebRTC, much less WHEP (although this is coming soon), there is an existing fork that has implemented these features in that is usable today.

To learn how to use this software, we suggest following the instructions laid on in this previous blog post.

Testing the Video.js WHEP Viewer App

With our stream started and our app set up, we can run our app and see the results. Start by running:

npm run dev

Then navigating to the proper URL, by default http://localhost:5173.

We can now clearly see working video playback of the broadcasted stream in browser!

Taking a look at the code, the viewer sample code is pretty short, only around 25 lines:

import videojs from 'video.js'
import MillicastWhepPlugin from 'videojsplugin'
import 'videojs-resolution-switcher/lib/videojs-resolution-switcher.css'
import 'videojs-resolution-switcher/lib/videojs-resolution-switcher'
const params = new Proxy(new URLSearchParams(, {
  get: (searchParams, prop) => searchParams.get(prop)
const whepUrl = params.whepUrl ? params.whepUrl : import.meta.env.VITE_WHEP_URL
videojs.registerPlugin('MillicastWhepPlugin', MillicastWhepPlugin)
// Configure Video.js options
const options = {
  muted: true
// Initialize Video.js player
videojs('my-video', options, function onPlayerReady () {
  videojs.log('Your player is ready!')
  this.MillicastWhepPlugin({ url: whepUrl })

This demonstrates how much the plugin is doing for you, simplifying the work needed to integrate Video.js with WHEP with standard Video.js functions and behavior, with the WHEP source being provided via native plugin handling.

Additional Features of the Video.js WHEP Integration

If you take the time to review more of the code, this plugin provides features beyond just WHEP support. The main one of note is the resolution switcher, which takes advantage of Simulcast to broadcast multiple bitrates and resolutions of the live stream at once, like you would see on Netflix for example. This is even displayed on the above screenshot with the gear icon, showing how the plugin is already setup to look for a simulcasted stream automatically, and add the feature in if found. If simulcast is not enabled, the gear will not show up.

This plugin will enter the NPM official repositories soon, where you can simply npm install it and use it in your next viewer application. Report any issues you might find directly in our issues tab of the main repository, and we will try to resolve it as timely as possible!

This isn’t just limited to Video.js, we have seen examples of WHEP integrations with other popular frameworks, such as Janus and GStreamer. For further content, we suggest joining the official IETF WHIP and WHEP mailing list, and watching this presentation by Senior Director of Engineering and WHEP lead researcher, Sergio Garcia Murillo:

Griffin Solot-Kehl

Developer Advocate

Griffin Solot-Kehl is a developer advocate from San Francisco. He has a passion for open source technologies, developer onboarding experiences, and good documentation. Outside of the tech world, Griffin loves curating Spotify playlists, trying out new recipes, and perfecting his skincare routine.

Get Started

Drive real-time interactions and engagement with sub-second latency

We are more than just a streaming solutions provider; we are a technology partner helping you build a streaming ecosystem that meets your goals. Get started for free and as you grow, we offer aggressive volume discounts protecting your margins.

Developer Resources

Explore learning paths and helpful resources as you begin development with

Copy link
Powered by Social Snap