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

A full-featured library that allows you to get detailed info about any video, subscribe, unsubscribe, like, dislike, comment, search, download videos/music and much more!

  • 1.4.1-dev.2
  • 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.

Report Bug · Request Feature

Table of Contents
  1. About The Project
  2. Getting Started
  3. Usage
  4. Contributing
  5. License
  6. Contact
  7. Disclaimer

About

Innertube is an API used across all YouTube clients, it was made to simplify the internal structure of the platform and make it easy to push updates. This library takes advantage of that API, therefore providing a simple & efficient way to interact with YouTube programmatically.

And big thanks to @gatecrasher777 for his research on the workings of the Innertube API!

Features

As of now, this is one of the most advanced & stable YouTube libraries out there, here's a short summary of its features:

  • Search videos, playlists, music, albums etc.
  • Subscribe/Unsubscribe/Like/Dislike/Comment etc.
  • Get subscriptions/home feed, notifications and watch history.
  • Easily sign in to any Google Account.
  • Fetch live chat & live stats.
  • Manage account settings.
  • Create/delete playlists.
  • Download videos.

~ And more!

Do note that you must be signed-in to perform actions that involve an account; such as commenting, liking/disliking videos, sending messages to a live chat, etc.

Getting Started

Prerequisites

  • NodeJS v14 or greater

    To verify things are set up properly, you can run this:

    node --version
    

Installation

  • NPM:
    npm install youtubei.js@latest
    
  • Yarn:
    yarn add youtubei.js@latest
    

Usage

First of all we're gonna start by initializing the Innertube instance. And to make things faster, you should do this only once and reuse the Innertube object when needed.

const Innertube = require('youtubei.js');
const youtube = await new Innertube({ gl: 'US' }); // all parameters are optional.

YouTube:

const search = await youtube.search('Looking for life on Mars - Documentary');

YTMusic:

const search = await youtube.search('Interstellar Main Theme', { client: 'YTMUSIC' });
YouTube Output

{
   query: string,
   corrected_query: string,
   estimated_results: number,
   videos: [
      {
         id: string,
         url: string,
         title: string,
         description: string,
         metadata:{
            view_count: string,
            short_view_count_text: {
               simple_text: string,
               accessibility_label: string
            },
            thumbnails: [Array],
            duration: {
               seconds: number,
               simple_text: string,
               accessibility_label: string
            },
            published: string,
            badges:[Array],
            owner_badges:[Array]
         }
      }
      //...
   ]
}

YTMusic Output

{
   query:string,
   corrected_query:string,
   results:{
      top_result:[Array],  // Can be anything; video, playlist, artist etc..
      songs:[
         {
            id:string,
            title:string,
            artist:string,
            album:string,
            duration:string,
            thumbnails:[
               Array
            ]
         },
         //...
      ],
      videos:[
         {
            id:string,
            title:string,
            author:string,
            views:string,
            duration:string,
            thumbnails:[Array]
         },
         //...
      ],
      albums:[
         {
            id:string,
            title:string,
            author:string,
            year:string,
            thumbnails:[Array]
         },
         //...
      ],
      featured_playlists:[
         {
            id:string,
            title:string,
            author:string,
            channel_id:string,
            total_items:number
         },
         //...
      ],
      community_playlists:[
         {
            id:string,
            title:string,
            author:string,
            channel_id:string,
            total_items:number
         },
         //...
      ],
      artists:[
         {
            id:string,
            name:string,
            subscribers:string,
            thumbnails:[Array]
         },
         //...
      ]
   }
}


Get search suggestions:

const suggestions = await youtube.getSearchSuggestions('QUERY', {
   client: 'YOUTUBE' // Use YTMUSIC if you want music search suggestions 
})
Output

[
  {
     text: string, bold_text: string
  },
  //...
]

Get video info:

const video = await youtube.getDetails('VIDEO_ID');
Output

{
   title: string,
   description: string,
   thumbnail: {
      url: string,
      width: number,
      height: number
   },
   metadata: {
      embed: {
         iframeUrl: string,
         flashUrl: string,
         width: number,
         height: number,
         flashSecureUrl: string
      },
      likes: number,
      dislikes: number,
      view_count: number,
      average_rating: number,
      length_seconds: number,
      channel_id: string,
      channel_url: string,
      external_channel_id: string,
      allow_ratings: boolean,
      is_live_content: boolean,
      is_family_safe: boolean,
      is_unlisted: boolean,
      is_private: boolean,
      is_liked: boolean,
      is_disliked: boolean,
      is_subscribed: boolean,
      subscriber_count: string,
      current_notification_preference: string,
      likes: { count: number, short_count_text: string },
      publish_date_text: string,
      has_ypc_metadata: boolean,
      category: string,
      channel_name: string,
      publish_date: string,
      upload_date: string,
      keywords: [Array]
   }
}

