PoTokenRequired: exp=xpe in captionTrack baseUrl returns empty body — no workaround available (v1.2.4)
Description
When fetching transcripts for certain YouTube videos, the library raises PoTokenRequired instead of returning the transcript. This happens even for videos that clearly have captions visible in the YouTube UI and accessible when browsing normally.
Environment
- youtube-transcript-api version: 1.2.4
- Python: 3.12.6
- OS: Windows 10 Pro 10.0.19045
Steps to reproduce
from youtube_transcript_api import YouTubeTranscriptApi
api = YouTubeTranscriptApi()
transcript = api.fetch('VIDEO_ID', languages=['it', 'en'])The exception is raised for videos whose caption track baseUrl (inside ytInitialPlayerResponse.captions.playerCaptionsTracklistRenderer.captionTracks) contains the &exp=xpe query parameter. When this parameter is present, YouTube's timedtext endpoint returns an empty HTTP 200 response body for any programmatic request — including requests that carry valid session cookies from a logged-in browser.
Expected behaviour
api.fetch() returns transcript segments, or raises a specific exception with documented guidance on how to work around the PoToken requirement.
Actual behaviour
youtube_transcript_api._errors.PoTokenRequiredNo documented way to supply a PoToken exists. Passing a requests.Session pre-loaded with valid YouTube cookies does not help, because the PoToken is not a cookie — it is a cryptographic proof-of-origin token generated at runtime by the YouTube player JavaScript and appended as a query parameter (&pot=...) to the URL.
Additional context
- Affects only videos whose
captionTracks[].baseUrlalready contains&exp=xpe. - Distinct from
IpBlocked/RequestBlocked: those indicate server-side IP banning; this is a client-side authentication requirement that no amount of IP rotation resolves. - The transcript IS accessible by clicking "Open transcript" in the YouTube UI in a real logged-in browser — the browser's player JS generates the PoToken transparently.
- Closed issue #454 reported a similar symptom. Reopening because the root cause remains unresolved as of v1.2.4.
Requested fix / workaround
- Document how to provide a PoToken to the library, OR
- Implement automatic PoToken generation (as some yt-dlp forks do via Botguard), OR
- Fall back to an alternative transcript-fetching strategy when
exp=xpeis detected in the base URL (e.g. use the InnerTube/browseendpoint or parse the transcript panel response instead of the timedtext direct URL).
Source: jdepoix/youtube-transcript-api