## Description
InnerTube is an API used by all YouTube clients. It was created to simplify the deployment of new features and experiments across the platform[^1]. 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][discord] or open an issue [here](https://github.com/LuanRT/YouTube.js/issues).
## Getting Started
### Prerequisites
YouTube.js runs on Node.js, Deno, and modern browsers.
It requires a runtime with the following features:
- [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
- On Node we use [undici]()'s fetch implementation which requires Node.js 16.8+. You may provide your fetch implementation if you need to use an older version. See [providing your own fetch implementation](#custom-fetch) for more information.
- The `Response` object returned by fetch must thus be spec compliant and return a `ReadableStream` object if you want to use the `VideoInfo#download` method. (Implementations like `node-fetch` returns a non-standard `Readable` object.)
- [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) and [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) are required.
### Installation
```bash
# NPM
npm install youtubei.js@latest
# Yarn
yarn add youtubei.js@latest
# Git (edge version)
npm install github:LuanRT/YouTube.js
```
When using Deno, you can import YouTube.js directly from deno.land:
```ts
import { Innertube } from 'https://deno.land/x/youtubei/deno.ts';
```
## Usage
Create an InnerTube instance:
```ts
// 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`](https://github.com/LuanRT/YouTube.js/tree/main/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`](https://github.com/LuanRT/YouTube.js/tree/main/examples/browser/web) for a simple example using [Vite](https://vitejs.dev/).
```ts
// We provide multiple exports for the web.
// Unbundled ESM version
import { Innertube } from 'youtubei.js/web';
// Bundled ESM version
// import { Innertube } from 'youtubei.js/web.bundle';
// Production Bundled ESM version
// import { Innertube } from 'youtubei.js/web.bundle.min';
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`](https://github.com/Dash-Industry-Forum/dash.js) to play the video.
```ts
import { Innertube } from 'youtubei.js/web';
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 = await 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);
```
A fully working example can be found in [`examples/browser/web`](https://github.com/LuanRT/YouTube.js/blob/main/examples/browser/web). Alternatively, you can view it live at [ytjsexample.pages.dev](https://ytjsexample.pages.dev/).
## 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).
```ts
// 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.
```ts
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(false)
});
// 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
* `Innertube`
Objects
### getInfo(target, client?)
Retrieves video info, including playback data and even layout elements such as menus, buttons, etc — all nicely parsed.
**Returns**: `Promise`
| Param | Type | Description |
| --- | --- | --- |
| target | `string` \| `NavigationEndpoint` | If `string`, the id of the video. If `NavigationEndpoint`, the endpoint of watchable elements such as `Video`, `Mix` and `Playlist`. To clarify, valid endpoints have payloads containing at least `videoId` and optionally `playlistId`, `params` and `index`. |
| client? | `InnerTubeClient` | `WEB`, `ANDROID`, `YTMUSIC`, `YTMUSIC_ANDROID` or `TV_EMBEDDED` |
Methods & Getters
- `#like()`
- Likes the video.
- `#dislike()`
- Dislikes the video.
- `#removeRating()`
- Removes like/dislike.
- `#getLiveChat()`
- Returns a LiveChat instance.
- `#getTrailerInfo()`
- Returns trailer info in a new `VideoInfo` instance, or `null` if none. Typically available for non-purchased movies or films.
- `#chooseFormat(options)`
- Used to choose streaming data formats.
- `#toDash(url_transformer?, format_filter?)`
- Converts streaming data to an MPEG-DASH manifest.
- `#download(options)`
- Downloads the video. See [download](#download).
- `#filters`
- Returns filters that can be applied to the watch next feed.
- `#selectFilter(name)`
- Applies the given filter to the watch next feed and returns a new instance of [`VideoInfo`](https://github.com/LuanRT/YouTube.js/blob/main/src/parser/youtube/VideoInfo.ts).
- `#getWatchNextContinuation()`
- Retrieves the next batch of items for the watch next feed.
- `#addToWatchHistory()`
- Adds the video to the watch history.
- `#autoplay_video_endpoint`
- Returns the endpoint of the video for Autoplay.
- `#has_trailer`
- Checks if trailer is available.
- `#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()`](#getinfo).
**Returns**: `Promise`
| Param | Type | Description |
| --- | --- | --- |
| video_id | `string` | The id of the video |
| client? | `InnerTubeClient` | `WEB`, `ANDROID`, `YTMUSIC_ANDROID`, `YTMUSIC`, `TV_EMBEDDED` |
### search(query, filters?)
Searches the given query on YouTube.
**Returns**: `Promise`
> **Note**
> `Search` extends the [`Feed`](https://github.com/LuanRT/YouTube.js/blob/main/docs/API/feed.md) class.
| Param | Type | Description |
| --- | --- | --- |
| query | `string` | The search query |
| filters? | `SearchFilters` | Search filters |
Methods & Getters
- `#selectRefinementCard(SearchRefinementCard | string)`
- Applies given refinement card and returns a new Search instance.
- `#refinement_card_queries`
- Returns available refinement cards, this is a simplified version of the `refinement_cards` object.
- `#getContinuation()`
- Retrieves next batch of results.
### getSearchSuggestions(query)
Retrieves search suggestions for given query.
**Returns**: `Promise`
| Param | Type | Description |
| --- | --- | --- |
| query | `string` | The search query |
### getComments(video_id, sort_by?)
Retrieves comments for given video.
**Returns**: `Promise`
| Param | Type | Description |
| --- | --- | --- |
| video_id | `string` | The video id |
| sort_by | `string` | Can be: `TOP_COMMENTS` or `NEWEST_FIRST` |
See [`./examples/comments`](https://github.com/LuanRT/YouTube.js/blob/main/examples/comments) for examples.
### getHomeFeed()
Retrieves YouTube's home feed.
**Returns**: `Promise`
> **Note**
> `HomeFeed` extends the [`FilterableFeed`](https://github.com/LuanRT/YouTube.js/blob/main/docs/API/filterable-feed.md) class.
Methods & Getters
- `#videos`
- Returns all videos in the home feed.
- `#posts`
- Returns all posts in the home feed.
- `#shelves`
- Returns all shelves in the home feed.
- `#filters`
- Returns available filters.
- `#applyFilter(name | ChipCloudChip)`
- Applies given filter and returns a new HomeFeed instance.
- `#getContinuation()`
- Retrieves feed continuation.
### getHashtag(hashtag)
Retrieves a given hashtag's page.
**Returns**: `Promise`
> **Note**
> `HashtagFeed` extends the [`FilterableFeed`](https://github.com/LuanRT/YouTube.js/blob/main/docs/API/filterable-feed.md) class.
| Param | Type | Description |
| --- | --- | --- |
| hashtag | `string` | The hashtag |
Methods & Getter
- `#applyFilter(filter)`
- Applies given filter and returns a new `HashtagFeed` instance.
- `#getContinuation()`
- Retrieves next batch of contents.
### getStreamingData(video_id, options)
Returns deciphered streaming data.
> **Note**
> This will be deprecated in the future. It is recommended to retrieve streaming data from a `VideoInfo`/`TrackInfo` object instead if you want to select formats manually, see the example below.
```ts
const info = await yt.getBasicInfo('somevideoid');
const url = info.streaming_data?.formats[0].decipher(yt.session.player);
console.info('Playback url:', url);
```
**Returns**: `Promise