惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
量子位
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
U
Unit 42
IT之家
IT之家
F
Fortinet All Blogs
GbyAI
GbyAI
MongoDB | Blog
MongoDB | Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
大猫的无限游戏
大猫的无限游戏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The Register - Security
The Register - Security
NISL@THU
NISL@THU
Webroot Blog
Webroot Blog
A
Arctic Wolf
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
Visual Studio Blog
Recent Announcements
Recent Announcements
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Blog — PlanetScale
Blog — PlanetScale
L
LangChain Blog
P
Palo Alto Networks Blog
Y
Y Combinator Blog
WordPress大学
WordPress大学
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
AWS News Blog
AWS News Blog
有赞技术团队
有赞技术团队
Engineering at Meta
Engineering at Meta
C
Cybersecurity and Infrastructure Security Agency CISA
aimingoo的专栏
aimingoo的专栏
Know Your Adversary
Know Your Adversary
Cyberwarzone
Cyberwarzone
Martin Fowler
Martin Fowler
The Hacker News
The Hacker News
P
Privacy International News Feed
T
Threat Research - Cisco Blogs
G
GRAHAM CLULEY
宝玉的分享
宝玉的分享
博客园 - 聂微东
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The GitHub Blog
The GitHub Blog
S
Securelist
T
The Exploit Database - CXSecurity.com
T
Threatpost
Microsoft Azure Blog
Microsoft Azure Blog
The Cloudflare Blog
F
Full Disclosure

ImageKit.io Blog

Next.js Image Optimization with ImageKit Use Video as a Background in Your Next.js Project How to Fix Autoplay Video in Next.js How Durian Scaled a Visual-First Retail Experience to 350K Monthly Visitors Online How Matsmart accelerated image delivery across countries with ImageKit AI in Digital Asset Management: From Smart Workflows to Agentic Automation How Joseph Joseph unified and secured global video delivery with ImageKit How Modall powers fast, effortless media delivery across 40+ projects with ImageKit Digital Asset Management (DAM) Trends: 2026 Report How to add a poster image to Video.js player (and automate it) Building the future of storytelling with fast, AI-powered video delivery How PushOwl delivers 100M+ image-rich notifications seamlessly with ImageKit How Homify delivers millions of interior design images seamlessly with ImageKit Better event discovery with lightning‑fast videos & images Adding video player in React Native Video player in Angular applications Crop and resize videos in React Next.js image and video upload React image and video upload React video optimization How we quadrupled our traffic to 625K monthly page views How Apollo 24|7 boosted performance & reduced costs with ImageKit Simplify your media workflows with ImageKit DAM integrations Extending Lighthouse for custom image and video optimization analysis Brand Asset Management: What is it? How does it work? WordPress Digital Asset Management Guide - Manage your WP media assets better Why Shopify retailers need a digital asset management solution DAM vs. SharePoint: Which is best for you? AI-powered Metadata and Tagging in Digital Asset Management How Hopscotch built India's largest online Kids' fashion brand with ImageKit Dropbox Vs. DAM: Which Is The Right Tool For Digital Asset Management Digital Asset Management for Photographers: A Complete Guide Why digital asset management for agencies is essential Helping both Top and Bottom Line: SaffronStays rapid, profitable growth with ImageKit How KreditBee simplified media experiences with ImageKit Google Drive alternatives for businesses (with fast-growing teams) Node.js image upload ImageKit: The Secret Ingredient in Swiggy’s Expansion Journey Streamlining the Design Approval Process: A Comprehensive Guide AV1 Codec - Complete guide for video application devs PHP image and video upload Angular image & video upload AV1 vs VP9: Which codec should you choose? Adding video player in Next.js React Video Player VP8 vs VP9 - In the context of online video delivery Exploring WebM vs MP4 7 Free Digital Asset Management Software that are not Open-Source Comparing 9 Top Digital Asset Management Tools in the Market What are Brand Standards and Why do they Matter? Boost Sales and Brand Appeal: Essential Tips for eCommerce Image Management Brand Recall: The Strategy to Create Unforgettable Brands How to upload files in HTML? Branding for Small Businesses (2025 Edition) Everything you need to know about VP9 codec Recent updates from ImageKit and what's next Best Ways to Write RFP For Digital Asset Management (+ with free RFP template) What is Brand Dilution? How to Avoid It? Explained with [Examples] The Importance of Brand Identity: Leveraging Digital Asset Management for Impact From Launch to Scale: How to Launch a Brand Campaign Digital Asset Management Requirements - What do You Need to Evaluate and How? Marketing Collateral Management: A Quick End-to-End Guide Video Content Management System: What Is It And How To Choose One? Dropbox vs. Google Drive vs. Onedrive: The Best Cloud Storage Solution How to Build Brand Trust: Get Started In 2025 Google Drive vs. Box: A Detailed Comparison How Digital Asset Management Solutions Help Protect Brand Equity A DAM Solution Can Safeguard Your Digital Intellectual Property - Here’s How WebP Vs. PNG: Which Image Format Should You Use and Why? How to Resize Images in Bootstrap Easily Progressive jpegs (PJPEG): the key to loading images faster on your website Dropbox vs. Google Drive: The Best Cloud Storage For Digital Assets Dropbox Pros & Cons In 2024: An In-Depth Analysis and Why A DAM Solution Stands Out Google Drive Vs OneDrive: The Better Storage Option For Digital Assets Manage your video assets better with video metadata Understanding DAM's Role in Strengthening Brand Identity Digital asset management strategy: What to know before creating one The Ultimate Guide To Marketing Agency Onboarding 6 Solutions To Simplify Large File Sharing Over The Web A Step-by-Step Breakdown of a Video Production Workflow 13 Digital Asset Management Use Cases You Should Know How to Conduct a Brand Audit and Manage Your Brand Assets Costly Consequences of Inconsistent Branding And How DAM Can Help Dynamic Asset Transformation: What It Is, Why You Need It, and How ImageKit Can Help Everything You Need to Know About HTML Video Autoplay How To Select Your DAM Vendor: A Complete Guide How to Boost User Experience with Smart Digital Asset Management React Image Optimization: A Guide for Web Developers Why Should DAM Be A Part Of Your MarTech Stack? Unleashing the Power of Content Repurposing with ImageKit MKV vs MP4: Which Video File Format Is Better for Your Needs? Digital Asset Management For Ecommerce: A Complete Guide How an Image Tagging Software can Transform Your Image Search How to Manage Your Content Lifecycle Effectively M4V vs MP4: Which Video Format Should You Use and Why? Why Every Business Needs An Image Management System All The Questions To Ask During A Dam Demo Which is the Best Image Format for Your Website? Uploading Multiple Files Using JavaScript: A Comprehensive Guide Headless DAM: Why API-Driven Digital Asset Management is the Way Forward
HLS streaming with Video.js + React
Rahul Nanwani · 2025-09-17 · via ImageKit.io Blog

Delivering a seamless video streaming experience online is a non-negotiable for modern web applications. The key to this is Adaptive Bitrate Streaming (ABR), a technology that automatically adjusts video quality to match a user's network conditions.

In this guide, we'll demonstrate-

  1. An actual working VideoJS component for React using VideoJS 8+
  2. Code to use this Video.js player component to deliver YouTube-like Adaptive Bitrate Streaming videos with HLS protocol (m3u8 manifest file) on your websites and apps.
  3. Setting up HLS Quality selector to display quality options and the current stream quality being played by VideoJS.
  4. Setting up playback rates like 1x, 2x, etc. for the player.

We have a working repository of HLS Streaming with VideoJS here. All the code samples in this article are from the same repository.

So let's get started.

Understanding the core technologies

What is HLS?

HTTP Live Streaming (HLS) is the leading ABR protocol. It works by breaking a video into a series of small, short chunks. It then provides an index file, or a manifest file ( with .m3u8 extension), that lists playlists of renditions of varying bitrate and resolution such as 360p, 720p, 1080p, etc. via links. Each child playlist link then lists the different chunks of that specific rendition. The video player's job is to read this manifest and intelligently switch between different quality levels in real-time, downloading the corresponding video chunks to ensure smooth playback without buffering.

