YouTube requires a Proof of Origin Token (PoToken) for stream access through theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/faraasaaay/innertube-v2/llms.txt
Use this file to discover all available pages before exploring further.
WEB_REMIX and TVHTML5 clients. The token proves the request originates from a genuine browser or WebView environment by running YouTube’s BotGuard integrity challenge inside a real Android WebView.
PoToken generation requires a real Android WebView. It will not work in pure JVM or server environments. If the system WebView is unavailable or broken,
PoTokenGenerator returns null gracefully rather than throwing.How PoTokens Work
Two distinct tokens are required for each play session:| Token | Where It Goes | Description |
|---|---|---|
playerRequestPoToken | YouTube.player(poToken = ...) parameter | Authenticates the player endpoint request itself |
streamingDataPoToken | Appended as &pot= to the stream URL | Authenticates each CDN stream fetch |
class PoTokenGenerator
The high-level entry point. Manages a PoTokenWebView instance internally, including creation, expiry detection, and automatic recreation on failure.
getWebClientPoToken(videoId: String, sessionId: String): PoTokenResult?
| Parameter | Type | Description |
|---|---|---|
videoId | String | The YouTube video ID for which the player token is needed |
sessionId | String | Session identifier — use YouTube.dataSyncId for logged-in users, YouTube.visitorData for guests |
PoTokenResult with both tokens, or null if:
- The system WebView is unavailable (
webViewSupported == false) - The system WebView has been detected as broken (
webViewBadImpl == true)
- Thread-safe via a
Mutex— concurrent calls queue rather than creating duplicate WebViews. - On the first call (or when the session changes): creates a new
PoTokenWebView, runs the BotGuard challenge, generates the streaming token forsessionId, then generates the player token forvideoId. - On subsequent calls with the same session: reuses the existing WebView; only generates a new player token for
videoId. - On
PoTokenException: re-throws — the caller should handle this as a playback failure. - On
BadWebViewException: setswebViewBadImpl = trueand returnsnull— no further PoToken attempts are made. - On WebView expiry (
isExpired == true): automatically recreates the WebView and regenerates the streaming token.
class PoTokenWebView
The low-level WebView that runs the BotGuard challenge. Used internally by PoTokenGenerator. You typically do not interact with this class directly.
companion object.getNewPoTokenGenerator(context: Context): PoTokenWebView
PoTokenWebView instance.
Must be called on the Main dispatcher. Uses suspendCancellableCoroutine internally and returns only after the BotGuard initialization sequence completes:
- Loads
po_token.htmlfrom assets into the WebView - Calls
https://www.youtube.com/api/jnn/v1/Createto obtain a challenge - Runs
runBotGuard()inside the WebView JavaScript context - Calls
https://www.youtube.com/api/jnn/v1/GenerateITwith the BotGuard response - Creates the PoToken minter with the resulting integrity token
PoTokenException or BadWebViewException on failure.
generatePoToken(identifier: String): String
suspendCancellableCoroutine.
Returns: The PoToken as a URL-safe base64 string.
Throws: PoTokenException or BadWebViewException on JavaScript error.
val isExpired: Boolean
true when the integrity token from the BotGuard challenge has expired. PoTokenWebView applies a 10-minute safety margin — isExpired returns true 10 minutes before the actual token expiry to prevent using a token that could expire mid-request.
When isExpired is true, PoTokenGenerator automatically discards the old WebView and creates a fresh one on the next getWebClientPoToken() call.
fun close()
about:blank before calling destroy() to ensure the WebView is fully torn down. Called automatically by PoTokenGenerator when recreating the WebView.
class PoTokenResult
The result object returned by PoTokenGenerator.getWebClientPoToken().
| Field | Type | Description |
|---|---|---|
playerRequestPoToken | String | Pass this to YouTube.player(poToken = ...) |
streamingDataPoToken | String | Append this as &pot= to the stream URL after deobfuscation |
class PoTokenException
SyntaxError). The message contains the JavaScript error string.
class BadWebViewException
SyntaxError is reported in the WebView console. This indicates the installed WebView APK does not support the JavaScript features required by BotGuard.
When BadWebViewException is caught by PoTokenGenerator, it sets webViewBadImpl = true and stops attempting PoToken generation for the lifetime of the PoTokenGenerator instance.
fun buildExceptionForJsError(error: String): Exception
- Returns
BadWebViewExceptioniferrorcontains"SyntaxError" - Returns
PoTokenExceptionfor all other JavaScript errors
PoTokenWebView to produce the right exception from WebView console error callbacks.