Video.js 4.9 - Now <audio> can join the party!

HTML5 Audio support

A common request we’ve seen is to be able to use Video.js with an &lt;audio&gt; tag, and now you can! Usage is almost identical, you can just include a data-setup={} attribute on an &lt;audio&gt; tag or initialize via Javascript.

&lt;audio id="audio_example" class="video-js vjs-default-skin" controls 
  preload="auto" width="600" height="600" 
  poster="/img/awesome-album-art.png" data-setup='{}'&gt;
  &lt;source src="/audio/awesome-music.mp3" type='audio/mp3'/&gt;

The only differences in behavior are that the poster image and controls are never hidden. This allows you to keep up something like album art during playback rather than a black video element. Since there’s no interesting content to hide (other than the poster image), we leave the controls showing to mimic a familiar audio player experience.

Audio Screenshot

Note: The Flash fallback still doesn’t support audio-only sources, but we’d like to add that in the future. In the meantime, audio playback with MP3 and Ogg sources should work fine in any (modern) browser that’s not IE8, so enjoy!

More translations!

We’ve been really excited by the continued support in terms of new translations. This release contains Brazilian Portuguese, Japanese, Italian, French, and Korean, as well as some improvements to the previous Spanish translation. We’d love to see the trend continue, so if you’re fluent in a language please consider submitting improvements or whole new localizations!

Video.js in the wild

Coursera is an education platform that offers free courses online from some of the world’s top institutions. They’ve built great tools for video interaction on top of Video.js, and are even going to talk about some of the work they’re doing at October’s SF Video Meetup.

Coursera Screenshot

New Plugins

videojs-wavesurfer - Adds a navigable waveform for audio files, using the excellent wavesurfer.js library.

Full list of changes

  • @deedos added a Brazilian Portuguese translation (view)
  • @baloneysandwiches added a hasClass method (view)
  • @mynameisstephen fixed an issue where slider event listeners were not being cleaned up (view)
  • @alexrqs cleaned up the Spanish translation (view)
  • @t2y added a Japanese translation (view)
  • @chikathreesix fixed an issue where data-setup options could be missed (view)
  • @seniorflexdeveloper added new translations and translation updates (view)
  • @chikathreesix exported the videojs.Flash.embed method (view)
  • @doublex fixed an issue with IE7 backwards compatibility (view)
  • @mmcc made it possible to override the font-size of captions and subtitles (view)
  • @philipgiuliani added an Italian translation (view)
  • @twentyrogersc fixed the return value when setting the poster source (view)
  • @heff updated to swf v4.5.0 to fix event issues (view)
  • @rpless made the VolumeMenuButton volume more accesible via tab navigation (view)
  • @mmcc added support for audio tags (html5 audio only) (view)

Video.js 4.8.0 released...Prost!

This isn’t the flashiest minor release ever, but it’s hot off the press and ready for use. As mentioned in the last (few) release posts, we’re making a concerted effort to be more consistent with releases, so hopefully the trend of bite-sized, scheduled releases will continue.


We only just released localization with version 4.7, but we’ve already had two pull-requests for new translations! The German translation is included with this release, and you’ll find the French translation in the next patch release. If you’re fluent in another language, you can help Video.js be even more internationally accessible by submitting a pull request translating just 24 words / phrases. &lt;/shameless_plug&gt;

Video.js in the wild

Heavybit Industries has a speaker series they host at their office, and they’ve been kind enough to start posting these sessions online in their library. The experience they’ve built using Video.js is impressive, including syncing the video progress with a transcript below the player.

Heavybit Screenshot

New plugins

  • videojs-ass: Adds Advanced SubStation Alpha subtitles support.
  • videojs-hdtoggle: HD button which toggles between HD and non-HD source.

Full list of changes

  • @andekande added a German translation (view)
  • @mattosborn fixed a bug where getting the video element src would overwrite it (view)
  • @songpete fixed a bug where keyboard events were bubbling and causing additional actions (view)
  • @knabar made the inactivity timeout configurable (view)
  • @seniorflexdeveloper added language files to the distribution for including specific languages (view)
  • @gkatsev improved handling of null and NaN dimension values (view)
  • @gkatsev fixed an issue where the controls would break if Flash was initialized too quickly (view)
  • @mmcc fixed an issue where if no playback tech was supported the error could not be caught (view)

Video.js v4.7.0 - Built mostly by NEW contributors! Also Google chooses Video.js

We’re continuing to work hard on improving the contributor experience around the Video.js project and it’s paying off. Over half of the changelog is thanks to brand new contributors! Issues and pull requests are getting addressed faster than ever, and I was even allowed to give a talk at OSCON on some of the strategies we’re using. If you’re instersted in getting involved, join the #videojs IRC room or post an issue to let us know.

Google Chooses Video.js for Google Media Framework

Google recently announced a new framework for building video experiences and monetization. There are versions of the framework for native iOS and Android apps, and for the browser they chose to use Video.js. Check out their video.js plugin, and as it says in their announcement, “Stay tuned as well for a deeper dive into Video.js with IMA soon!”


In this release we’ve built the infrastructure for displaying text in other languages. Examples of text include error messages and text used for accessibility. This feature can extend to plugins as well.

Today you can include other languages by including the JSON translations object from the language you want with the player, like in this example for Spanish (es).

videojs.options.languages['es'] = { [translations object] }

You can find translations files in the lang folder of the project. We don’t have many translations yet, but we’re looking for translators if you’d like to help!

Multiple buffered regions

With HTML5 video you can skip ahead in the video and the browser will start downloading the part of the file needed for the new position, which is different from how Flash video works by default. Flash will download from the start to the end of the file so you can only skip ahead once it has download that part of the video.

In the HTML5 video API we’re given the buffered property which returns a list of time ranges that the browser has downloaded data for. Early on in HTML5 video, browsers only ever reported one time range, but now we have a direct view of what’s been downloaded.

In the newest version of the video.js skin you can see the specific regions.

We’ve kept it subtle so it’s not too big of a change. We’d love to hear your thoughts on it.

DASH Everywhere-ish

If you haven’t seen it yet, check out the post on Tom Johson’s work getting DASH supported in Video.js, using Flash or the new Media Source Extensions. MPEG-DASH is an adaptive streaming format that Netflix and YouTube are using to stream video to cutting-edge browsers. It has the potential to replace Apple’s HTTP Live Streaming format as the main format used for adaptive streaming.

Video.js on Conan!

Conan O’Brien’s TeamCoco site is using Video.js with a nicely customized skin and ads integration. Check it out!

New Skin by Cabin

The team at Cabin put together a simple and clean new skin for video.js.

New Plugins

A lot of great new plugins have been released!

  • videojs-ima: Easily integrate the Google IMA SDK into Video.js to enable advertising on your video content.
  • videojs-brightcoveAnyaltics: Allow tracking of views/impressions & engagement data in videojs for Brightcove videos
  • videojs-logobrand: Add a logo/brand image to the player that appears/disappears with the controls. (also useful as a basic plugin template for learning how Video.JS plugins work.)
  • videojs-seek: Seeks to a specific time point specified by a query string parameter.
  • videojs-preroll: Simple preroll plugin that displays an advertisement before the main video
  • videojs-framebyframe: Adds buttons for stepping through a video frame by frame
  • videojs-loopbutton: Adds a loop button to the player
  • videojs-ABdm: Use CommentCoreLibrary to show comments (which is called as DanMu) during playing.
  • videojs-hotkeys: A plugin for Video.js that enables keyboard hotkeys when the player has focus.

New Release Schedule

As part of improving the contributor experience we’re moving to scheduled releases. We’ll now put out a release every other Tuesday as long as there’s new changes to release. This will help give everyone a better idea of when specific features and fixes will become available.

Full list from the change log

  • Added cross-browser isArray for cross-frame support. fixes #1195 (view)
  • Fixed support for webvtt chapters. Fixes #676. (view)
  • Fixed issues around webvtt cue time parsing. Fixed #877, fixed #183. (view)
  • Fixed an IE11 issue where clicking on the video wouldn’t show the controls (view)
  • Added a composer.json for PHP packages (view)
  • Exposed the vertical option for slider controls (view)
  • Fixed an error when disposing a tech using manual timeupdates (view)
  • Exported missing Player API methods (remainingTime, supportsFullScreen, enterFullWindow, exitFullWindow, preload) (view)
  • Added a base for running saucelabs tests from grunt (view)
  • Added additional browsers for saucelabs testing (view)
  • Added support for listening to multiple events through a types array (view)
  • Exported the vertical option for the volume slider (view)
  • Fixed Component trigger function arguments and docs (view)
  • Now copying all attributes from the original video tag to the generated video element (view)
  • Added files to be ignored in the bower.json (view)
  • Fixed an error that could happen if Flash was diposed before the ready callback was fired (view)
  • The up and down arrows can now be used to control sliders in addition to left and right (view)
  • Added a player.currentType() function to get the MIME type of the current source (view)
  • Fixed a potential conflict with other event listener shims (view)
  • Added support for multiple time ranges in the load progress bar (view)
  • Added vjs-waiting and vjs-seeking css classnames and updated the spinner to use them (view)
  • Now restoring the original video tag attributes on a tech change to support webkit-playsinline (view)
  • Fixed an issue where the user was unable to scroll/zoom page if touching the video (view)
  • Added “sliding” class for when slider is sliding to help with handle styling (view)



Discuss on Twitter | Discuss on Hacker News

DASH Everywhere-ish (hack project)

A couple of times a year Brightcove has an internal hackweek where engineers work on any project they’d like. In the latest hackweek (2014-07-14) Tom Johnson decided to see if he could get DASH supported in as many places as possible, by combining a few of the existing DASH player implementations with Video.js.

MPEG-DASH (Dynamic Adaptive Streaming over HTTP) is a streaming format similar to Apple’s HTTP Live Streaming (HLS). It allows you to provide multiple versions of a video at different bitrates, and then the player can switch between those versions depending on the user’s bandwidth (which is more complicated than you might think).

The two DASH playback implementations used were Dash.js and They were combined using video.js’s playback tech architecture, which means you can include plugins and custom skins and they’ll work the same with either playback method.

See the results.

Browser/Device Coverage

Using a combination of DASH.AS and DASH.JS will give us the following browser/device coverage:

DASH.JS (media source extensions support)

  • Internet Explorer: 11+
  • Chrome: 23+
  • FireFox: 25+ (upcoming version)
  • Safari (Desktop): 8+ (OSX Yosemite - Fall 2014)
  • iOS: No
  • Android: 4.2+ (Chrome)


Fallback to any environment that supports Flash Player 10.3


As you can see, the one remaining holdout is iOS and there’s currently no word when or if that will happen. Seeing media source extensions support in Safari 8 gives some hope, but my understanding is the requirements for getting support built into iOS are much more significant. My guess is it will happen eventually, but not for a while (and hopefully in-line playback + the fullscreen API will be supported at the same time).

Today, to provide adaptive streaming everywhere, you still need either DASH + HLS, or just HLS (you can use the video.js HLS plugin to support HLS in more browsers).

Tom’s Notes

The demo shows that for environments which support Media Source Extensions (MSE) we use a full Javscript implementation via Dash.js and as a fallback we use Flash built around OSMF and, an open-source plugin provided by Castlabs.

Tom has been working on videojs-osmf on the side, which helped make this possible.

DASH.AS Requirements


  • Environment must support Flash Player 10.3+
  • Video.js OSMF Tech (videojs-osmf)
  • CastLabs Dash.AS plugin for OSMF (


  • Since the requests are fired from within Flash, a crossdomain.xml file is required.* Ability to serve byte range requests via query string (myFile.mp4?range=0-1000 || myFile.m4s?bytes=0-1000) is necessary because Flash Player restricts use of the ‘Range’ request header. Castlabs has an .htaccess file which uses mod_rewrite to achieve this. Akamai edge servers accept the bytes query string var as well.


  • Something we may want to modify is handling the request/response portions of the workload outside of the Flash Player similar to the Video.js HLS solution. This would remove the need for having a crossdomain.xml, which cannot be normally expected to exist in a DASH focused environment.
  • Akamai edgesuite appear to be an exception to the above rule, as those domains do in fact have the crossdomain from it’s use as a serving platform under Akamai HD. The Akamai param syntax is ‘myFile.m4s?bytes=XXXX-YYYY’.
  • In it’s current form the Dash.AS manifest parser is very rigid. We may want to look into implementing a version of the DASH.JS manifest parsing on the AS side, as it is a lot more flexible in terms of structure recognition.
  • Deeper class inspection shows that the Dash.AS plugin is based on using Netstream in data generation mode, similar to our HLS solution. There may be better way to share the codebase between the two to reduce code duplication.

DASH.JS Requirements



  • Open CORS headers: Access-Control-Allow-Origin: *
  • Accept use of the Range request header: Access-Control-Allow-Headers:Range, Options


  • Dash.js MPD parsing is significantly more robust in comparison to the Dash.AS solution.
  • Most streams tested are Akamai based, we should probably try more local and non-Akamai hosted options moving forward.* In my testing I did see a Youtube DASH/MSE example, and those streams were confirmed to work within Dash.JS as well.
  • Dash.JS streaming lifecycle and segment loading lifecycle tend to be directly coupled and don’t necessarily fire the element media events at the time expected. For example is duration. While known at the parse complete stage of the manifest load cycle, is not reported to the player until the first of the segments is received.

Tech Compatibility

The independant techs work well together. A slight modification had to be made to the Dash.AS library to insure that it only checked for resources which 1. had a URL and 2. url contained the file extension of either ‘mpd’ or ‘m4s’ for DASH manifests/segments.

NOTE: Dash.JS tech should be loaded into DOM prior to OSMF tech to insure the OSMF tech is the fallback scenario for DASH playback.

Video.js version 4.6.0 released! It's been a productive month.

The video.js community has been in full force lately and it’s resulted in a lot of great features and fixes, including UI updates, better error messages, and even a Video.js Polymer element built by Addy Osmani himself.

New Live UI

Video.js has supported different forms of live video for a while, but a recent update has made the user experience a little clearer. Specifically, a ‘LIVE’ badge is added to the controls and the seek bar is hidden when seeking isn’t permitted.

Clearer Errors

A big effort went into improving error situations that developers and viewers might encounter. In cases where the viewer’s browser supports neither JavaScript nor HTML5 Video, a more helpful message is shown that informs the viewer how they can support video playback.

In cases where a common media error occurs (e.g. the file doesn’t exist or the network fails), an “X” icon is displayed showing that playback can’t continue, and a message is shown describing the issue. Additionally an error message is logged to the javascript console.

For developers, better logging functions have been added including videojs.log.error(), and they’re being used throughout the code base to provide better information and help track down issues.

IE11 Fullscreen

Video.js relies on native browser fullscreen even when Flash is used. IE11 is the first version of Internet Explorer to support native browser fullscreen, and video.js has now been updated to take advantage of that feature and provide a better fullscreen experience for those users.

Playback Rate Switching

If you ever wanted to speed up or slow down the rate of a video, now you can! HTML5 video browsers have been adding support for playback rate switching, and video.js now has an optional UI component that will let you select the speed. Flash however does not support playback rate switching, so unfortunately it’s not a feature that users on older browsers (e.g. IE8) can use.

See a demo.

New community plugins

The latest plugins to be added to the video.js plugins list.

  • videojs-vr: Project video onto different geometric shapes (Sphere, Cube, Cylinder) and view in 3d with optional Oculus Rift support
  • video-speed: Adds customizable video-speed control
  • OpenVideoAnnotation - create annotations in video-js using annotator
  • videojs-overlay: display simple HTML overlays during video playback
  • video.js-polymer: A video.js element for the Polymer web components framework

If you’d like a head-start on the scaffolding for a new video.js plugin, check out the Yeoman video.js plugin generator.

Full list from the change log

  • Updated the UI to support live video (view)
  • The UI now resets after a source change (view)
  • Now assuming smart CSS defaults for sliders to prevent reflow on player init (view)
  • Fixed the title element placement in menus (view)
  • Fixed title support for menu buttons (view)
  • Fixed extra mousemove events on Windows caused by certain apps, not users (view)
  • Fixed error due to undefined tech when no source is supported (view)
  • Fixed the progress bar not finishing when manual timeupdate events are used (view)
  • Added a more informative and styled fallback message for non-html5 browsers (view)
  • Added the option to provide an array of child components instead of an object (view)
  • Fixed casing on webkitRequestFullscreen (view)
  • Made tap events on mobile less sensitive to touch moves (view)
  • Fixed the default flag for captions/subtitles tracks (view)
  • Fixed compilation failures with LESS v1.7.0 and GRUNT v0.4.4 (view)
  • Added better error handling across the library (view)
  • Updated captions/subtiles file fetching to support cross-origin requests in older IE browsers (view)
  • Added support for playback rate switching (view)
  • Fixed an issue with the loadstart event order that caused the big play button to not hide (view)
  • Modernized the fullscreen API and added support for IE11 (view)
  • Added cross-browser testing with SauceLabs, and added Karma as the default test runner (view)
  • Fixed saucelabs integration to run on commits in TravisCI (view)
  • Added a clearer error message when a tech is undefined (view)
  • Added a cog icon to the font icons (view)
  • Added a player option to offset the subtitles/captions timing (view)

The new version is available on and has been added to the CDN.



Video.js version 4.5.0 released! Nothing to see here, move along

Well, sort of… this release is the result of a lot of hard work to speed up the version release process, meaning they’ll be coming a lot faster now with smaller sets of changes.

In this release we’ve added support for the Component(1) package manager, fixed the captions positioning when the controls are hidden, and helped Android devices know when they can support HLS. ;-) There were a few other changes as well but a lot of the work this round was done on the processes around the project. If you’ve spent time in the github issues, you’ll hopefully notice an improvement in the response rate on issues and the speed in which bugs get fixed.

New plugins

  • videojs-vast: A VideoJS plugin to play pre-roll videos from a VAST feed
  • videojs-comscore: Reports to comScore using their latest Streaming Tag SDK

Video.js in the wild

Toyota Europe! (click a video on that page) I was in Paris a few weeks ago and stopped by the Toyota store on Champs-Elysées. Next to the cars are multimedia touch screens that tell you details and allow you to watch videos. The video player looked kind of familiar, and sure enough it was video.js with a very nice custom skin. It turns out the Toyota Europe website uses video.js as well. Very cool.

If you find video.js on an interesting site somewhere, let us know in the comments.

Full list from the change log

  • Added component(1) support (view)
  • Captions now move down when controls are hidden (view)
  • Added the .less source file to the distribution files (view)
  • Changed src() to return the current selected source (view)
  • Added a grunt task for opening the next issue that needs addressing (view)
  • Fixed Android 4.0+ devices’ check for HLS support (view)

The new version is available on and has been added to the CDN.



Video.js version 4.4.0 released - Now supporting RequireJS and Browserify

Version 4.4.0 is here with over 20 updates and fixes. The most notable addition may be support for AMD and CommonJS module loaders, meaning you can now include Video.js using RequireJS or Browserify. Video.js can be installed through npm already, and we’ll soon add support for bower and component(1) as well.

New plugins

The plugin list continues to grow, with more in the works. Checkout the new endcard plugin built by The Onion.

Video.js in the wild

The Brightcove Play 2014 website recently went live with Video.js as the player. We’re also hard at work building Brightcove’s next-gen player with Video.js at the core, so stay tuned.

Full list from the changelog

  • Made the poster updateable after initialization (view)
  • Exported more textTrack functions (view)
  • Moved player ID generation to support video tags with no IDs (view)
  • Moved to using QUnit as a dependency (view)
  • Added the util namespace for public utility functions (view)
  • Fixed an issue with calling duration before Flash is loaded (view)
  • Added player methods to externs so they can be overridden (view)
  • Fixed html5 playback when switching between media techs (view)
  • Fixed Firefox+Flash mousemove events so controls don’t hide permanently (view)
  • Fixed a test for touch detection (view)
  • Updated the src file list for karma tests (view)
  • Added more tests for API properties after minification (view)
  • Updated projet to use npm version of videojs-swf (view)
  • Added support for dist zipping on windows (view)
  • Fixed iOS fullscreen issue (view)
  • Fixed touch event bubbling (view)
  • Fixed ARIA role attribute for button and slider (view)
  • Fixed and issue where a component’s dispose event would bubble up (view)
  • Quieted down deprecation warnings (view)
  • Update seek handle to display the current time (view)
  • Added requirejs and browserify support (UMD) (view)

The new version is available on and has been added to the CDN.



Video.js version 4.3.0 released w/ shiny new API docs

The biggest change in this update is actually an overhaul of the API docs. The best example of the new docs is the Player doc, which is the API most video.js users will work with.

The new docs are now automatically generated from the code and code comments, making it easier to keep them up to date with what’s currently in the codebase.

One interesting note about the doc-generator is that it uses esprima, a tool that reads javascript files and gives back the “abstract syntax tree” of the code.

For the following javascript:

var hi;

Esprima would generate:

    "type": "Program",
    "body": [
            "type": "VariableDeclaration",
            "declarations": [
                    "type": "VariableDeclarator",
                    "id": {
                        "type": "Identifier",
                        "name": "hi"
                    "init": null
            "kind": "var"

We’re using the AST of the video.js codebase to generate the majority of the information in the docs, which means it requires fewer comments and less work to keep the docs really great as we continue to build. If you’re interested in seeing how we’re handling that, check out the doc-generator repo (it’s currently only useful with the video.js codebase, but it could be extended to support more).

New CSS Options

Additional updates include new loading spinner icon options, and a new class for centering the big play button.

Many users have been clear that they’d prefer the big play button in the center of the video. While we feel the trend is still moving towards getting the play button out of the way of the content, we wanted to make this feature easier to customize. You can now use the vjs-big-play-centered class on your video tag to center the play button.

To try the new spinner icon options, check out the designer and change the icon name used by the spinner class.

Even more plugins!

Finally, the most exciting developments are actually happening in the video.js community, with more and more plugins being built. We’re up to 26 in the plugins list, with more on the way.

If you have some code you’ve built on top of video.js that you think might be valuable to others, please share it on the plugins list, or post an issue on the video.js repo if you have questions about the plugin process.

Full list from the changelog

  • Added Karma for cross-browser unit testing (view)
  • Unmuting when the volume is changed (view)
  • Fixed an accessibility issue with the big play button (view)
  • Exported user activity methods (view)
  • Added a classname to center the play button and new spinner options (view)
  • Added API doc generation (view)
  • Added support for codecs in Flash mime types (view)

The new version is available on and has been added to the CDN.



The Guardian uses Video.js in feature article

It’s always nice to find Video.js in the wild, but this article from The Guradian is an especially cool use case. Most of the players don’t use controls at all, but rather play/pause based on the user scrolling the page. The ones that do use controls are styled with a white on light gray theme that matches the rest of the page really well.

The article begins with a full-width video that includes controls.
Big Player

Most of the videos are short dialogs that are triggered based on scrolling to a certain point in the page. These have no controls other than an external play/pause button.
No Controls

Smaller player with controls.
Small Player

4.2.2 Patch Release

Two bugs have been squashed with this patch:

  • An issue most commonly seen in Firefox where video playback would break when a race condition would occur during video loading (#756)
  • An issue where the duration would get stuck at 0:00 when loading the player dynamically (#775)

See the changes made

This version can be downloaded on, is available on the CDN, and the existing /4.2/ CDN version has been updated to 4.2.2. (may take time to propagate to your area)