Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

youtubei.js

Package Overview
Dependencies
Maintainers
1
Versions
124
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

youtubei.js

Full-featured wrapper around YouTube's private API. Supports YouTube, YouTube Music and YouTube Studio (WIP).

  • 2.7.0
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
27K
increased by27.57%
Maintainers
1
Weekly downloads
 
Created
Source

YouTube.js

A full-featured wrapper around the InnerTube API, which is what YouTube itself uses

Tests NPM Version Codefactor Downloads Discord Say thanks
Donate

Special thanks to:

SerpApi
Scrape Google and other search engines from a fast, easy and complete API.

Table of Contents
  1. About
  2. Getting Started
  3. Usage
  4. Extending the library
  5. Contributing
  6. Contact
  7. Disclaimer
  8. License

Description

InnerTube is an API used by all YouTube clients. It was created to simplify the deployment of new features and experiments across the platform1. This library handles all the low-level communication with InnerTube, providing a simple, and efficient way to interact with YouTube programmatically. It is designed to emulate an actual client as closely as possible, including how API responses are parsed.

If you have any questions or need help, feel free to reach out to us on our Discord server or open an issue here.

Getting Started

Prerequisites

YouTube.js runs on Node.js, Deno, and modern browsers.

It requires a runtime with the following features:

Installation

# NPM
npm install youtubei.js@latest

# Yarn
yarn add youtubei.js@latest

# Git (edge version)
npm install github:LuanRT/YouTube.js

TODO: Deno install instructions (esm.sh possibly?)

Usage

Create an InnerTube instance:

// const { Innertube } = require('youtubei.js');
import { Innertube } from 'youtubei.js';
const youtube = await Innertube.create();

Browser Usage

To use YouTube.js in the browser you must proxy requests through your own server. You can see our simple reference implementation in Deno in examples/browser/proxy/deno.ts.

You may provide your own fetch implementation to be used by YouTube.js. Which we will use here to modify and send the requests through our proxy. See examples/browser/web for a simple example using Vite.

// Pre-bundled version for the web
import { Innertube } from 'youtubei.js/bundle/browser';
await Innertube.create({
  fetch: async (input: RequestInfo | URL, init?: RequestInit) => {
    // Modify the request
    // and send it to the proxy

    // fetch the URL
    return fetch(request, init);
  }
});

Streaming

YouTube.js supports streaming of videos in the browser by converting YouTube's streaming data into an MPEG-DASH manifest.

The example below uses dash.js to play the video.

import { Innertube } from 'youtubei.js';
import dashjs from 'dashjs';

const youtube = await Innertube.create({ /* setup - see above */ });

// get the video info
const videoInfo = await youtube.getInfo('videoId');

// now convert to a dash manifest
// again - to be able to stream the video in the browser - we must proxy the requests through our own server
// to do this, we provide a method to transform the URLs before writing them to the manifest
const manifest = videoInfo.toDash(url => {
  // modify the url
  // and return it
  return url;
});

const uri = "data:application/dash+xml;charset=utf-8;base64," + btoa(manifest);

const videoElement = document.getElementById('video_player');

const player = dashjs.MediaPlayer().create();
player.initialize(videoElement, uri, true);

Our browser example in examples/browser/web provides a fully working example.

Providing your own fetch implementation

You may provide your own fetch implementation to be used by YouTube.js. This can be useful in some cases to modify the requests before they are sent and transform the responses before they are returned (eg. for proxies).

// provide a fetch implementation
const yt = await Innertube.create({
  fetch: async (input: RequestInfo | URL, init?: RequestInit) => {
    // make the request with your own fetch implementation
    // and return the response
    return new Response(
      /* ... */
    );
  }
});

Caching

To improve performance, you may wish to cache the transformed player instance which we use to decode the streaming urls.

Our cache uses the node:fs module in Node-like environments, Deno.writeFile in Deno, and indexedDB in browsers.

import { Innertube, UniversalCache } from 'youtubei.js';
// By default, cache stores files in the OS temp directory (or indexedDB in browsers).
const yt = await Innertube.create({
  cache: new UniversalCache()
});

// You may wish to make the cache persistent (on Node and Deno)
const yt = await Innertube.create({
  cache: new UniversalCache(
    // Enables persistent caching
    true, 
    // Path to the cache directory will create the directory if it doesn't exist
    './.cache' 
  )
});

API

getInfo(video_id, client?)

Retrieves video info, including playback data and even layout elements such as menus, buttons, etc — all nicely parsed.

Returns: Promise.<VideoInfo>