Get comments:

const response = await youtube.getComments('VIDEO_ID');

Alternatively you can use:

const video = await youtube.getDetails('VIDEO_ID');
const response = await video.getComments(); 
Output

{
   comments: [
      {
         text: string,
         author: {
            name: string,
            thumbnail: [
               {
                  url: string,
                  width: number,
                  height: number
               }
            ],
            channel_id: string
         },
         metadata:{
            published: string,
            is_liked: boolean,
            is_disliked: boolean,
            is_pinned: boolean,
            is_channel_owner: boolean,
            like_count: number,
            reply_count: number,
            id: string
         }
      },
      //...
   ],
   comment_count: string // not available in continuations
}

Reply to, like and dislike comments:

await response.comments[0].like();
await response.comments[0].dislike();
await response.comments[0].reply('Nice comment!'); 

Comment replies:

const replies = await response.comments[0].getReplies();

Comments/replies continuation:

const continuation = await response.getContinuation();
const replies_continuation = await replies.getContinuation();

Get home feed:

const homefeed = await youtube.getHomeFeed();
Output

{
   videos: [
     {
        id: string,
        title: string,
        description: string,
        channel: {
          id: string,
          name: string,
          url: string
        },
        metadata: {
           view_count: string,
           short_view_count_text: { simple_text: string, accessibility_label: string },
           thumbnail: {
              url: string,
              width: number,
              height: number
            },
            moving_thumbnail: {
              url: string,
              width: number,
              height: number
            },
            published: string,
            duration: {
              seconds: number,
              simple_text: string,
              accessibility_label: string
            },
            badges: string,
            owner_badges: [Array]
        }
     },
     // ...
  ]
}

Continuation:

const continuation = await homefeed.getContinuation();

Get watch history:

const history = await youtube.getHistory();
Output

{
   items: [
      {
         date: string,
         videos: [
            {
               id: string,
               title: string,
               channel: {
                  id: string,
                  name: string,
                  url: string
               },
               metadata: {
                  view_count: string,
                  short_view_count_text: {
                     simple_text: string,
                     accessibility_label: string
                  },
                  thumbnail: {
                     url: string,
                     width: number,
                     height: number
                  },
                  moving_thumbnail: {
                     url: string,
                     width: number,
                     height: number
                  },
                  published: string,
                  badges: [Array],
                  owner_badges: [Array]
               }
            },
            //...
         ]
      },
      //...
   ]
}

Continuation:

const continuation = await history.getContinuation();

Get subscriptions feed:

const mysubsfeed = await youtube.getSubscriptionsFeed();
Output

{
   items: [
      {
         date: string,
         videos: [
            {
               id: string,
               title: string,
               description: string,
               channel: {
                  id: string,
                  name: string,
                  url: string
               },
               metadata: {
                  view_count: string,
                  short_view_count_text: {
                     simple_text: string,
                     accessibility_label: string
                  },
                  thumbnail: {
                     url: string,
                     width: number,
                     height: number
                  },
                  moving_thumbnail: {
                     url: string,
                     width: number,
                     height: number
                  },
                  published: string,
                  badges: [Array],
                  owner_badges: [Array]
               }
            },
            //...
         ]
      },
      //...
   ]
}

Continuation:

const continuation = await mysubsfeed.getContinuation();
const trending = await youtube.getTrending();
Output

{
  now: {
    content: [
      {
        title: string,
        videos: [] 
      },
      //...
    ]
  },
  // Other categories require an additional call to fetch videos
  music: { getVideos: Promise.<Array> },
  gaming: { getVideos: Promise.<Array> },
  movies: { getVideos: Promise.<Array> }
}

Get song lyrics:

const search = await youtube.search('Never give you up', { client: 'YTMUSIC' });
const lyrics = await youtube.getLyrics(search.results.songs[0].id); 

Get notifications:

const notifications = await youtube.getNotifications();
Output

{
  items: [  
    {
      title: string,
      sent_time: string,
      channel_name: string,
      channel_thumbnail: {
         url: string,
         width: number,
         height: number
      },
      video_thumbnail: { 
         url: string,
         width: number,
         height: number
      },
      video_url: string,
      read: boolean,
      notification_id: string
    },
    //...
  ]
}

Continuation:

const continuation = await notifications.getContinuation();