Why use Video.js?

Video.js is a popular, open-source HTML5 video player framework. It provides a consistent API across different browsers, allowing you to use a single player for various video formats.

For extended functionality, video.js uses plugins.

Since version 7, Video.js also bundles the videojs-http-streaming (VHS) plugin. This plugin handles HLS streaming on browsers like Chrome and Firefox, where it is not native, while gracefully falling back to native browser support on browsers like Safari. This fallback mechanism ensures broad compatibility with minimal effort on your part.

In this guide, we are using Video.js 8+, which automatically includes videojs-http-streaming (VHS).

Getting started with HLS streaming with Video.js

Step 1: Getting Your HLS Stream from ImageKit

Before you can play an HLS stream, you need one. Suppose you have an MP4 video, you will need to process it to convert it to an HLS stream with the manifest file in M3U8 format. Your original video will be encoded at different bitrates corresponding to 360p, 480p, or other desired resolutions, and the video at each bitrate will then be split into multiple smaller segments. All of these would be put into the M3U8 manifest file that will be supplied to the video player.

While there are several ways in which you can do this, including ffmpeg or other third-party tools, we will use ImageKit's video API for the adaptive streaming feature. It is free to use for a small amount of video processing every month and very easy to use with any video file in your own object storage, like S3, or if you upload files to the integrated Media Library. You can sign up for it here.

You can download the original video file used in this guide from here and upload it to your ImageKit Media Library, or whichever service you are using for HLS encoding.

Assuming your video is available via ImageKit at the following path (the ImageKit ID 'ikmedia' will change for your account)

https://ik.imagekit.io/ikmedia/example_video_train.mp4

You can create the HLS manifest for this video in 360p, 480p, 720p, and 1080p resolutions by appending /ik-master.m3u8?tr=sr-360_480_720_1080 to the end of the URL.

The ik-master.m3u8 instructs ImageKit to create an HLS manifest (m3u8 extension), and the tr=sr- parameter indicates the different video resolutions that should be a part of this manifest.

So our final HLS manifest URL is

https://ik.imagekit.io/ikmedia/example_video_train.mp4/ik-master.m3u8?tr=sr-360_480_720_1080

This single, transformed URL is all you need to play your adaptive stream.

Step 2: Setting Up the Video.js Player in React

For React applications, we need to encapsulate the Video.js player within a React component. It will allow you to manage the player's lifecycle and options using React hooks.

We'll use the following component from our repository: src/components/VideoJS.jsx. The code of the same is copied below as well.

This component handles the following things -

  1. The core logic of initializing and disposing of the Video.js player ensures it integrates cleanly with React's lifecycle.
  2. It accepts the sources option, which is where we will pass the HLS stream.
  3. Other options, such as autoplay, preload, muted, poster, and more, are configured to control player behavior and combined correctly using buildVideoOptions. In this guide, we won't discuss all the options, but only the ones relevant for HLS video streaming in the next section.
  4. It initializes the HLS quality selector and playback speed selector to show or switch the current stream resolution and playback speed, respectively.

The code for this component is quite long. It handles React-specific cases well to become your go-to component for the future to load any HLS streaming videos.

'use client';

import { useEffect, useRef } from "react";
import videojs from "video.js";
import "video.js/dist/video-js.css";

// To provide quality control option in HLS Video
import 'videojs-hls-quality-selector/src/plugin'

/**
 * React wrapper for Video.JS player with HLS streaming support
 * This version creates the video element dynamically to avoid DOM issues
 */
export default function VideoJS({ options, onReady }) {
  const containerRef = useRef(null);
  const playerRef = useRef(null);

  // Build video options
  const buildVideoOptions = () => ({
    controls: options?.controls ?? true,
    autoplay: options?.autoplay ?? false,
    preload: options?.preload ?? 'metadata',
    height: options?.height ?? 400,
    width: options?.width ?? '100%',
    fluid: options?.fluid ?? true,
    responsive: options?.responsive ?? true,
    aspectRatio: options?.aspectRatio ?? '16:9',
    muted: options?.muted ?? true,
    playsinline: true,
    poster: options?.poster,
    sources: options?.sources,
    html5: {
      vhs: {
        enableLowInitialPlaylist: true
      }
    },
    playbackRates: options?.playbackRates || [0.5, 1, 1.25, 1.5, 2],
  });

  // Initialize player effect
  useEffect(() => {
    // Only initialize if we don't have a player and container exists
    if (!playerRef.current && containerRef.current) {
      const containerElement = containerRef.current;
      
      // Create video element dynamically
      const videoElement = document.createElement("video");
      videoElement.classList.add('video-js');
      videoElement.classList.add('vjs-big-play-centered');
      
      // Append to container
      containerElement.appendChild(videoElement);
      
      try {
        // Initialize Video.js player
        const player = videojs(videoElement, buildVideoOptions(), () => {
          
          // Initialize quality selector plugin
          if (player.hlsQualitySelector) {
            player.hlsQualitySelector({ 
              displayCurrentQuality: true
            });
          }

          // Call onReady callback
          if (onReady && typeof onReady === 'function') {
            onReady(player);
          }
        });

        // Store player reference
        playerRef.current = player;

      } catch (error) {
        console.error('VideoJS: Failed to initialize player', error);
      }
    } 
    // Update existing player if options changed
    else if (playerRef.current) {
      const player = playerRef.current;
      const newOptions = buildVideoOptions();

      try {
        // Update source if changed
        const currentSrc = player.currentSrc();
        const newSrc = newOptions.sources[0].src;
        
        if (newSrc && newSrc !== currentSrc) {
          player.src(newOptions.sources);
        }

        // Update other properties
        player.muted(newOptions.muted);
        player.autoplay(newOptions.autoplay);
        player.poster(newOptions.poster);

      } catch (error) {
        console.error('VideoJS: Error updating player', error);
      }
    }
  }, [options, onReady]);

  // Cleanup effect
  useEffect(() => {
    return () => {
      if (playerRef.current && !playerRef.current.isDisposed()) {
        try {
          playerRef.current.dispose();
        } catch (error) {
          console.error('VideoJS: Error during cleanup', error);
        } finally {
          playerRef.current = null;
        }
      }
    };
  }, []);

  return (
    <div 
      ref={containerRef}
      className="video-container" 
      style={​{ 
        width: '100%', 
        maxWidth: options?.maxWidth || '100%',
        backgroundColor: '#000',
        minHeight: options?.height || 150
      }​}
      data-testid="videojs-container"
    />
  );
}

Step 3: Integrating the Video.js component on a page

Now, let's use our VideoJS component on a page. In our example repository, we use it within src/pages/HlsVideoJsStreaming.jsx.

This is where we define the specific options to pass to our player, including the HLS manifest source URL we obtained from ImageKit. The Video.js component has correct default values set for all options; we only have to pass the options we want to modify.

Since we are only covering HLS streaming in this guide, we are passing only a small number of options; however, you have the flexibility to configure more, such as poster, aspect ratio, and others. Some of the more essential options being passed to the component are:

  1. sources helps pass the M3U8 manifest file from ImageKit to the component. It is an array of objects with two properties - one is the HLS stream itself, and the other is the content type 'application/x-mpegURL' which helps indicate to Video.js that the src is a HLS stream
  2. The controls parameter ensures that the player will show the seekbar, play/pause, fullscreen buttons, and more.
  3. autoplay and muted help automatically start the video playback on page load. Modern browsers only autoplay when muted. On iOS, an additional playsinline : true might be needed to avoid full-screen takeovers. Whether or not to automatically start the video playback will depend on your business requirements.
  4. The responsive and fluid options ensure the player scales correctly on different screen sizes.
  5. The final JSX markup to render the Video.js component on the page

If you use some other service for your HLS stream processing, you just need to change the HLS_SRC URL that is provided to the Video.js component.

Our demo player using Video.js + HLS streaming in React
Our demo player using Video.js + HLS streaming in React

The entire page can be found here.

import React from 'react'
import VideoJS from '../components/VideoJS.jsx'

const HLS_SRC = 'https://ik.imagekit.io/ikmedia/example_video_train.mp4/ik-master.m3u8?tr=sr-360_480_720_1080'

export default function HlsVideoJsStreaming() {
  const videoJsOptions = {
    controls: true,
    autoplay: true,
    muted: true,
    preload: 'auto',
    responsive: true,
    fluid: true,
    sources: [{
      src: HLS_SRC,
      type: 'application/x-mpegURL'
    }]
  }

  return (
    <main style={​{ maxWidth: 960, width: '100%', margin: '2rem auto' }​}>
      <h1 style={​{fontSize: '1.25rem', marginBottom: '1rem'}​}>HLS Streaming with Video.js and ImageKit for HLS ABR transformation</h1>
      <VideoJS options={videoJsOptions} />
    </main>
  )
}

Showing quality levels using HLS Quality Selector

You are likely familiar with the YouTube interface, which displays the video stream in the bottom right corner of the player.

By default, Video.js does not show the quality of the stream that is currently playing. To get that functionality, we use the videojs-hls-quality-selector plugin. Version 1.2+ of this plugin is compatible with Video.js 8+. You can see that this plugin is imported in the beginning of the Video.js React component and is then initialized in the same component. The code for initialization has been repeated below, but it is already present in the main Video.js component.

if (player.hlsQualitySelector) {
  player.hlsQualitySelector({ 
    displayCurrentQuality: true
  });
}

Upon adding this plugin, we start seeing the different stream options available to the player, the one currently playing, and allow the user to switch between streams manually if needed.

Quality-level selector for HLS streaming in Video.js
Quality-level selector for HLS streaming in Video.js

💡

Note on Safari: Since Safari natively supports HLS streaming, it doesn't use the plugin videojs-http-streaming (VHS) for the same. Therefore, the plugin for HLS quality selector, which relies on videojs-http-streaming and the quality levels exposed by VHS, doesn't display any quality levels on Safari.

Setting up the Playback Rate in the player

Streaming platforms such as YouTube allow videos to be sped up or slowed down. We can implement a similar functionality with Video.js using the playbackRates option.

//From the main Video.js component
playbackRates: options?.playbackRates || [0.5, 1, 1.25, 1.5, 2],

In our code above, this can be passed either as an option to the component or the defaults of 0.5x, 1x, 1.25x, 1.5x, 2x, get rendered using the default values used in our component.

Different playback rates getting rendered in the player
Different playback rates getting rendered in the player

Testing if Adaptive Streaming is working or not with Video.js?

Now is the time to test of the streaming works as expected or not.

Open the Network tab of Chrome Dev Tools, and use Network Throttling to throttle the network to 'Slow 4G'. The player should automatically start loading a lower bitrate variant like 480p or 360p. When the throttling is removed, the player should return to a more suitable variant.

Segments changing from 720p to 480p to 1080p can be seen in Chrome Dev tools
Segments changing from 720p to 480p to 1080p can be seen in Chrome Dev tools

The above results are a clear indication that our Video.js player with the HLS manifest is correctly adapting to the user's network and device.

Final Thoughts

A functional player we have achieved above is a great start. Adaptive bitrate streaming automatically monitors the user's network to make the best decision for a smooth experience. However, there is more to improving streaming performance, especially when a video begins to stream.

We can further optimize video start time and streaming performance by making a few key configurations, such as controlling the resolution used at the beginning of the video, adjusting the amount of video to buffer, deciding whether to preload video metadata, enabling lazy loading, loading only the video poster and waiting for user interaction to start the video, and more. The right combination of these options can significantly reduce initial video load time, especially for users on slower connections.

You can read more about these settings from the Video.js HTTP Streaming documentation or from the video optimization guide. You can also learn more about ImageKit's Video API here.