This guide walks you through adding Zemer Cipher to an Android project, initializing the library at app startup, deciphering a YouTube stream URL (signature deobfuscation + n-parameter transformation), and generating a BotGuard PoToken for web client streams. By the end you will have a fully working playback pipeline that self-heals across YouTube player rotations.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ZemerTeam/zemer-cipher/llms.txt
Use this file to discover all available pages before exploring further.
Add the dependency
Zemer Cipher is published via Sync your project after saving.
maven-publish. Declare the dependency in your app module’s build.gradle.kts and make sure google() and mavenCentral() are listed in your project’s dependency resolution repositories:Initialize in Application class
Call Register
ZemerCipher.initialize() once during Application.onCreate(). Initialization sets up the shared OkHttpClient, starts a background player-config refresh, and prepares the CipherDeobfuscator context. All other library calls will throw if this step is skipped.MyApplication in your AndroidManifest.xml:Decipher a stream URL
All
CipherDeobfuscator methods are suspend functions. Call them from a coroutine scope — for example, inside a viewModelScope.launch block or a repository function running on Dispatchers.IO.Generate a PoToken (web client streams)
Web client (The two tokens have different bindings by design:
WEB_REMIX, WEB) streams increasingly require a BotGuard PoToken. PoTokenGenerator manages a dedicated WebView that mints tokens for a given session.playerRequestPoToken is session-bound (safe to reuse across videos in the same session) while streamingDataPoToken is video-bound (must be regenerated per video). PoTokenGenerator handles this automatically.Prewarm (optional)
On first playback the library fetches ~2.8 MB of player JS and loads it into a WebView, which takes 2–5 seconds on a typical device. Call
CipherDeobfuscator.prewarm() in a background coroutine shortly after ZemerCipher.initialize() to absorb that latency before the user requests playback:prewarm() is guarded by the same mutex as deobfuscateStreamUrl and transformNParamInUrl, so it cannot race a real request. If it fails for any reason the WebView is created lazily on first use instead.All
CipherDeobfuscator methods — signatureTimestamp(), deobfuscateStreamUrl(), transformNParamInUrl(), prewarm(), and onStreamRejected() — are suspend functions. They must be called from a coroutine or another suspend function; calling them from a regular thread will not compile.