ParamTypeDescription
video_idstringThe id of the video
client?InnerTubeClientWEB, ANDROID, YTMUSIC, YTMUSIC_ANDROID or TV_EMBEDDED
Methods & Getters

  • <info>#like()

    • Likes the video.
  • <info>#dislike()

    • Dislikes the video.
  • <info>#removeLike()

    • Removes like/dislike.
  • <info>#getLiveChat()

    • Returns a LiveChat instance.
  • <info>#chooseFormat(options)

    • Used to choose streaming data formats.
  • <info>#toDash(url_transformer)

    • Converts streaming data to an MPEG-DASH manifest.
  • <info>#download(options)

  • <info>#filters

    • Returns filters that can be applied to the watch next feed.
  • <info>#selectFilter(name)

    • Applies the given filter to the watch next feed and returns a new instance of VideoInfo.
  • <info>#getWatchNextContinuation()

    • Retrieves the next batch of items for the watch next feed.
  • <info>#addToWatchHistory()

    • Adds the video to the watch history.
  • <info>#page

    • Returns original InnerTube response (sanitized).

getBasicInfo(video_id, client?)

Suitable for cases where you only need basic video metadata. Also, it is faster than getInfo().

Returns: Promise.<VideoInfo>

ParamTypeDescription
video_idstringThe id of the video
client?InnerTubeClientWEB, ANDROID, YTMUSIC_ANDROID, YTMUSIC, TV_EMBEDDED

search(query, filters?)

Searches the given query on YouTube.

Returns: Promise.<Search>

ParamTypeDescription
querystringThe search query
filters?SearchFiltersSearch filters
Methods & Getters

  • <search>#selectRefinementCard(SearchRefinementCard | string)

    • Applies given refinement card and returns a new Search instance.
  • <search>#refinement_card_queries

    • Returns available refinement cards, this is a simplified version of the refinement_cards object.
  • <search>#getContinuation()

    • Retrieves next batch of results.

getSearchSuggestions(query)

Retrieves search suggestions for given query.

Returns: Promise.<string[]>

ParamTypeDescription
querystringThe search query

getComments(video_id, sort_by?)

Retrieves comments for given video.

Returns: Promise.<Comments>

ParamTypeDescription
video_idstringThe video id
sort_bystringCan be: TOP_COMMENTS or NEWEST_FIRST

See ./examples/comments for examples.

getHomeFeed()

Retrieves YouTube's home feed.

Returns: Promise.<HomeFeed>

Methods & Getters

  • <home_feed>#videos

    • Returns all videos in the home feed.
  • <home_feed>#posts

    • Returns all posts in the home feed.
  • <home_feed>#shelves

    • Returns all shelves in the home feed.
  • <home_feed>#filters

    • Returns available filters.
  • <home_feed>#applyFilter(name | ChipCloudChip)

    • Applies given filter and returns a new HomeFeed instance.
  • <home_feed>#getContinuation()

    • Retrieves feed continuation.

getLibrary()

Retrieves the account's library.

Returns: Promise.<Library>

Methods & Getters

  • <library>#history
  • <library>#watch_later
  • <library>#liked_videos
  • <library>#playlists
  • <library>#clips
  • <library>#page
    • Returns original InnerTube response (sanitized).

getHistory()

Retrieves watch history.

Returns: Promise.<History>

Methods & Getters

  • <history>#getContinuation()
    • Retrieves next batch of contents.

getTrending()

Retrieves trending content.

Returns: Promise.<TabbedFeed>

getSubscriptionsFeed()

Retrieves subscriptions feed.

Returns: Promise.<Feed>

getChannel(id)

Retrieves contents for a given channel.

Returns: Promise.<Channel>

ParamTypeDescription
idstringChannel id
Methods & Getters

  • <channel>#getVideos()
  • <channel>#getShorts()
  • <channel>#getLiveStreams()
  • <channel>#getPlaylists()
  • <channel>#getHome()
  • <channel>#getCommunity()
  • <channel>#getChannels()
  • <channel>#getAbout()
  • <channel>#search(query)
  • <channel>#getContinuation()
  • <channel>#filters
  • <channel>#page

See ./examples/channel for examples.

getNotifications()

Retrieves notifications.

Returns: Promise.<NotificationsMenu>

Methods & Getter

  • <notifications>#getContinuation()
    • Retrieves next batch of notifications.

getUnseenNotificationsCount()

Retrieves unseen notifications count.

Returns: Promise.<number>

getPlaylist(id)

Retrieves playlist contents.

Returns: Promise.<Playlist>

ParamTypeDescription
idstringPlaylist id
Methods & Getter

  • <playlist>#items
    • Returns the items of the playlist.

getStreamingData(video_id, options)

Returns deciphered streaming data.

Note: It is recommended to retrieve streaming data from a VideoInfo/TrackInfo object instead if you want to select formats manually, example:

const info = await yt.getBasicInfo('somevideoid');
const url = info.streaming_data?.formats[0].decipher(yt.session.player);
console.info('Playback url:', url);

Returns: Promise.<object>

ParamTypeDescription
video_idstringVideo id
optionsFormatOptionsFormat options

download(video_id, options?)

Downloads a given video.

Returns: Promise.<ReadableStream<Uint8Array>>

ParamTypeDescription
video_idstringVideo id
optionsDownloadOptionsDownload options

See ./examples/download for examples.

resolveURL(url)

Resolves a given url.

Returns: Promise.<NavigationEndpoint>

ParamTypeDescription
urlstringUrl to resolve

call(endpoint, args?)

Utility to call navigation endpoints.

Returns: Promise.<ActionsResponse | ParsedResponse>

ParamTypeDescription
endpointNavigationEndpointThe target endpoint
args?objectAdditional payload arguments

Extending the library

YouTube.js is completely modular and easy to extend. Almost all methods, classes, and utilities used internally are exposed and can be used to implement your own extensions without having to modify the library's source code.

For example, let's say we want to implement a method to retrieve video info manually. We can do that by using an instance of the Actions class:

import { Innertube } from 'youtubei.js';

(async () => {
  const yt = await Innertube.create();

  async function getVideoInfo(videoId: string) {
    const videoInfo = await yt.actions.execute('/player', {
      // anything added here will be merged with the default payload and sent to InnerTube.
      videoId,
      client: 'YTMUSIC', // InnerTube client, can be ANDROID, YTMUSIC, YTMUSIC_ANDROID, WEB or TV_EMBEDDED
      parse: true // tells YouTube.js to parse the response, this is not sent to InnerTube.
    });

    return videoInfo;
  }

  const videoInfo = await getVideoInfo('jLTOuvBTLxA');
  console.info(videoInfo);
})();

Or perhaps there's a NavigationEndpoint in a parsed response and we want to call it to see what happens:

import { Innertube, YTNodes } from 'youtubei.js';

(async () => {
  const yt = await Innertube.create();

  const artist = await yt.music.getArtist('UC52ZqHVQz5OoGhvbWiRal6g');
  const albums = artist.sections[1].as(YTNodes.MusicCarouselShelf);

  // Say we want to click the “More” button:
  const button = albums.as(YTNodes.MusicCarouselShelf).header?.more_content;

  if (button) {
    // After making sure it exists, we can call its navigation endpoint:
    const page = await button.endpoint.call(yt.actions);
    console.info(page);
  }
})();

Parser

YouTube.js' parser allows you to parse InnerTube responses and turn their nodes into strongly typed objects that can be easily manipulated. It also provides a set of utility methods that make working with InnerTube much easier.

Example:

// See ./examples/parser

import { Parser, YTNodes } from 'youtubei.js';
import { readFileSync } from 'fs';

// Artist page response from YouTube Music
const data = readFileSync('./artist.json').toString();

const page = Parser.parseResponse(JSON.parse(data));

const header = page.header?.item().as(YTNodes.MusicImmersiveHeader, YTNodes.MusicVisualHeader);

console.info('Header:', header);

/**
 * The parser encapsulates all arrays in a proxy object.
 * A proxy intercepts access to the actual data, allowing
 * the parser to add type safety and many utility methods
 * that make working with InnerTube much easier.
 */
const tab = page.contents.item().as(YTNodes.SingleColumnBrowseResults).tabs.firstOfType(YTNodes.Tab);


if (!tab)
  throw new Error('Target tab not found');

if (!tab.content)
  throw new Error('Target tab appears to be empty');
  
const sections = tab.content?.as(YTNodes.SectionList).contents.array().as(YTNodes.MusicCarouselShelf, YTNodes.MusicDescriptionShelf, YTNodes.MusicShelf);

console.info('Sections:', sections);

Documentation for the parser can be found here.

Contributing

Contributions, issues, and feature requests are welcome. Feel free to check the issues page and our guidelines if you want to contribute.

Thank you to all the wonderful people who have contributed to this project:

Contact

LuanRT - @thesciencephile - luan.lrt4@gmail.com

Project Link: https://github.com/LuanRT/YouTube.js

Disclaimer

This project is not affiliated with, endorsed, or sponsored by YouTube or any of its affiliates or subsidiaries. All trademarks, logos, and brand names are the property of their respective owners and are used only to directly describe the services being provided, as such, any usage of trademarks to refer to such services is considered nominative use.

Should you have any questions or concerns please contact me directly via email.

License

Distributed under the MIT License.

(back to top)

Footnotes

  1. https://gizmodo.com/how-project-innertube-helped-pull-youtube-out-of-the-gu-1704946491

Keywords

FAQs

Package last updated on 02 Jan 2023

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc