Sign Up for Free

RunKit +

Try any Node.js package right in your browser

This is a playground to test code. It runs a full Node.js environment and already has all of npm’s 400,000 packages pre-installed, including ytdl-core with all npm packages installed. Try it out:

var ytdlCore = require("ytdl-core")

This service is provided by RunKit and is not affiliated with npm, Inc or the package authors.

ytdl-core v3.2.1

Youtube video downloader in pure javascript.


Dependency Status codecov Discord

Yet another youtube downloading module. Written with only Javascript and a node-friendly streaming interface.


You can contact us for support on our chat server


const fs = require('fs');
const ytdl = require('ytdl-core');
// TypeScript: import ytdl from 'ytdl-core'; with --esModuleInterop
// TypeScript: import * as ytdl from 'ytdl-core'; with --allowSyntheticDefaultImports
// TypeScript: import ytdl = require('ytdl-core'); with neither of the above



ytdl(url, [options])

Attempts to download a video from the given url. Returns a readable stream. options can have the following keys

  • quality - Video quality to download. Can be an itag value, a list of itag values, or highest/lowest/highestaudio/lowestaudio/highestvideo/lowestvideo. highestaudio/lowestaudio/highestvideo/lowestvideo all prefer audio/video only respectively. Defaults to highest, which prefers formats with both video and audio.

    A typical video's formats will be sorted in the following way using quality: 'highest'

    itag container quality codecs                 bitrate  audio bitrate
    18   mp4       360p    avc1.42001E, mp4a.40.2 696.66KB 96KB
    137  mp4       1080p   avc1.640028            4.53MB
    248  webm      1080p   vp9                    2.52MB
    136  mp4       720p    avc1.4d4016            2.2MB
    247  webm      720p    vp9                    1.44MB
    135  mp4       480p    avc1.4d4014            1.1MB
    134  mp4       360p    avc1.4d401e            593.26KB
    140  mp4               mp4a.40.2                       128KB

    format 18 at 360p will be chosen first since it's the highest quality format with both video and audio.

  • filter - Used to filter the list of formats to choose from. Can be audioandvideo to filter formats that contain both video and audio, video to filter for formats that contain video, or videoonly for formats that contain video and no additional audio track. Can also be audio or audioonly. You can give a filtering function that gets called with each format available. This function is given the format object as its first argument, and should return true if the format is preferable.

    // Example with custom function.
    ytdl(url, { filter: format => format.container === 'mp4' })
  • format - Primarily used to download specific video or audio streams. This can be a specific format object returned from getInfo.

    • Supplying this option will ignore the filter and quality options since the format is explicitly provided.
  • range - A byte range in the form {start: INT, end: INT} that specifies part of the file to download, ie {start: 10355705, end: 12452856}. Not supported on segmented (DASH MPD, m3u8) formats.

    • This downloads a portion of the file, and not a separately spliced video.
  • begin - What time in the video to begin. Supports formats 00:00:00.000, 0ms, 0s, 0m, 0h, or number of milliseconds. Example: 1:30, 05:10.123, 10m30s.

    • For live videos, this also accepts a unix timestamp or Date object, and defaults to
    • This option is not very reliable for non-live videos, see #129, #219.
  • liveBuffer - How much time buffer to use for live videos in milliseconds. Default is 20000.

  • requestOptions - Anything to merge into the request options which miniget is called with, such as headers.

  • highWaterMark - How much of the video download to buffer into memory. See node's docs for more. Defaults to 512KB.

  • dlChunkSize - The size of the download chunk in bytes. When the chosen format is video only or audio only, the download in this case is separated into multiple chunks to avoid throttling. Defaults to 10MB.

  • lang - The 2 character symbol of a language. Default is en.

Event: info

Emitted when the video's info is fetched, along with the chosen format to download.

Event: progress

  • number - Chunk byte length.
  • number - Total bytes or segments downloaded.
  • number - Total bytes or segments.

Emitted whenever a new chunk is received. Passes values describing the download progress.

miniget events

All miniget events are forwarded and can be listened to from the returned stream.


Call to abort and stop downloading a video.

async ytdl.getBasicInfo(url, [options])

Use this if you only want to get metainfo from a video.

async ytdl.getInfo(url, [options])

Gets metainfo from a video. Includes additional formats, and ready to download deciphered URL. This is what the ytdl() function uses internally.

ytdl.downloadFromInfo(info, options)

Once you have received metadata from a video with the ytdl.getInfo function, you may pass that information along with other options to this function.

ytdl.chooseFormat(formats, options)

Can be used if you'd like to choose a format yourself with the options above. Throws an Error if it fails to find any matching format.

// Example of choosing a video format.
let info = await ytdl.getInfo(videoID);
let format = ytdl.chooseFormat(info.formats, { quality: '134' });
console.log('Format found!', format);

ytdl.filterFormats(formats, filter)

If you'd like to work with only some formats, you can use the filter option above.

// Example of filtering the formats to audio only.
let info = await ytdl.getInfo(videoID);
let audioFormats = ytdl.filterFormats(info.formats, 'audioonly');
console.log('Formats with only audio: ' + audioFormats.length);


Returns true if the given string satisfies YouTube's ID format.


Returns true if able to parse out a valid video ID.


Returns a video ID from a YouTube URL. Throws an Error if it fails to parse an ID.


Same as the above ytdl.getURLVideoID(), but can be called with the video ID directly, in which case it returns it. This is what ytdl uses internally. Throws an Error if it fails to parse an ID.


ytdl cannot download videos that fall into the following

  • Regionally restricted (requires a proxy)
  • Private (if you have access, requires cookies)
  • Rentals (if you have access, requires cookies)

Generated download links are valid for 6 hours, for the same IP address.

Handling Separate Streams

Typically 1080p or better video does not have audio encoded with it. The audio must be downloaded separately and merged via an appropriate encoding library. ffmpeg is the most widely used tool, with many Node.js modules available. Use the format objects returned from ytdl.getInfo to download specific streams to combine to fit your needs. Look at example/ffmpeg.js for an example on doing this.

What if it stops working?

Youtube updates their website all the time, it's not that rare for this to stop working. If it doesn't work for you and you're using the latest version, feel free to open up an issue. Make sure to check if there isn't one already with the same error.

If you'd like to help fix the issue, look at the type of error first. If you're getting the following error

Could not extract signature deciphering actions

Run the tests at test/irl-test.js just to make sure that this is actually an issue with ytdl-core.

mocha test/irl-test.js

These tests are not mocked, and they try to start downloading a few videos. If these fail, then it's time to debug.

For getting started with that, you can look at the extractActions() function in /lib/sig.js.


npm install ytdl-core@latest

Or for Yarn users:

yarn add ytdl-core@latest

Make sure you're installing the latest version of ytdl-core to keep up with the latest fixes.

If you're using a bot or app that uses ytdl-core such as ytdl-core-discord or discord-player, it may be dependent on an older version. To update its ytdl-core version, you'll have to fork the project and update its package.json file, you can't simply change the version on your project's package.json, the app will still use its own older version of ytdl-core.

You can then submit a pull request to their project and point to your fork temporarily. You can also check their pull request and check if there's one open already, and point to that instead. To point to a github's repo's branch in your package.json, you can do

  "ytdl-core-discord": "amishshah/ytdl-core-discord#dependabot/npm_and_yarn/ytdl-core-2.0.1"

Related Projects

  • ytdl - A cli wrapper of this.
  • pully - Another cli wrapper of this aimed at high quality formats.
  • ytsr - YouTube video search results.
  • ytpl - YouTube playlist and channel resolver.


Tests are written with mocha

npm test


RunKit is a free, in-browser JavaScript dev environment for prototyping Node.js code, with every npm package installed. Sign up to share your code.
Sign Up for Free