Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/faraasaaay/innertube-v1/llms.txt

Use this file to discover all available pages before exploring further.

InnerTube is distributed as a local Android library module — there is no Maven artifact to download. The steps below walk you through cloning the repository into your project, wiring up the Gradle dependency, and running your first search against the YouTube Music API.

Prerequisites

  • An Android project using Kotlin (not Java).
  • minSdk set to 26 or higher in your app module’s build.gradle.kts.
  • Kotlin coroutines available (the library’s public API is entirely suspend-based).

Installation

1

Clone or copy the innertube module into your project

Place the innertube directory at the root of your Android project alongside your app module. Your project structure should look like:
MyApp/
├── app/
│   └── build.gradle.kts
├── innertube/
│   └── build.gradle.kts
└── settings.gradle.kts
2

Register the module in settings.gradle.kts

Open your root settings.gradle.kts and include the module:
// settings.gradle.kts
rootProject.name = "MyApp"
include(":app")
include(":innertube")
3

Add the module dependency to your app

In your app/build.gradle.kts, declare a dependency on :innertube:
// app/build.gradle.kts
dependencies {
    implementation(project(":innertube"))
}
Sync your Gradle project. The innertube module compiles against compileSdk 37 and requires minSdk 26. Ensure your app module’s minSdk is at least 26.
The innertube module uses core library desugaring (isCoreLibraryDesugaringEnabled = true). If your app module does not already have desugaring enabled, add coreLibraryDesugaring(libs.desugaring) to your app’s dependencies as well.

Your first API call

Once the module is on the classpath, you can use the YouTube singleton object directly. All methods are suspend functions and must be called from a coroutine scope.

Configure the locale

Set the locale before making any API calls. The gl field is an ISO 3166-1 alpha-2 country code and hl is a BCP 47 language tag:
import com.metrolist.innertube.YouTube
import com.metrolist.innertube.models.YouTubeLocale

YouTube.locale = YouTubeLocale(gl = "US", hl = "en")

(Optional) Attach a visitor ID

YouTube assigns a visitor data token that improves personalisation and reduces the chance of bot-detection challenges. You can fetch one directly from YouTube’s servers:
import com.metrolist.innertube.YouTube

// Fetch a fresh visitor ID from YouTube and store it
val visitorData = YouTube.visitorData().getOrNull()
if (visitorData != null) {
    YouTube.visitorData = visitorData
}

Search for songs

Call YouTube.search() with a query string and one of the SearchFilter constants. The method returns Result<SearchResult>, where SearchResult.items is a List<YTItem> and SearchResult.continuation holds an opaque token for the next page of results.
import com.metrolist.innertube.YouTube
import com.metrolist.innertube.models.SongItem
import com.metrolist.innertube.models.YouTubeLocale
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    // 1. Configure locale
    YouTube.locale = YouTubeLocale(gl = "US", hl = "en")

    // 2. Optionally fetch and store a visitor ID
    YouTube.visitorData().getOrNull()?.let { YouTube.visitorData = it }

    // 3. Search for songs
    val result = YouTube.search("Bohemian Rhapsody", YouTube.SearchFilter.FILTER_SONG)

    result.fold(
        onSuccess = { searchResult ->
            println("Found ${searchResult.items.size} results:")
            searchResult.items.filterIsInstance<SongItem>().forEach { song ->
                val artistNames = song.artists.joinToString(", ") { it.name }
                println("  • ${song.title}$artistNames (id: ${song.id})")
            }

            // If there are more results, searchResult.continuation is non-null
            if (searchResult.continuation != null) {
                println("More results available via YouTube.searchContinuation()")
            }
        },
        onFailure = { error ->
            println("Search failed: ${error.message}")
        }
    )
}

Available search filters

YouTube.SearchFilter.FILTER_SONG               // Audio tracks
YouTube.SearchFilter.FILTER_VIDEO              // Music videos
YouTube.SearchFilter.FILTER_ALBUM              // Albums and EPs
YouTube.SearchFilter.FILTER_ARTIST             // Artist profiles
YouTube.SearchFilter.FILTER_FEATURED_PLAYLIST  // YouTube curated playlists
YouTube.SearchFilter.FILTER_COMMUNITY_PLAYLIST // User-created playlists
YouTube.SearchFilter.FILTER_PODCAST            // Podcast series
YouTube.SearchFilter.FILTER_EPISODE            // Individual podcast episodes
YouTube.SearchFilter.FILTER_PROFILE            // User profiles

Paginate search results

When SearchResult.continuation is non-null, call YouTube.searchContinuation() to fetch the next page:
var currentResult = YouTube.search("Radiohead", YouTube.SearchFilter.FILTER_SONG).getOrThrow()

while (currentResult.continuation != null) {
    currentResult.items.filterIsInstance<SongItem>().forEach { song ->
        println(song.title)
    }
    currentResult = YouTube.searchContinuation(currentResult.continuation!!).getOrThrow()
}

Fetching an artist page

Use YouTube.artist() with a browse ID (the UCxxxxx-style channel identifier) to retrieve a complete ArtistPage:
import com.metrolist.innertube.YouTube
import com.metrolist.innertube.pages.ArtistPage
import kotlinx.coroutines.runBlocking

fun fetchArtist(browseId: String) = runBlocking {
    val result: Result<ArtistPage> = YouTube.artist(browseId)

    result.fold(
        onSuccess = { page ->
            println("Artist: ${page.artist.title}")
            println("Subscribers: ${page.subscriberCountText ?: "unknown"}")
            println("Monthly listeners: ${page.monthlyListenerCount ?: "unknown"}")

            // Sections hold carousels like "Popular songs", "Albums", "Related artists"
            page.sections.forEach { section ->
                println("Section: ${section.title} (${section.items.size} items)")
            }
        },
        onFailure = { error ->
            println("Failed to load artist: ${error.message}")
        }
    )
}
Every YouTube method returns Result<T>. Use getOrNull() to silently discard errors, getOrThrow() to propagate them as exceptions, or fold(onSuccess, onFailure) to handle both branches explicitly.

Next steps

Once you are comfortable with search and browse calls, explore the rest of the YouTube API:
  • YouTube.album(browseId) — fetch a full AlbumPage including song list and alternate versions.
  • YouTube.playlist(playlistId) — load playlist metadata and its first page of tracks.
  • YouTube.home() — fetch the personalised home feed with carousel sections and filter chips.
  • YouTube.player(videoId, playlistId, ...) — resolve playback streams for a given video ID.
  • YouTube.createPlaylist(title) — create a new playlist on the authenticated account.

Build docs developers (and LLMs) love