Skip to content
brohoyaPublic

About

Youtube Music unofficial API in TypeScript

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

ytmusicapi

Unofficial YouTube Music API client for TypeScript/JavaScript. A complete TypeScript port of the Python ytmusicapi library.

Features

  • Full TypeScript support with comprehensive type definitions
  • Works in Node.js 18+ (uses native fetch)
  • Supports both ESM and CommonJS
  • Cookie-based authentication for accessing personal library
  • All major YouTube Music features: search, browse, playlists, library, uploads, podcasts

Installation

npm install ytmusicapi

Quick Start

import { YTMusic } from 'ytmusicapi';

// Create an unauthenticated client
const ytm = new YTMusic();

// Search for songs
const results = await ytm.search('Daft Punk', { filter: 'songs' });
console.log(results[0].title, results[0].artists);

// Get artist details
const artist = await ytm.getArtist('UC_kRDKYrUlrbtrSiyu5Tflg');
console.log(artist.name, artist.subscribers);

// Get album details
const album = await ytm.getAlbum('MPREb_K8qWMWVqXGi');
console.log(album.title, album.tracks.length);

Authentication

Some features require authentication (library access, playlist management, etc.). Authentication uses browser cookies.

Getting Your Cookies

  1. Open YouTube Music in your browser
  2. Open Developer Tools (F12)
  3. Go to Network tab
  4. Play a song or navigate
  5. Find a request to music.youtube.com
  6. Copy these headers: Cookie, X-Goog-AuthUser (if present)

Using Authentication

// Option 1: JSON file with headers
const ytm = new YTMusic({ auth: './headers.json' });

// Option 2: JSON string
const ytm = new YTMusic({
  auth: JSON.stringify({ cookie: 'your_cookie_string_here' })
});

// Option 3: Headers object
const ytm = new YTMusic({
  auth: { cookie: 'SAPISID=xxx; __Secure-3PAPISID=xxx; ...' }
});

// Check if authenticated
console.log(ytm.isAuthenticated); // true

Headers JSON Format

{
  "cookie": "__Secure-3PAPISID=xxx; __Secure-3PSID=xxx; SAPISID=xxx; ...",
  "x-goog-authuser": "0"
}

Required cookies: __Secure-3PAPISID (or SAPISID), __Secure-3PSID, LOGIN_INFO

API Reference

Constructor Options

interface YTMusicOptions {
  auth?: string | BrowserAuthHeaders;  // Authentication
  user?: string;                        // Brand account user ID
  language?: string;                    // Language code (default: 'en')
  location?: string;                    // Country code (default: 'US')
}

const ytm = new YTMusic({
  language: 'es',
  location: 'ES'
});

Search Methods

search(query, options?)

Search YouTube Music for songs, albums, artists, playlists, or videos.

const results = await ytm.search('never gonna give you up');

// With filter
const songs = await ytm.search('daft punk', {
  filter: 'songs',
  limit: 20
});

// With scope (library only - requires auth)
const librarySongs = await ytm.search('favorite', {
  filter: 'songs',
  scope: 'library'
});

Parameters:

Name Type Description
query string Search query
options.filter 'songs' | 'albums' | 'artists' | 'playlists' | 'videos' | 'community_playlists' | 'featured_playlists' Filter results by type
options.scope 'library' | 'uploads' Search scope (requires auth)
options.limit number Maximum results (default: 20)
options.ignoreSpelling boolean Ignore spelling corrections

Returns: Promise<SearchResult[]>

getSearchSuggestions(query, detailedRuns?)

Get search suggestions/autocomplete.

const suggestions = await ytm.getSearchSuggestions('never gonna');
// ['never gonna give you up', 'never gonna let you down', ...]

Returns: Promise<SearchSuggestion[]>


Browsing Methods

getHome(limit?)

Get personalized home page content.

const sections = await ytm.getHome(5);
for (const section of sections) {
  console.log(section.title);
  console.log(section.contents);
}

Returns: Promise<HomeSection[]>

getArtist(channelId)

Get artist information and discography.

const artist = await ytm.getArtist('UC_kRDKYrUlrbtrSiyu5Tflg');

console.log(artist.name);           // 'Daft Punk'
console.log(artist.subscribers);    // '8.42M subscribers'
console.log(artist.songs?.results); // Top songs
console.log(artist.albums?.results); // Albums
console.log(artist.singles?.results); // Singles

Parameters:

Name Type Description
channelId string Artist channel ID (starts with UC)

Returns: Promise<ArtistDetail>

interface ArtistDetail {
  name: string;
  channelId: string;
  description?: string;
  subscribers?: string;
  views?: string;
  thumbnails: Thumbnail[];
  songs?: { browseId?: string; results: PlaylistItem[] };
  albums?: { browseId?: string; params?: string; results: AlbumSummary[] };
  singles?: { browseId?: string; params?: string; results: AlbumSummary[] };
  videos?: { browseId?: string; results: VideoItem[] };
  related?: { browseId?: string; results: RelatedArtist[] };
  shuffleId?: string;
  radioId?: string;
}

getArtistAlbums(channelId, params)

Get full list of artist's albums (when artist page shows "Show all").

const artist = await ytm.getArtist('UC_kRDKYrUlrbtrSiyu5Tflg');
if (artist.albums?.params) {
  const allAlbums = await ytm.getArtistAlbums(
    artist.channelId,
    artist.albums.params
  );
}

Returns: Promise<AlbumSummary[]>

getAlbum(browseId)

Get album details including tracks.

const album = await ytm.getAlbum('MPREb_K8qWMWVqXGi');

console.log(album.title);        // 'Random Access Memories'
console.log(album.artists);      // [{ name: 'Daft Punk', id: '...' }]
console.log(album.year);         // '2013'
console.log(album.trackCount);   // 13
console.log(album.duration);     // '1 hour, 14 minutes'
console.log(album.tracks);       // Array of tracks

Parameters:

Name Type Description
browseId string Album browse ID (starts with MPREb_)

Returns: Promise<AlbumDetail>

interface AlbumDetail {
  title: string;
  type: string;  // 'Album', 'Single', 'EP'
  thumbnails: Thumbnail[];
  description?: string;
  artists: ArtistRef[];
  year?: string;
  trackCount?: number;
  duration?: string;
  audioPlaylistId?: string;
  tracks: PlaylistItem[];
}

getAlbumBrowseId(audioPlaylistId)

Convert an audio playlist ID (OLAK...) to a browse ID (MPREb_...).

const browseId = await ytm.getAlbumBrowseId('OLAK5uy_l...');
const album = await ytm.getAlbum(browseId);

Returns: Promise<string | null>

getSong(videoId, signatureTimestamp?)

Get song metadata and streaming information.

const song = await ytm.getSong('dQw4w9WgXcQ');

console.log(song.title);
console.log(song.author);
console.log(song.lengthSeconds);
console.log(song.viewCount);
console.log(song.streamingData?.adaptiveFormats); // Stream URLs

Returns: Promise<SongDetail>

getLyrics(browseId)

Get lyrics for a song. The browseId comes from getWatchPlaylist().

const watchPlaylist = await ytm.getWatchPlaylist({ videoId: 'dQw4w9WgXcQ' });
if (watchPlaylist.lyrics) {
  const lyrics = await ytm.getLyrics(watchPlaylist.lyrics);
  console.log(lyrics?.lyrics);
  console.log(lyrics?.source);
}

Returns: Promise<Lyrics | null>

getSongRelated(browseId)

Get related content for a song. The browseId comes from getWatchPlaylist().

const watchPlaylist = await ytm.getWatchPlaylist({ videoId: 'dQw4w9WgXcQ' });
if (watchPlaylist.related) {
  const related = await ytm.getSongRelated(watchPlaylist.related);
}

Returns: Promise<HomeSection[]>

getUser(channelId)

Get a user's public profile.

const user = await ytm.getUser('UCxxxxxxxx');
console.log(user.name);
console.log(user.thumbnails);

Returns: Promise<UserProfile>

getUserPlaylists(channelId)

Get a user's public playlists.

const playlists = await ytm.getUserPlaylists('UCxxxxxxxx');

Returns: Promise<PlaylistItem[]>


Watch Methods

getWatchPlaylist(options)

Get the "Up Next" queue/watch playlist for a video or playlist.

// From a video
const watchPlaylist = await ytm.getWatchPlaylist({
  videoId: 'dQw4w9WgXcQ'
});

// From a playlist
const watchPlaylist = await ytm.getWatchPlaylist({
  playlistId: 'PLxxxxxxxx'
});

console.log(watchPlaylist.tracks);    // Queue tracks
console.log(watchPlaylist.lyrics);    // Lyrics browse ID
console.log(watchPlaylist.related);   // Related content browse ID
console.log(watchPlaylist.playlistId); // Current playlist ID

Parameters:

Name Type Description
options.videoId string Video ID to start from
options.playlistId string Playlist ID
options.limit number Maximum tracks (default: 25)
options.radio boolean Get radio/mix playlist
options.shuffle boolean Shuffle the playlist

Returns: Promise<WatchPlaylist>

getRadioPlaylist(videoId)

Get a radio/mix playlist based on a song.

const radio = await ytm.getRadioPlaylist('dQw4w9WgXcQ');
console.log(radio.tracks); // Similar songs

Returns: Promise<WatchPlaylist>


Explore Methods

getMoodCategories()

Get mood and genre categories for browsing.

const moods = await ytm.getMoodCategories();
// { 'Mood': [{ title: 'Chill', params: '...' }, ...], ... }

for (const [category, items] of Object.entries(moods)) {
  console.log(category);
  for (const mood of items) {
    console.log(`  ${mood.title}`);
  }
}

Returns: Promise<MoodCategories>

getMoodPlaylists(params)

Get playlists for a specific mood/genre.

const moods = await ytm.getMoodCategories();
const chillParams = moods['Mood'].find(m => m.title === 'Chill')?.params;
if (chillParams) {
  const playlists = await ytm.getMoodPlaylists(chillParams);
}

Returns: Promise<MoodPlaylists>

getCharts(country?)

Get music charts for a country.

const charts = await ytm.getCharts('US');
console.log(charts.songs);    // Top songs
console.log(charts.videos);   // Top videos
console.log(charts.artists);  // Top artists
console.log(charts.trending); // Trending

Returns: Promise<ChartsResult>

getNewReleases()

Get new album releases.

const releases = await ytm.getNewReleases();
console.log(releases.title);
console.log(releases.albums);

Returns: Promise<{ title: string; albums: unknown[] }>


Library Methods (Requires Authentication)

getLibraryPlaylists(options?)

Get user's library playlists.

const playlists = await ytm.getLibraryPlaylists({ limit: 50 });
for (const playlist of playlists) {
  console.log(playlist.title, playlist.count);
}

Options:

Name Type Description
limit number Maximum results
order 'a_to_z' | 'z_to_a' | 'recently_added' Sort order

Returns: Promise<LibraryPlaylist[]>

getLibrarySongs(options?)

Get user's liked/added songs.

const songs = await ytm.getLibrarySongs({ limit: 100 });

Returns: Promise<LibrarySong[]>

getLibraryAlbums(options?)

Get user's saved albums.

const albums = await ytm.getLibraryAlbums();

Returns: Promise<LibraryAlbum[]>

getLibraryArtists(options?)

Get artists from user's library.

const artists = await ytm.getLibraryArtists();

Returns: Promise<LibraryArtist[]>

getLibrarySubscriptions(options?)

Get user's subscribed artists.

const subscriptions = await ytm.getLibrarySubscriptions();

Returns: Promise<LibrarySubscription[]>

getLikedSongs(limit?)

Get user's "Liked Music" playlist.

const liked = await ytm.getLikedSongs(100);

Returns: Promise<PlaylistItem[]>

getHistory()

Get user's playback history.

const history = await ytm.getHistory();
for (const item of history) {
  console.log(item.title, item.played);
}

Returns: Promise<HistoryItem[]>

removeHistoryItem(feedbackToken)

Remove an item from playback history.

const history = await ytm.getHistory();
if (history[0].feedbackToken) {
  await ytm.removeHistoryItem(history[0].feedbackToken);
}

Returns: Promise<boolean>

rateSong(videoId, rating)

Rate a song (like/dislike/remove rating).

await ytm.rateSong('dQw4w9WgXcQ', 'LIKE');
await ytm.rateSong('dQw4w9WgXcQ', 'DISLIKE');
await ytm.rateSong('dQw4w9WgXcQ', 'INDIFFERENT'); // Remove rating

Parameters:

Name Type Description
videoId string Video ID
rating 'LIKE' | 'DISLIKE' | 'INDIFFERENT' Rating

Returns: Promise<boolean>

subscribeArtists(channelIds)

Subscribe to artists.

await ytm.subscribeArtists(['UC_kRDKYrUlrbtrSiyu5Tflg']);

Returns: Promise<boolean>

unsubscribeArtists(channelIds)

Unsubscribe from artists.

await ytm.unsubscribeArtists(['UC_kRDKYrUlrbtrSiyu5Tflg']);

Returns: Promise<boolean>

getAccountInfo()

Get account information.

const account = await ytm.getAccountInfo();
console.log(account.accountName);
console.log(account.channelHandle);

Returns: Promise<AccountInfo>


Playlist Methods

getPlaylist(playlistId, limit?, suggestions?)

Get playlist contents.

const playlist = await ytm.getPlaylist('PLxxxxxxxx', 100);

console.log(playlist.title);
console.log(playlist.author);
console.log(playlist.trackCount);
console.log(playlist.duration);
console.log(playlist.tracks);

Parameters:

Name Type Description
playlistId string Playlist ID (with or without VL prefix)
limit number | null Maximum tracks (null for all)
suggestions number Number of suggestions to include

Returns: Promise<PlaylistDetail>

createPlaylist(options) (Requires Authentication)

Create a new playlist.

const playlistId = await ytm.createPlaylist({
  title: 'My Playlist',
  description: 'A great playlist',
  privacyStatus: 'PRIVATE',
  videoIds: ['dQw4w9WgXcQ', 'abc123']
});

Options:

Name Type Description
title string Playlist title (required)
description string Playlist description
privacyStatus 'PUBLIC' | 'PRIVATE' | 'UNLISTED' Privacy (default: PRIVATE)
videoIds string[] Initial video IDs
sourcePlaylist string Clone from existing playlist

Returns: Promise<string> (new playlist ID)

editPlaylist(options) (Requires Authentication)

Edit playlist metadata.

await ytm.editPlaylist({
  playlistId: 'PLxxxxxxxx',
  title: 'New Title',
  description: 'New description',
  privacyStatus: 'PUBLIC'
});

Returns: Promise<boolean>

deletePlaylist(playlistId) (Requires Authentication)

Delete a playlist.

await ytm.deletePlaylist('PLxxxxxxxx');

Returns: Promise<boolean>

addPlaylistItems(options) (Requires Authentication)

Add songs to a playlist.

const result = await ytm.addPlaylistItems({
  playlistId: 'PLxxxxxxxx',
  videoIds: ['dQw4w9WgXcQ', 'abc123']
});

// result.playlistEditResults contains setVideoIds for removal

Options:

Name Type Description
playlistId string Target playlist ID
videoIds string[] Video IDs to add
sourcePlaylist string Add all from another playlist
duplicates boolean Allow duplicates (default: false)

Returns: Promise<{ playlistEditResults: Array<{ videoId: string; setVideoId?: string }> }>

removePlaylistItems(options) (Requires Authentication)

Remove songs from a playlist.

await ytm.removePlaylistItems({
  playlistId: 'PLxxxxxxxx',
  videos: [
    { videoId: 'dQw4w9WgXcQ', setVideoId: 'setVideoIdFromAddResult' }
  ]
});

Returns: Promise<boolean>


Upload Methods (Requires Authentication)

getLibraryUploadSongs(options?)

Get uploaded songs.

const uploads = await ytm.getLibraryUploadSongs();

Returns: Promise<UploadedSong[]>

getLibraryUploadAlbums(options?)

Get uploaded albums.

const albums = await ytm.getLibraryUploadAlbums();

Returns: Promise<UploadedAlbum[]>

getLibraryUploadArtists(options?)

Get uploaded artists.

const artists = await ytm.getLibraryUploadArtists();

Returns: Promise<UploadedArtist[]>

getLibraryUploadArtist(browseId, limit?)

Get songs by an uploaded artist.

const songs = await ytm.getLibraryUploadArtist('FEmusic_library_privately_owned_artist_...');

Returns: Promise<UploadedSong[]>

getLibraryUploadAlbum(browseId)

Get tracks from an uploaded album.

const tracks = await ytm.getLibraryUploadAlbum('FEmusic_library_privately_owned_release_...');

Returns: Promise<UploadedSong[]>

deleteUploadEntity(entityId) (Requires Authentication)

Delete an uploaded song/album.

await ytm.deleteUploadEntity('entityIdFromUploadedSong');

Returns: Promise<boolean>


Podcast Methods

getChannel(channelId)

Get podcast channel information.

const channel = await ytm.getChannel('UCxxxxxxxx');
console.log(channel.title);
console.log(channel.episodes);

Returns: Promise<PodcastChannel>

getChannelEpisodes(channelId, params?)

Get all episodes from a podcast channel.

const episodes = await ytm.getChannelEpisodes('UCxxxxxxxx');

Returns: Promise<PodcastEpisode[]>

getPodcast(playlistId, limit?)

Get podcast show details.

const podcast = await ytm.getPodcast('PLxxxxxxxx');
console.log(podcast.title);
console.log(podcast.author);
console.log(podcast.episodes);

Returns: Promise<PodcastDetail>

getEpisode(videoId)

Get episode details.

const episode = await ytm.getEpisode('dQw4w9WgXcQ');
console.log(episode.title);
console.log(episode.description);
console.log(episode.duration);

Returns: Promise<EpisodeDetail>

getSavedEpisodes(limit?) (Requires Authentication)

Get user's saved podcast episodes.

const saved = await ytm.getSavedEpisodes();

Returns: Promise<PodcastEpisode[]>

getLibraryPodcasts(limit?) (Requires Authentication)

Get user's subscribed podcasts.

const podcasts = await ytm.getLibraryPodcasts();

Returns: Promise<Array<{ title: string; browseId: string; thumbnails: unknown[] }>>


Utility Methods

setLanguage(language)

Change the language for API requests.

ytm.setLanguage('es'); // Spanish
ytm.setLanguage('fr'); // French
ytm.setLanguage('de'); // German

setLocation(location)

Change the country/region for API requests.

ytm.setLocation('ES'); // Spain
ytm.setLocation('JP'); // Japan
ytm.setLocation('BR'); // Brazil

fetchVisitorId()

Fetch and store a visitor ID (improves API reliability).

await ytm.fetchVisitorId();

Returns: Promise<string | undefined>


Common Types

Thumbnail

interface Thumbnail {
  url: string;
  width: number;
  height: number;
}

ArtistRef

interface ArtistRef {
  name: string;
  id: string | null;
}

PlaylistItem

interface PlaylistItem {
  videoId: string;
  title: string;
  artists: ArtistRef[];
  album?: { name: string; id?: string };
  duration?: string;
  duration_seconds?: number;
  thumbnails: Thumbnail[];
  isExplicit: boolean;
  isAvailable: boolean;
  likeStatus?: 'LIKE' | 'DISLIKE' | 'INDIFFERENT';
  feedbackTokens?: { add?: string; remove?: string };
  setVideoId?: string;
  trackNumber?: number;
}

SearchResult

interface SearchResult {
  resultType: 'song' | 'video' | 'album' | 'artist' | 'playlist';
  category?: string;
  // Type-specific fields...
}

Error Handling

The library throws typed errors for different scenarios:

import {
  YTMusicError,        // Base error class
  YTMusicAuthError,    // Authentication required/failed
  YTMusicUserError,    // Invalid input
  YTMusicServerError,  // API errors
  YTMusicNavigationError // Response parsing errors
} from 'ytmusicapi';

try {
  const playlists = await ytm.getLibraryPlaylists();
} catch (error) {
  if (error instanceof YTMusicAuthError) {
    console.log('Need to authenticate first');
  } else if (error instanceof YTMusicServerError) {
    console.log('API error:', error.statusCode, error.message);
  }
}

Advanced Usage

Using the Base Class

For custom implementations:

import { YTMusicBase, ENDPOINTS } from 'ytmusicapi';

class CustomYTMusic extends YTMusicBase {
  async customMethod() {
    return this.sendRequest(ENDPOINTS.BROWSE, {
      browseId: 'FEmusic_home'
    });
  }
}

Using Navigation Utilities

For parsing raw API responses:

import { nav, findObjectByKey } from 'ytmusicapi';

const title = nav(response, ['header', 'title', 'runs', 0, 'text'], true);
const shelf = findObjectByKey(contents, 'musicShelfRenderer');

License

MIT

Credits

This is a TypeScript port of ytmusicapi by sigma67.

About

Youtube Music unofficial API in TypeScript

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages