How to download Vimeo video using JavaScript?

ยท

8 min read

Some time ago, I made the same article but with Python. You can find it here. Some guys asked me to make a similar post, but with JavaScript and NodeJS. So, today I'll teach you how to download a Vimeo video using JavaScript. The article is oriented toward beginners. Welcome undercut.

Attention!

I made this post and this code for learning purposes. I don't recommend it for commercial use. I'm not responsible for any damage caused by this code. Please, don't lawlessly use this code and avoid any illegal activities.

Setup project template

I have NodeJS on my MacBook if you don't, please install it first. Installing NodeJS is out of scope for this post, but if you need some help feel free to ask any questions here or on my Twitter. My NodeJS version is 18.0.0.

The next step is creating an empty directory and initializing npm there. I use terminal commands for that.

mkdir download-vimeo-video-javascript
cd download-vimeo-video-javascript
npm init -y

Those commands create a project directory and initialize it with the default package.json file. By default, index.js is the main file, but I prefer for those kinds of apps to use app.js.

Also, to use ES6 imports, we need to change the package type by putting the "type": "module" option. I usually do it to be able to use "import" instead of "require".

And will be great to have npm command to run our application.

Honestly, this doesn't matter for the current article, but I am showing you what I always do. So, let's edit package.json file.

{
  "name": "download-vimeo-video-javascript",
  "version": "1.0.0",
  "type": "module",
  "description": "",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node app.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

We need to create a file app.js in the same directory and start coding. Finally!

Basic code

Let's make basic code for our app.js file.

'use strict';
const main = async () => {
    console.log('Hello World');
};
const promise = main();
promise.then(() => {
    console.log('Program finished!');
});
promise.catch((err) => {
    console.log('Program finished with error!');
    console.log(err);
});

Let me explain why we make those code.

The first line tells NodeJS we want to use strict mode. Strict mode is out of the scope of this article too. I use it by default because it disallows you to do some not safe things, and also, it shows an error that doesn't appear in no strict mode.

The next block is the initialization async function and putting it inside the variable name. I prefer to have the ability to use async/await constructions. You can put await only inside asynchronous functions. That's why I create the main. Inside the function, we have console.log call with hello world just for testing purposes. We will remove it later.

Below the main function initialization, I put calling of it and promise with then and catch handler. If you want to know more about promises, let me know. I could write an article about that.

Let's test our program. Run the following command.

npn run start

My result is in the screenshot bellow.

hello world nodejs example

Looks like everything is working. Let's move to downloading the video now.

Theory

If you watch any video from Vimeo, your browser downloads it in the background. So, we can do the same, but we need to know the video URL. If we have a video URL, there isn't a problem with downloading it.

I have investigated before, and I know where it is. When you visit Vimeo page, your browser sends one more request with video ID to Vimeo servers, and it gets JSON object with information about the video. There is a video URL too.

Getting Vimeo video ID

Let's take some video for example. I took this one randomly in the previous article. It looks strange, but we don't need to care about content.

Our first goal is to take the ID of the video. Video ID is those numbers at the end of video URL.

    let inputVideoUrl = 'https://vimeo.com/712159936/';

    if (inputVideoUrl.slice(-1) === '/') {
        inputVideoUrl = inputVideoUrl.slice(0, -1);
    }

    const videoId = inputVideoUrl.split('/').pop();
    console.log(videoId);

Maybe you want some additional explanation.

At first, I checked if is there an ending slash inside the input URL. This is required because I want to split the string by "/" char and get the last element or result array (video ID). So, an ending slash could interfere with doing that.

Okay, we have a video ID. What is next?

Getting project JSON config from Vimeo

In my previous article how to download Video video using Python I show screenshots from browser inspection. They illustrate how browser sends an additional request to Vimeo servers and get project JSON config. Let me put them here.

request to vimeo video

request result to vimeo video

As you can see, a browser sends the request to some Vimeo URL and get the JSON configuration of the video. You can't see this on screenshots, but for a request, the browser uses host player.vimeo.com.

Time to make the same.

First, let's import https module. For that just add import on the top of the file import https from 'https'; I like to use async/await contraction, so let's use promises to get our JSON with https module.


    const videoJsonConfigUrl = `https://player.vimeo.com/video/${videoId}/config`;
    const videoConfig = await new Promise((resolve, reject) => {

        https.get(videoJsonConfigUrl, (res) => {

            let result = '';

            res.on('data', data => {
                result += data;
            });

            res.on('error', err => {
                reject(err);
            });

            res.on('end', () => {
                resolve(JSON.parse(result));
            });

        });
    });

    console.log(videoConfig);

Here I put await and create new promise. The main code for getting video is inside the promise. I put data in the result string chunk by chunk and resolve it when the end event is emitted. If some error happens, then my code call rejects.

I put the result on the screenshot.

getting video url from Vimeo

What is the next step?

Download Vimeo video using JavaScript

Each video has different video quality. Each quality item has its own URL. There is a field videoConfig.request.files.progressive. It is an array of objects. Each object represents a video quality item. And, of course, each object has its own URL.

how to download vimeo video using javascript - quality items

Let's ignore quality choosing for now and download the first available one. At first, we need to import module fs. Add this line to the top of file import fs from 'fs';

Now we can implement downloading and finally get that video from Vimeo.


    const videoQualityItems = videoConfig.request.files.progressive;
    const targetItem = videoQualityItems[0];
    const targetVideoFileUlr = targetItem.url;
    const localPath = `./${videoId}-${targetItem.quality}.mp4`;

    await new Promise((resolve, reject) => {

            https.get(targetVideoFileUlr, (res) => {

                const file = fs.createWriteStream(localPath);

                res.pipe(file);

                res.on('error', err => {
                    reject(err);
                });

                res.on('end', () => {
                    resolve();
                });

            });
    });

I used almost the same way to download video, except adding pipe from the input https stream to the output file write stream. This allows us to download a huge file without taking care of memory.

Looks like everything works as excepted.

result of video downloading

Choosing the quality of video

Now, let's say we want to choose the quality of the video. For example, let's take the best one. I use reduce method of the array for that.

    // selecting the best video quality based on height and width
    // you could also add FPS multiplication to get the best quality based on FPS too
    const targetItem = videoQualityItems.reduce((prev, curr) => {
        return prev.width * prev.height > curr.width * curr.height ? prev : curr;
    });

The logic here is very simple. Best quality = bigger amount of pixels. You could also FPS multiplication to get the best quality based on FPS too.

Conclusions

In general downloading video from Vimeo using JavaScript is pretty simple. I hope my article was useful for you. If you have any questions, suggestions, or criticism, please ask them below in the comments or write me directly on Twitter.

I put all code in my GitHub repository in case you need to check the full version.

ย