Skip to content

Fix YouTube live Picture-in-Picture Error 153 - #1758

Merged
David Pine (IEvangelist) merged 1 commit into
mainfrom
ievangelist-youtube-pip-issue
Oct 1, 2026
Merged

David Pine (IEvangelist) merged 1 commit into
mainfrom
ievangelist-youtube-pip-issue

Conversation

@IEvangelist

Copy link
Copy Markdown
Member

Summary

Fix YouTube's "Video player configuration error — Error 153" in native Document Picture-in-Picture without adding a wrapper page or changing Twitch's player URL.

The live-status API returned the correct live video ID, but the iframe created directly in PiP's initial about:blank document sent no HTTP Referer. YouTube requires that identification; Twitch already receives its explicit parent parameter.

Initialize the newly opened PiP document with document.open() / document.close() before rendering or attaching lifecycle listeners, and explicitly set the iframe's strict-origin-when-cross-origin referrer policy. This is five production lines, including the explanation. No document.write(), additional route, extra request, nested iframe, or new dependency is needed.

Why this approach

The HTML document-open algorithm copies the calling document's URL to the target document. It also clears listeners, which is why initialization occurs before registering the existing pagehide handler and only once per new PiP window. The iframe policy sends only the site origin to YouTube, not the documentation path or query string.

Browser experiments against the current aspire.dev livestream compared:

Approach Observed result
Existing direct iframe No Referer; Error 153
Referrer policy alone No Referer; Error 153
Policy plus origin player parameter No Referer; Error 153
srcdoc wrapper No Referer; Error 153
Blob wrapper No Referer; Error 153
Same-origin hosted wrapper Correct Referer; playback succeeds, but requires a new page and nested iframe
Initialize the PiP document with open/close Correct Referer; playback succeeds without a wrapper

This follows YouTube's embedded-player identification requirement.

Third-party links and affiliations

None. The site continues to use the existing YouTube and Twitch endpoints.

Validation

  • Added real native-PiP tests using full Chromium, intercepting only provider responses so the browser still generates the actual embed request and Referer header. CI does not depend on a live stream or external player playback.
  • Both new cases (video ID and channel fallback) failed on the original implementation with Referer: null and pass with the fix.
  • Coverage includes autoplay/mute parameters, YouTube-to-Twitch-to-YouTube switching, persistence through Astro navigation without recreating the player, close-handler state cleanup, and reopening from a documentation page.
  • pnpm --dir src/frontend exec playwright test tests/e2e/live-pip.spec.ts tests/e2e/live-status.spec.ts --workers=2 --reporter=line: 25 passed, 11 expected viewport-specific skips across desktop/tablet/mobile.
  • Targeted ESLint for the new test and Prettier checks for both changed files passed. Astro files are not covered by this repository's ESLint configuration.
  • Confirmed actual livestream playback in a real native PiP browser experiment after open/close initialization (Referer: https://aspire.dev/, video readyState 4, paused false).
  • No local production build run.

Initialize the native PiP document from its opener before rendering embeds so YouTube receives the required Referer header. Cover real browser requests and PiP lifecycle without loading external providers in CI.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings September 25, 2026 17:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

No unresolved review comments remain, and the supplied validation covers the fix.

Review effort: Lite
Findings: None

What changed in this PR

Fixes YouTube Error 153 in native Document Picture-in-Picture by preserving the site referrer.

Changes:

  • Initializes the PiP document with document.open()/document.close().
  • Applies an explicit iframe referrer policy.
  • Adds Chromium E2E coverage for fallback, switching, navigation, and cleanup.
File Description
src/​frontend/​tests/​e2e/​live-pip.spec.ts Verifies referrers, provider switching, navigation, cleanup, and reopening.
src/​frontend/​src/​components/​LivePip.astro Initializes the PiP document and configures iframe referrer handling.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@aspire-repo-bot

Copy link
Copy Markdown
Contributor

Frontend HTML artifact ready

The latest frontend build uploaded the frontend-dist artifact for PR #1758. Use the VS Code button below to open this PR with GitHub Artifacts Explorer and browse the built HTML locally.

VS Code: Open PR #1758 artifacts

This comment updates automatically when a new frontend build artifact is uploaded.

Comment on lines +376 to +377
pipWindow.document.open();
pipWindow.document.close();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a hack. Is this the real way to handle the problem?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair question. This is a standards-defined workaround for the missing referrer, not a YouTube- or Chrome-documented PiP recipe. I should distinguish those rather than imply this is the official PiP solution.

The relevant behavior is explicit in the HTML specification's document open steps:

  • It obtains entryDocument from the calling environment and requires the target document to be same-origin.
  • For a fully active target document, it says: “Let newURL be a copy of entryDocument's URL.” If the documents differ, it removes the fragment, then runs the URL and history update steps for the target document with that URL.
  • It sets the target document's “is initial about:blank” flag to false.
  • It clears the target document's contents and its DOM/window event listeners, then creates an HTML parser. document.close() closes that input stream; we subsequently create the iframe through the DOM API, without document.write() or HTML string injection.

That URL change is the part we need: PiP initially contains an about:blank document, and the direct YouTube embed request had no HTTP Referer. Calling open() from the opener gives the PiP document the opener's URL, allowing Chromium to generate the header normally. The explicit strict-origin-when-cross-origin policy sends only our origin to YouTube, not the documentation path or query. This satisfies YouTube's embedded-player identification requirement.

The destructive effects are why these calls run only on the newly created, empty PiP document, before registering the pagehide listener or adding the iframe—never during provider switches or reuse of an existing PiP window.

I compared alternatives in a real native PiP window against the livestream. Referrer policy alone, adding origin, a srcdoc wrapper, and a blob wrapper all still produced Error 153. A hosted same-origin wrapper also worked, but adds a page/request and nested iframe. The open/close initialization restored Referer: https://aspire.dev/ and actual playback without that extra structure.

The new tests use a real native PiP window and inspect the browser-generated request, stubbing only the provider response. Both video-ID and channel-fallback cases failed with a null referrer before the fix and pass after it; they also cover provider switching, client navigation, and close/reopen cleanup. On that evidence, I prefer this smaller, standards-defined workaround to the hosted wrapper.

Auto-replied by the GitHub Copilot app

@eerhardt Eric Erhardt (eerhardt) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a hack, but if you (and your agent) are convinced it is the correct approach, let's do it.

@IEvangelist
David Pine (IEvangelist) merged commit f5b99e4 into main Oct 1, 2026
15 checks passed
@IEvangelist
David Pine (IEvangelist) deleted the ievangelist-youtube-pip-issue branch October 1, 2026 18:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants