Select Video.js subtitle track automatically

We at Dotsub are using videojs as video player for our sites. One of the Video.js main benefits is customizability via its plugin system. Recently we had a need to automatically select certain subtitle track after user started video on Video.js player. This is handy when we know the language user is most probably going to need translation into. So we created simple open-source plugin to save few user clicks needed for selecting default subtitle track.

The plugin was named videojs-select-subtitle and is hosted on Github. Assuming you know how to use Video.js plugin for you video player, we jump straight to explaining how to configure this new plugin.


Most modern JavaScript projects are using some kind of Node.JS based build process with NPM dependency management. So easiest way to install plugin is to use NPM:

npm i --save videojs-select-subtitle

Your other option is to clone Github project build the project with command:

npm run build

This command creates JavaScript files in sub-directory dist. You can include minified or non-minified version of JavaScript plugin file into your project with whatever mechanism you are used to.


After after videojs player is initialized and plugin is installed in our project, we can execute it with command:

player.selectSubtitle({ trackLanguage: 'es' });

Object passed as parameter into selectSubtitle function is option required by plugin to select correct subtitle/caption track. Options object has to have trackLanguage key and value needs to define language attribute of caption/subtitle track to be selected. Of course such track must be available in videojs player, otherwise plugin can’t select it at all. Both key and value of options object are case sensitive.

Usage on Brightcove Video Cloud

Video.js project was created by Brightcove. Therefore they made it very easy to embed Video.JS plugins into their Video Cloud service. If you are using this service as your online video platform, you can install videojs-subtitle-plugin via their UI.

In order to do this, you need to host built plugin file somewhere on the internet. After plugin is accessible by Brightcove Video Cloud, you can refer to it from your Brightcove player. It is important to configure name of the plugin to selectSubtitle and trackLanguage option for the plugin:




After the user starts video, plugin finds desired caption/subtitle track and show it automatically.

Creating a videojs plugin

At Dotsub we work with a lot of video. For the last couple years we have been using videojs as our sites main video player. This week I’ve been updating some of our plugins to the latest videojs version (5.9.2) and also open sourcing them!

This week lets walk through how to create a videojs plugin. We’ll make a simple watermark plugin that displays the company logo on a video.

Getting Started

The folks at videojs do provide a yeoman generator as an initial starting point. You can check out that project here:

To create the initial framework just install and run the generator.

$ npm install -g yo generator-videojs-plugin
$ yo videojs-plugin

I enabled the following for the watermark plugin.

    "bcov": false,
    "scope": "",
    "name": "watermark",
    "description": "Adds a watermark image the video player",
    "author": "Brooks Lyrette ",
    "license": "apache2",
    "changelog": true,
    "sass": true,
    "docs": false,
    "lang": false,
    "bower": false

You now have a ready to go project that uses `grunt` to build, `karma` and `qunit` to test. The plugin code is under `src/plugin.js` and `src/plugin.scss`.

You can make sure everything is working fine by typing `npm test` in your console.

Note: If you need to be able to use ES6 imports check this out:

### Making the plugin do something

Now comes the fun part, making the plugin do something useful. The requirements are pretty simple for this plugin:

  • Show a configured image in the video player.
  • When the video is played for the first time wait the pre configured number of seconds to fade the logo out.
  • After the initial fade out, the logo should be shown when the player’s controls are shown.
  • The logo can be a clickable link.
  • The logo position should be configurable (the four corners).

Defaults, Options and configuration.

Videojs provides a nice way deal with configuration. As the plugin developer you can provide a set of `defaults`, the user will input their settings using `options` and you can merge the two using a function the provide called: `videojs.mergeOptions(defaults, options);`. Based on the requirements our plugin will use the following settings with these defaults:

const defaults = {
  position: 'top-right',
  fadeTime: 3000,
  url: undefined,
  image: undefined

image: The URL to the image to be used as the watermark.

position: The location to place the watermark (top-left, top-right, bottom-left, bottom-right). Defaults to ‘top-right’.

fadeTime: The amount of time in milliseconds for the initial watermark fade. Defaults to 3000.

url: A url to be linked to from the watermark. If the user clicks the watermark the video will be paused and the link will open in a new window.

Coding the plugin

We’ll need some DOM elements added to the video player. If you look at the generated code in `src/plugin.js` you’ll see there is already a function listing for `onPlayerReady`. This is where we will add the needed DOM elements. `onPlayerReady` is an event videojs throws when the player is setup and ready to go.

const watermark = function(options) {
  this.ready(() => {
    onPlayerReady(this, videojs.mergeOptions(defaults, options));

Let’s add a call to a new function `setupWatermark(player, options);`. In that function lets setup the required DOM.

const onPlayerReady = (player, options) => {

  // if there is no image set just exit
  if (!options.image) {
  setupWatermark(player, options);

As you see above we exit if there is not image configured. If there is one we continue on and set up the DOM. The setup ends up looking like:

const setupWatermark = (player, options) => {
  // Add a div and img tag
  const videoEl = player.el();
  const div = document.createElement('div');
  const img = document.createElement('img'); = 'vjs-watermark';
  img.src = options.image;

  // if a url is provided make the image link to that URL.
  if (options.url) {
    const a = document.createElement('a');

    a.href = options.url;
    // if the user clicks the link pause and open a new window
    a.onclick = (e) => {
  } else {

We only add a `a` tag if there was a url provided in the configuration. To handle the logo positions we have a CSS class for each location. Let’s write the SCSS for the plugin. We will us absolute positioning for the image container.

// Sass for videojs-watermark
.video-js {
  &.vjs-watermark {
    display: block;
  .vjs-watermark-content {
    opacity: 0.99;
    position: absolute;
    padding: 5px;

  // pre-defined positions
  .vjs-watermark-top-right {
    right: 0;
  .vjs-watermark-top-left {
    left: 0;
  .vjs-watermark-bottom-right {
    right: 0;
    bottom: 30px;
  .vjs-watermark-bottom-left {
    left: 0;
    bottom: 30px;

For the bottom logo positions the `30px` of padding is to account for the height of the controlbar.

We’ve covered almost all of the requirements, you can configure the image, its location and an optional URL to link to.

Implementing fade out

We will want the logo to fade in and out. This will look smoother than having it just disappear. We will do this using CSS transitions. To do this we will animate the opacity from 1 to 0 over 1 second.

Since one of the requirements is that the logo remains visible on the initial play we can use a timeout to wait the correct amount of time.

const onPlayerReady = (player, options) => {
  player.on('play', () => fadeWatermark(options));

const fadeWatermark = (options) => {
    () => document.getElementById('vjs-watermark').classList.add('vjs-watermark-fade'),

Once the `vjs-watermark-fade` fade class is attached to the element it will start fading in and out. For the SCSS I recommend using a mixin that covers all the browser prefixes.

// cross browser mixin
@mixin transition($args...) {
  -webkit-transition: $args;
  -moz-transition: $args;
  -ms-transition: $args;
  -o-transition: $args;
  transition: $args;

// Sass for videojs-watermark
.video-js {
  &.vjs-watermark {
    display: block;
  .vjs-watermark-content {
    opacity: 0.99;
    position: absolute;
    padding: 5px;
    @include transition(visibility 1.0s, opacity 1.0s);
  //fade out when the user is not active and the video is playing.
  &.vjs-user-inactive.vjs-playing .vjs-watermark-fade {
   opacity: 0;

There you have it. A working simple videojs watermark plugin. You can check out the completed project here: (Apache 2.0 licenced)

The final version includes Qunit tests and ES6 support.