Unseen notifications count:

const unread_notis_count = await youtube.getUnseenNotificationsCount();

Get playlist:

YouTube (default):

const playlist = await youtube.getPlaylist('PLAYLIST_ID');

YouTube Music:

const playlist = await youtube.getPlaylist('PLAYLIST_ID', {
   client: 'YTMUSIC' 
});
YouTube Output

{
  title: string,
  description: string,
  total_items: string,
  last_updated: string,
  views: string,
  items: [
    {
      id: string,
      title: string,
      author: string,
      duration: {
         seconds: number,
         simple_text: string,
         accessibility_label: string
      },
      thumbnails: [Array]
    },
    //...
  ]
}

YouTube Music Output

{
  title: string,
  description: string,
  total_items: number,
  duration: string,
  year: string,
  items: [
    {
      id: string,
      title: string,
      author: string,
      duration: {
         seconds: number,
         simple_text: string
      },
      thumbnails: [Array]
    },
    //...
}

Interactions:


The library makes it easy to interact with YouTube programmatically. However, don't forget that you must be signed in to use the following features!

  • Subscribe/Unsubscribe:

    await youtube.interact.subscribe('CHANNEL_ID');
    await youtube.interact.unsubscribe('CHANNEL_ID');
    
  • Like/Dislike:

    await youtube.interact.like('VIDEO_ID');
    await youtube.interact.dislike('VIDEO_ID');
    await youtube.interact.removeLike('VIDEO_ID');
    
  • Comment:

    await youtube.interact.comment('VIDEO_ID', 'Haha, nice video!');
    
  • Playlists:

    // Create a playlist:
    await youtube.playlist.create('NAME', 'VIDEO_ID');
    
    // Delete a playlist:
    await youtube.playlist.delete('PLAYLIST_ID');
    
    // Add videos to a playlist:
    await youtube.playlist.addVideos('PLAYLIST_ID', [ 'VIDEO_ID1', 'VIDEO_ID2' ]);
    
  • Change notification preferences:

    // Options: ALL | NONE | PERSONALIZED
    await youtube.interact.setNotificationPreferences('CHANNEL_ID', 'ALL'); 
    

These methods will always return { success: true, status_code: 200 } if successful.

Account Settings

It is also possible to manage an account's settings:

  • Get account info:

    await youtube.account.info();
    
    Output

    {
        name: string,
        photo: [
           {
              url: string,
              width: number,
              height: number
           }
        ],
        country: string,
        language: string;
    }
    


Notification settings:
  • Subscription notifications:

    await youtube.account.settings.notifications.setSubscriptions(true); 
    
  • Recommended content notifications:

    await youtube.account.settings.notifications.setRecommendedVideos(true); 
    
  • Channel activity notifications:

    await youtube.account.settings.notifications.setChannelActivity(true); 
    
  • Comment replies notifications:

    await youtube.account.settings.notifications.setCommentReplies(true); 
    
  • Channel mention notifications:

    await youtube.account.settings.notifications.setSharedContent(true); 
    
Privacy settings:
  • Subscriptions privacy:

    await youtube.account.settings.privacy.setSubscriptionsPrivate(true); 
    
  • Saved playlists privacy:

    await youtube.account.settings.privacy.setSavedPlaylistsPrivate(true); 
    

Live chats:


YouTube.js isn't able to download live content yet, but it does allow you to fetch live chats plus you can also send messages!

const Innertube = require('youtubei.js');

async function start() {
  const youtube = await new Innertube();

  const search = await youtube.search('Lofi girl live');
  const video = await youtube.getDetails(search.videos[0].id);
  
  const livechat = video.getLivechat();

  // Updated stats about the livestream
  livechat.on('update-metadata', (data) => {
    console.info('Info:', data);
  });
   
  // Fired whenever there is a new message or other chat events
  livechat.on('chat-update', (message) => {
    console.info(`- ${message.author.name}\n${message.text}\n\n`);
    
    if(message.text == '!info') {
      livechat.sendMessage('Hello! This message was sent from YouTube.js');
    }
  });
}

start();

Stop fetching the live chat:

livechat.stop();

Delete a message:

const msg = await livechat.sendMessage('Nice livestream!');
await msg.deleteMessage();

Downloading videos:


YouTube.js provides an easy-to-use and simple downloader:

const fs = require('fs');
const Innertube = require('youtubei.js');

async function start() {
  const youtube = await new Innertube();
 
  const search = await youtube.search('Looking for life on Mars - documentary');
  
  const stream = youtube.download(search.videos[0].id, {
    format: 'mp4', // Optional, defaults to mp4 and I recommend to leave it as it is unless you know what you're doing
    quality: '360p', // if a video doesn't have a specific quality it'll fall back to 360p, also ignored when type is set to audio
    type: 'videoandaudio' // can be “video”, “audio” and “videoandaudio”
  });
  
  stream.pipe(fs.createWriteStream(`./${search.videos[0].title}.mp4`));
 
  stream.on('start', () => {
    console.info('[DOWNLOADER]', 'Starting download now!');
  });
  
  stream.on('info', (info) => {
    // { video_details: {..}, selected_format: {..}, formats: {..} }
    console.info('[DOWNLOADER]', `Downloading ${info.video_details.title} by ${info.video_details.metadata.channel_name}`);
  });
  
  stream.on('progress', (info) => {
    process.stdout.clearLine();
    process.stdout.cursorTo(0);
    process.stdout.write(`[DOWNLOADER] Downloaded ${info.percentage}% (${info.downloaded_size}MB) of ${info.size}MB`);
  });
  
  stream.on('end', () => {
    process.stdout.clearLine();
    process.stdout.cursorTo(0);
    console.info('[DOWNLOADER]', 'Done!');
  });
  
  stream.on('error', (err) => console.error('[ERROR]', err)); 
}

start();

You can also specify a range:

const stream = youtube.download(VIDEO_ID, {
  //...
  type: 'videoandaudio',
  range: { start: 0, end: 1048576 * 5 }
});
  

Cancel a download:

stream.cancel();

Alternatively, you can get the deciphered streaming data and handle the download yourself:

const streaming_data = await youtube.getStreamingData(search.videos[0].id, {
   format: 'mp4',
   quality: '360p',
   type: 'videoandaudio'
});
Output

{
   selected_format: {
      itag: number,
      mimeType: string,
      bitrate: number,
      initRange: { start: string, end: string },
      indexRange: { start: string, end: string },
      lastModified: string,
      contentLength: string,
      quality: string,
      projectionType: string,
      averageBitrate: number,
      highReplication: boolean,
      audioQuality: string,
      approxDurationMs: string,
      audioSampleRate: string,
      audioChannels: number,
      loudnessDb: number,
      url: string, 
      has_audio: boolean,
      has_video: boolean
  },
  formats: [
    {
      itag: number,
      mimeType: string,
      bitrate: number,
      initRange: { start: string, end: string },
      indexRange: { start: string, end: string },
      lastModified: string,
      contentLength: string,
      quality: string,
      projectionType: string,
      averageBitrate: number,
      highReplication: boolean,
      audioQuality: string,
      approxDurationMs: string,
      audioSampleRate: string,
      audioChannels: number,
      loudnessDb: number,
      url: string, 
      has_audio: boolean,
      has_video: boolean
    }
    //...
  ]
}

Signing-in:


When signing in to your account, you have two options:

  • Use OAuth 2.0; easy, simple & reliable.
  • Cookies; usually more complicated to get and unreliable.
OAuth:
const fs = require('fs');
const Innertube = require('youtubei.js');
const creds_path = './yt_oauth_creds.json'; 

async function start() {
  const creds = fs.existsSync(creds_path) && JSON.parse(fs.readFileSync(creds_path).toString()) || {};
  const youtube = await new Innertube();
  
  youtube.ev.on('auth', (data) => {
    if (data.status === 'AUTHORIZATION_PENDING') {
      console.info(`Hello!\nOn your phone or computer, go to ${data.verification_url} and enter the code ${data.code}`);
    } else if (data.status === 'SUCCESS') {
      fs.writeFileSync(creds_path, JSON.stringify(data.credentials));
      console.info('Successfully signed-in, enjoy!');
    }
  });
  
  youtube.ev.on('update-credentials', (data) => {
    fs.writeFileSync(creds_path, JSON.stringify(data.credentials));
    console.info('Credentials updated!', data);
  });
  
  await youtube.signIn(creds);
  
  //...
}

start();

Sign-out:

const response = await youtube.signOut();
if (response.success) {
  console.log('You have successfully signed out');
}
Cookies:
const Innertube = require('youtubei.js');

async function start() {
  const youtube = await new Innertube({ cookie: '...' }); 
  //...
}

start();

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

Contact

LuanRT - @lrt_nooneknows - 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 their affiliates or subsidiaries. All trademarks, logos and brand names are the property of their respective owners.

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

License

Distributed under the MIT License.

(back to top)

Keywords

FAQs

Package last updated on 20 Apr 2022

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