TL;DR
- Starting from v5.2.5, playback endpoints are reverted: not signed in →
android_vr (same as NewPipe), signed in → tv_downgraded
- SABR playback is temporarily disabled; the implementation is preserved in the codebase
- Reason: the visitorData / PO Token verification that SABR relies on is being probabilistically rejected server-side — success rates fluctuate between 30% and 70% per video depending on IP and local time, making playback unreliable
android_vr also encounters 403 errors randomly, but at a failure rate of roughly 5% or lower
tv_downgraded (signed-in) does not exhibit 403 errors
Why so many releases in one month?
We were not shipping broken code over and over. YouTube has been tightening playback restrictions continuously, and we were chasing a moving target. Here is what happened:
Timeline
| Version / Period |
What happened |
| After 5.1.1 |
Sporadic 403 reports on the android_vr endpoint began appearing |
| 5.2.0 |
Experimental SABR support added; main playback path remained android_vr |
| Days after 5.2.0 |
403 reports on android_vr became noticeably more frequent. Meanwhile, web_safari — the other endpoint in use — was also approaching failure. We concluded that a swift transition to SABR was necessary |
| 5.2.2 |
Main playback path switched to SABR, with the ability to fall back to android_vr retained |
| 5.2.3 |
With SABR now serving all users, the volume of requests exposed many more edge cases and a significant performance regression. This release fixed most edge cases and substantially improved performance. Further reports after release allowed us to resolve the remaining edge cases and optimize performance further |
| 5.2.4 |
SABR implementation was essentially complete — virtually no edge-case issues remained. At the time of release, playback worked near-perfectly |
| Days after 5.2.4 |
A new symptom appeared: playback increasingly hit an infinite error loop around the 1-minute mark. This was not an implementation bug (see below) |
| 5.2.5 beta |
Tested visitorData / PO Token implementations from yt-dlp, googlevideo, LibreTube, SmartTube, Grayjay, and others — none achieved a 100% success rate |
| 5.2.5 (imminent) |
Playback endpoints reverted to android_vr / tv_downgraded |
What does "1-minute error loop" actually mean?
SABR responses carry a playback status field:
| Status |
Meaning |
Practical effect |
| 1 |
OK |
Full stream can be fetched |
| 2 |
Pending attestation |
Already a precursor to rejection — only the first ~60 seconds of the stream are served |
| 3 |
Rejected |
Stream cannot be fetched at all |
When the server returns status 2, playback appears to work at first, but the moment it reaches the 60-second boundary — or if the user seeks past 60 seconds from the start — it immediately escalates to status 3. The user sees the player stuck at roughly the 1-minute mark, retrying and failing in a loop.
The end result is effectively identical to the old 403 problem (only the first ~60 seconds are accessible). The difference is that android_vr does not require a PO Token at all, and its failure rate is far lower.
This is not a bug in our SABR implementation. The server is rejecting our requests. When 5.2.4 was first released, status 2/3 responses were virtually nonexistent; within days, their frequency increased significantly.
The problem is visitorData, but we don't know the exact mechanism
Success rates vary by IP address and local time. For the same video, the probability of getting status 1 ranges from roughly 30% to 70%, and this variance is governed by the visitorData token.
During the 5.2.5 beta cycle we evaluated every notable public implementation of visitorData / PO Token generation we could find — yt-dlp, googlevideo, LibreTube, SmartTube, Grayjay, among others. Not a single one guarantees 100% success. We suspect YouTube has introduced a verification step that has not yet been publicly analyzed, and is using probabilistic failure to impede reverse-engineering efforts. As of this writing, the broader community has not found a solution.
Technical details: visitorData, the WebPO minter, and video-bound tokens
“The problem is visitorData” does not mean that PipePipe mints the final SABR media PO Token with visitorData as its content binding.
There are two separate stages:
visitorData
│
├── included in the `/youtubei/v1/att/get` context
├── sent as `X-Goog-Visitor-Id`
└── identifies the attestation/minter epoch
│
▼
BotGuard challenge
│
▼
BotGuard snapshot
│
▼
WAA integrity token
│
▼
WebPO minter associated with that visitor identity
│
│ mint(contentBinding = videoId)
▼
video-bound SABR media PO Token
PipePipe already uses the video ID as the content binding of the final media token. However, that token is minted by a minter created through an attestation chain whose identity starts with visitorData. Replacing visitorData therefore recreates the challenge, integrity token, minter, and all tokens minted from that minter.
Variants tested
| Component |
Variants tested |
Result |
| visitorData source |
Obtained through /youtubei/v1/att/get |
No improvement |
| visitorData source |
Parsed from a youtube.com response |
No improvement |
| visitorData lifetime |
Reuse one identity for its stated 6-hour lifetime |
No improvement |
| visitorData lifetime |
Use a new identity for every request |
No improvement |
| PO Token binding |
Always mint with videoId |
No improvement |
| PO Token binding |
Choose visitorData or videoId according to the token-binding experiment flag returned by youtube.com |
No improvement |
None of these visitorData acquisition, persistence, or PO Token content-binding strategies improved the acceptance rate.
Observed acceptance behavior
Acceptance is not a permanent property of a visitorData value or even of a specific (visitorData, PO Token) pair:
visitorData V
│
├── minter V ── mint(videoId X) ── token PX
│ │
│ ├── request at T1: status 2 / 3
│ └── request at T2: may succeed
│
└── same minter or identity
└── mint(videoId Y) ── token PY
└── probabilistic again
A visitorData identity accepted for one video therefore does not reliably carry that acceptance to the next video. Conversely, a previously rejected visitorData/token combination may be accepted when retried later.
Once a combination is accepted for a playback and playback crosses the 60-second boundary, we have not observed it being rejected later in that same playback. The decision appears to be sticky for the accepted playback, but not for the visitor identity as a whole.
Status 2 behavior
PipePipe already provides a real video-bound PO Token when status 2 is returned. In our environment, status 2 only permits approximately the first minute of media. Reaching or seeking beyond that boundary causes status 3, after which playback cannot continue.
status 1 ──> full playback remains available
status 2 ──> first ~60 seconds
│
└── reach/seek beyond boundary
└── status 3
The only environment in which we have observed status 2 being promoted to status 1 is a real Chrome session. We could not reproduce that transition in headless Chrome or in a Chrome session controlled through Playwright.
This suggests that the unresolved part is an additional verification condition in the visitorData-rooted attestation chain, not the already implemented video-ID content binding.
The decision
The comparison is straightforward:
| Endpoint |
Approximate success rate |
PO Token required |
| SABR |
30–70% |
Yes (visitorData) |
android_vr / vision_os (not signed in) |
~95% |
No |
tv_downgraded (signed in) |
~100% |
No |
For the sake of playback reliability, we are temporarily reverting to the latter two.
The SABR implementation remains in the codebase. Once the community figures out the visitorData verification, we can switch back quickly — the work done this month will not go to waste.
What you need to do
Update to v5.2.5 once it is released. No additional configuration is needed.
If you have technical insights
Reproducing the status 2/3 failure is straightforward and does not require special conditions, so simple reproduction reports are not particularly useful at this point. What would help is information about the underlying verification mechanism — if you have insights into how YouTube validates visitorData or PO Tokens in SABR streams, please share them in this issue.
Looking ahead
android_vr is not a long-term solution — YouTube continues to tighten its restrictions, and SABR remains the protocol it is moving toward. We are still actively experimenting on our end. Once a breakthrough emerges — whether from our own efforts or from others — we will be ready to switch back quickly.
TL;DR
android_vr(same as NewPipe), signed in →tv_downgradedandroid_vralso encounters 403 errors randomly, but at a failure rate of roughly 5% or lowertv_downgraded(signed-in) does not exhibit 403 errorsWhy so many releases in one month?
We were not shipping broken code over and over. YouTube has been tightening playback restrictions continuously, and we were chasing a moving target. Here is what happened:
Timeline
android_vrendpoint began appearingandroid_vrandroid_vrbecame noticeably more frequent. Meanwhile,web_safari— the other endpoint in use — was also approaching failure. We concluded that a swift transition to SABR was necessaryandroid_vrretainedandroid_vr/tv_downgradedWhat does "1-minute error loop" actually mean?
SABR responses carry a playback status field:
When the server returns status 2, playback appears to work at first, but the moment it reaches the 60-second boundary — or if the user seeks past 60 seconds from the start — it immediately escalates to status 3. The user sees the player stuck at roughly the 1-minute mark, retrying and failing in a loop.
The end result is effectively identical to the old 403 problem (only the first ~60 seconds are accessible). The difference is that
android_vrdoes not require a PO Token at all, and its failure rate is far lower.This is not a bug in our SABR implementation. The server is rejecting our requests. When 5.2.4 was first released, status 2/3 responses were virtually nonexistent; within days, their frequency increased significantly.
The problem is visitorData, but we don't know the exact mechanism
Success rates vary by IP address and local time. For the same video, the probability of getting status 1 ranges from roughly 30% to 70%, and this variance is governed by the visitorData token.
During the 5.2.5 beta cycle we evaluated every notable public implementation of visitorData / PO Token generation we could find — yt-dlp, googlevideo, LibreTube, SmartTube, Grayjay, among others. Not a single one guarantees 100% success. We suspect YouTube has introduced a verification step that has not yet been publicly analyzed, and is using probabilistic failure to impede reverse-engineering efforts. As of this writing, the broader community has not found a solution.
Technical details: visitorData, the WebPO minter, and video-bound tokens
“The problem is visitorData” does not mean that PipePipe mints the final SABR media PO Token with visitorData as its content binding.
There are two separate stages:
PipePipe already uses the video ID as the content binding of the final media token. However, that token is minted by a minter created through an attestation chain whose identity starts with visitorData. Replacing visitorData therefore recreates the challenge, integrity token, minter, and all tokens minted from that minter.
Variants tested
/youtubei/v1/att/getyoutube.comresponsevideoIdvisitorDataorvideoIdaccording to the token-binding experiment flag returned byyoutube.comNone of these visitorData acquisition, persistence, or PO Token content-binding strategies improved the acceptance rate.
Observed acceptance behavior
Acceptance is not a permanent property of a visitorData value or even of a specific
(visitorData, PO Token)pair:A visitorData identity accepted for one video therefore does not reliably carry that acceptance to the next video. Conversely, a previously rejected visitorData/token combination may be accepted when retried later.
Once a combination is accepted for a playback and playback crosses the 60-second boundary, we have not observed it being rejected later in that same playback. The decision appears to be sticky for the accepted playback, but not for the visitor identity as a whole.
Status 2 behavior
PipePipe already provides a real video-bound PO Token when status 2 is returned. In our environment, status 2 only permits approximately the first minute of media. Reaching or seeking beyond that boundary causes status 3, after which playback cannot continue.
The only environment in which we have observed status 2 being promoted to status 1 is a real Chrome session. We could not reproduce that transition in headless Chrome or in a Chrome session controlled through Playwright.
This suggests that the unresolved part is an additional verification condition in the visitorData-rooted attestation chain, not the already implemented video-ID content binding.
The decision
The comparison is straightforward:
android_vr/vision_os(not signed in)tv_downgraded(signed in)For the sake of playback reliability, we are temporarily reverting to the latter two.
The SABR implementation remains in the codebase. Once the community figures out the visitorData verification, we can switch back quickly — the work done this month will not go to waste.
What you need to do
Update to v5.2.5 once it is released. No additional configuration is needed.
If you have technical insights
Reproducing the status 2/3 failure is straightforward and does not require special conditions, so simple reproduction reports are not particularly useful at this point. What would help is information about the underlying verification mechanism — if you have insights into how YouTube validates visitorData or PO Tokens in SABR streams, please share them in this issue.
Looking ahead
android_vris not a long-term solution — YouTube continues to tighten its restrictions, and SABR remains the protocol it is moving toward. We are still actively experimenting on our end. Once a breakthrough emerges — whether from our own efforts or from others — we will be ready to switch back quickly.