Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/faraasaaay/inner/llms.txt

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

PortableInnertube is the KMP-compatible counterpart to the Android-only YouTube singleton. It accepts a platform-specific HttpClient via Kotlin’s expect/actual mechanism and is suitable for use in commonMain code shared between Android and iOS. Unlike the YouTube singleton, it carries no built-in retry logic or proxy support — making it lightweight and portable at the cost of some resilience.

When to use PortableInnertube vs YouTube

YouTube (Android only)

  • Full feature set: browse, search, playback, player state
  • Proxy support via OkHttp interceptors
  • Built-in exponential backoff and retry logic
  • All auth actions, including cookie refresh
  • Singleton pattern — configure once globally

PortableInnertube (KMP)

  • Subset API: search, browse, home, album, artist, playlist
  • No proxy, no retry
  • Works on iOS via the Ktor Darwin engine
  • Instance-based — create and configure per use case
  • Shares PlaybackAuthState model with the YouTube singleton

Creating an instance

import com.tamed.music.innertube.PortableInnertube
import com.tamed.music.innertube.models.YouTubeLocale

val client = PortableInnertube(
    locale = YouTubeLocale(gl = "US", hl = "en-US")
)
The httpClient parameter is provided automatically via createPortableInnertubeHttpClient(). On Android this resolves to an OkHttp-backed Ktor client; on iOS it resolves to a Darwin-backed Ktor client. You do not need to pass an HttpClient manually unless you have a specific testing or customization need.
The default locale is YouTubeLocale(gl = "US", hl = "en-US"), defined as PortableInnertube.DEFAULT_LOCALE. All HTTP requests are sent to YouTubeClient.API_URL_YOUTUBE_MUSIC with a 15-second request timeout and 10-second connect timeout.

Configuration properties

locale
YouTubeLocale
default:"YouTubeLocale(gl = \"US\", hl = \"en-US\")"
The geographic (gl) and language (hl) locale sent with every request. Used to receive region-appropriate results and UI text in the correct language.
useLoginForBrowse
Boolean
default:"false"
When true, browse requests (home, playlist) include the login context from the active PlaybackAuthState. Set this to true when you need personalised home feed results for a logged-in user.
visitorData
String?
A delegated property backed by the internal PlaybackAuthState. Setting this value updates the auth state and automatically calls normalized(), which trims whitespace and converts empty strings to null.
dataSyncId
String?
The account identifier used as onBehalfOfUser in authenticated requests. Delegated to PlaybackAuthState. Values containing || are automatically resolved during normalization.
poToken
String?
A generic PoToken fallback used when no specific player or GVS token is set. Delegated to PlaybackAuthState.
The raw YouTube Music cookie header string (e.g. "SAPISID=xxx; HSID=yyy; ..."). Delegated to PlaybackAuthState. The presence of SAPISID in this value determines hasLoginCookie.

Authentication

Use applyAuthState(PlaybackAuthState) to set all auth fields atomically. This is preferred over setting individual properties when you have a full auth context to apply, since it performs a single normalized() call.
import com.tamed.music.innertube.PlaybackAuthState

client.applyAuthState(
    PlaybackAuthState(
        cookie = "SAPISID=xxx; HSID=yyy; ...",
        visitorData = "CgtAbCdEfGhIjKlMnO",
        dataSyncId = "your_data_sync_id",
        webClientPoTokenEnabled = true,
        poTokenPlayer = "player_token_here",
        poTokenGvs = "gvs_token_here",
    )
)
To read the current state at any time, call currentAuthState():
val state: PlaybackAuthState = client.currentAuthState()
println("Logged in: ${state.hasLoginCookie}")
println("Session ID: ${state.sessionId}")
Setting individual properties (visitorData, dataSyncId, etc.) each trigger a copy() + normalized() cycle on the internal auth state. If you are setting multiple fields at once, prefer applyAuthState() for efficiency.

Available methods

All methods are suspend functions that return Result<T>. Errors from the underlying Ktor HTTP client (network failures, non-2xx responses) are captured and returned as Result.failure. Searches YouTube Music and returns a flat list of YTItem results. Pass a continuation token from a previous SearchResult to fetch the next page.
query
String
required
The search query string.
continuation
String?
default:"null"
Continuation token from a prior SearchResult. When provided, query is ignored.
params
String?
default:"null"
An optional encoded filter parameter that restricts results to a specific content type (songs, albums, artists, playlists, community playlists, featured playlists, or videos).
client
YouTubeClient
default:"WEB_REMIX"
The InnerTube client context to use for the request.
Returns: Result<SearchResult> — a SearchResult with items: List<YTItem> and an optional continuation: String?.
val result = client.search("Tame Impala").getOrThrow()
result.items.forEach { println(it.title) }

// Pagination
var continuation = result.continuation
while (continuation != null) {
    val next = client.search("Tame Impala", continuation = continuation).getOrThrow()
    next.items.forEach { println(it.title) }
    continuation = next.continuation
}

searchSuggestions

Fetches type-ahead search suggestions and recommended items for the given query prefix.
query
String
required
The partial query string to generate suggestions for.
client
YouTubeClient
default:"WEB_REMIX"
The InnerTube client context.
Returns: Result<SearchSuggestions> — contains queries: List<String> (text suggestions) and recommendedItems: List<YTItem>.
val suggestions = client.searchSuggestions("billie ei").getOrThrow()
suggestions.queries.forEach { println(it) }

searchSummary

Performs a full search and returns results grouped by category (Top result, Songs, Albums, Artists, Playlists). Useful for building an “All” search tab view.
query
String
required
The search query string.
client
YouTubeClient
default:"WEB_REMIX"
The InnerTube client context.
Returns: Result<SearchSummaryPage> — a SearchSummaryPage with summaries: List<SearchSummary>, where each SearchSummary has a title: String and items: List<YTItem>.

home

Fetches the YouTube Music home feed. Supports continuation tokens for loading more sections.
continuation
String?
default:"null"
Continuation token for fetching additional home sections.
params
String?
default:"null"
Optional browse parameter, used to filter by a chip endpoint.
client
YouTubeClient
default:"WEB_REMIX"
The InnerTube client context.
Returns: Result<HomePage> — a HomePage with chips, sections, and an optional continuation.

newReleaseAlbums

Browses the FEmusic_new_releases_albums endpoint to fetch a flat list of newly released albums.
client
YouTubeClient
default:"WEB_REMIX"
The InnerTube client context.
Returns: Result<List<AlbumItem>>

album

Fetches full album metadata and optionally its complete song list. When withSongs = true, the method first fetches inline songs from the browse response, then fetches the full song list from the album’s playlist endpoint (with continuation handling for large albums). If the playlist fetch fails but inline songs were found, those are returned as a fallback.
browseId
String
required
The album’s browse ID (e.g. "MPREb_xxxxxxxxxxxx").
withSongs
Boolean
default:"true"
When true, fetches and returns the full track listing. Set to false for metadata-only requests.
client
YouTubeClient
default:"WEB_REMIX"
The InnerTube client context.
Returns: Result<AlbumPage>

albumSongs

Fetches the song list for an album using its playlist ID directly. Handles pagination automatically, up to 50 continuation requests. Duplicate songs (by videoId) are deduplicated.
playlistId
String
required
The album’s associated playlist ID (e.g. "OLAK5uy_xxxx").
album
AlbumItem?
default:"null"
Optional parent AlbumItem used to populate each SongItem’s album field and thumbnail fallback.
client
YouTubeClient
default:"WEB_REMIX"
The InnerTube client context.
Returns: Result<List<SongItem>>

artist

Fetches an artist’s page, including sections (songs, albums, singles, videos, playlists, related artists), description, subscriber count text, and monthly listener count.
browseId
String
required
The artist’s channel browse ID (e.g. "UCxxxxxxxxxxxxxxxxxxxxxx").
client
YouTubeClient
default:"WEB_REMIX"
The InnerTube client context.
Returns: Result<ArtistPage> — includes subscriberCountText and monthlyListenerCount parsed from the immersive header.

playlist

Fetches a playlist’s metadata and its initial page of songs. The PlaylistItem.isEditable field reflects whether the authenticated user owns the playlist.
playlistId
String
required
The playlist ID (without VL prefix). The method prepends VL internally before browsing.
client
YouTubeClient
default:"WEB_REMIX"
The InnerTube client context.
Returns: Result<PlaylistPage> — contains playlist, songs, songsContinuation, and continuation.
val page = client.playlist("PLxxxxxxxxxxxxxx").getOrThrow()
println(page.playlist.title)
page.songs.forEach { println(it.title) }

iOS usage example

PortableInnertube is fully usable from Swift via the Kotlin/Native framework generated by the KMP build. The Darwin HTTP engine is used automatically — no extra configuration is needed.
// In commonMain shared code (Kotlin)
class MusicRepository(private val inner: PortableInnertube) {

    suspend fun fetchArtist(browseId: String): ArtistPage {
        return inner.artist(browseId).getOrThrow()
    }

    suspend fun fetchAlbum(browseId: String): AlbumPage {
        return inner.album(browseId, withSongs = true).getOrThrow()
    }

    suspend fun searchAll(query: String): List<YTItem> {
        return inner.search(query).getOrThrow().items
    }
}
On the Swift side, the KMP-generated PortableInnertube class is called using async/await via the Kotlin/Native coroutine bridge:
// Swift (iOS)
let inner = PortableInnertube(
    locale: YouTubeLocale(gl: "US", hl: "en-US")
)

let repo = MusicRepository(inner: inner)

Task {
    let artist = try await repo.fetchArtist(browseId: "UCxxxxxxxxxxxxxxxxxxxxxx")
    print(artist.artist.title)
    for section in artist.sections {
        print(section.title, section.items.count)
    }
}
PortableInnertube does not include retry logic. For resilient production use on Android, prefer the YouTube singleton which has built-in exponential backoff. Use PortableInnertube when you need a portable, iOS-compatible API surface in shared KMP code.

Build docs developers (and LLMs) love