Self-host the player
Serve the Video.js HTML player from your own origin for offline, air-gapped, or restricted-network deployments
By default, the installation flow loads the player from a public CDN. For offline, air-gapped, or locked-down deployments, you can serve everything from your own origin instead. Pick one of the options below.
Bundle a single file (recommended)
Install the package, put the player’s imports into an entry file, then let any bundler produce one self-contained module you can host anywhere. For the default video player, that’s:
import '@videojs/html/video/player';
import '@videojs/html/video/skin';npm install @videojs/html
npx esbuild player.js --bundle --format=esm --minify --sourcemap --outfile=public/player.jsLoad the output with type="module":
<script type="module" src="/player.js"></script>You get one file (plus a sourcemap), no runtime requests to a CDN, and only the features you import. Any bundler works (Vite, Rollup, webpack) as long as the output stays ESM.
Download the release archive
Every release ships a videojs-html-<version>.zip (and a .tar.gz) holding the prebuilt player. Use it when your deployment installs dependencies outside npm, or when you want a versioned artifact to vendor into your own repository.
Unpack it into whatever your server treats as static files:
curl -LO https://github.com/videojs/v10/releases/download/@videojs/html@10.0.0-beta.26/videojs-html-10.0.0-beta.26.zip
unzip videojs-html-10.0.0-beta.26.zip -d public/Then point a script tag at the player you want:
<script type="module" src="/videojs-html-10.0.0-beta.26/video.js"></script>The archive holds the same production bundles the CDN serves, minus sourcemaps and development builds. Every path inside it is relative, so it runs from any origin with no outbound requests. SHA256SUMS on the release verifies the download.
For Composer-based projects such as Drupal, declare the archive as a package:
{
"repositories": [
{
"type": "package",
"package": {
"name": "videojs/html",
"version": "10.0.0-beta.26",
"type": "drupal-library",
"dist": {
"type": "zip",
"url": "https://github.com/videojs/v10/releases/download/@videojs/html@10.0.0-beta.26/videojs-html-10.0.0-beta.26.zip"
}
}
}
],
"require": {
"videojs/html": "10.0.0-beta.26"
}
}Composer strips the archive’s top-level directory, so the player lands directly in your libraries path.
Mirror the prebuilt CDN files
To skip the bundler, copy the prebuilt CDN bundle to your server as-is.
npm install @videojs/html
mkdir -p public
cp -r node_modules/@videojs/html/cdn public/videojsThen point the script tag at your copy instead of the CDN:
<script type="module" src="/videojs/video.js"></script>The file name matches your player: video.js, audio.js, background.js, and so on. Every option is present in the cdn/ folder you copied.
Hashed chunk names change between releases, so re-copy the directory whenever you upgrade @videojs/html.
HLS and other media types
HLS and other non-default media need their own module on top of the player. Match it in your self-hosted build:
- Bundle: add the media import to your entry file (
import '@videojs/html/media/hlsjs-video';) and use the matching<hlsjs-video>element with your.m3u8source. - Mirror: serve the media file too and add its script tag (
<script type="module" src="/videojs/media/hlsjs-video.js"></script>).
Without the media module the player UI renders but the video never loads, with no console error.