youtube-transcript-to-pdf

Transcript to PDF for YouTube

A Manifest V3 Chrome extension that takes a YouTube URL, pulls the video’s transcript, and exports it as a formatted PDF — no server, no API key, no third-party service. Everything runs locally in the browser.

Features

Install (unpacked)

git clone https://github.com/<you>/youtube-transcript-to-pdf.git
cd youtube-transcript-to-pdf
  1. Open chrome://extensions.
  2. Turn on Developer mode.
  3. Click Load unpacked and select this directory.
  4. Pin the extension and click it on any YouTube video.

How it gets the transcript

Since 2024, YouTube requires a browser-minted proof-of-origin token on caption downloads. A plain request to the timedtext endpoint — even one carrying the user’s cookies — comes back HTTP 200 with an empty body. The extension therefore tries two strategies in order:

  1. Direct download. Reads the caption track list off the watch page and fetches timedtext. Silent and instant when YouTube allows it.
  2. Transcript panel. Loads the watch page in a tab — reusing one already open on that video, otherwise opening a background tab it closes again — and reads YouTube’s own transcript panel, which is rendered by a session that holds a valid token.

Strategy 2 is what works most of the time. It is slower and briefly opens a tab, which is the price of YouTube’s token requirement.

Architecture

Path Role
manifest.json MV3 manifest: permissions, service worker, popup, icons.
src/background/service-worker.js Owns all network and tab work; runs the two strategies.
src/content/scrape-transcript.js Injected on demand; reads the transcript panel.
src/lib/youtube.js URL parsing and watch-page scraping. Pure, unit-tested.
src/lib/transcript.js Caption parsing (json3 + legacy XML) and formatting. Pure.
src/lib/pdf.js Dependency-free PDF writer. Pure.
src/popup/ Popup UI. Builds the PDF and triggers the download.
src/viewer/ Printable page for the Chrome “Save as PDF” path.

The popup is a thin client: it sends one message and renders the reply, so closing it mid-fetch cannot abort the work. The service worker holds no state in module scope, since MV3 terminates it after roughly 30 seconds idle.

src/lib/ has no chrome.* dependency, which is what makes it testable under plain Node.

Permissions

Permission Why
tabs Read the active tab’s URL to prefill the input, and find an open tab showing the requested video.
scripting Inject the transcript-panel reader when the direct download is blocked.
storage Remember formatting preferences; pass the transcript to the printable viewer.
downloads Save the generated PDF.
host_permissions on youtube.com Fetch watch pages and caption tracks. Scoped to YouTube only.

No analytics, no telemetry, no remote code. Transcript data never leaves the machine. Requests to YouTube are sent with credentials: 'omit', so the user’s YouTube session is not attached.

Development

npm test              # 31 unit tests over the pure modules
npm run lint:manifest # manifest + icon-dimension validation
npm run lint:docs     # documentation index validation
npm run check         # all three
npm run build         # dist/youtube-transcript-to-pdf-<version>.zip

Tests run on the Node built-in test runner — no dependencies to install.

See CONTRIBUTING.md for the reload matrix, debugging notes, and the bar for a pull request.

Limitations

Documentation

Doc Covers
docs/ARCHITECTURE.md The proof-of-origin constraint, the two strategies, design decisions
docs/COMPONENTS.md Every module, its exports and dependencies
docs/DEVELOPMENT.md Setup, the reload matrix, debugging, troubleshooting
docs/INSTALLATION.md Install, verify, upgrade, uninstall
docs/SECURITY.md Permission justifications and threat model
docs/TESTING.md Automated coverage and the manual test plan
docs/known-issues.md Current limitations and what is not a bug
docs/onboarding.md A first-hour path through the codebase
docs/runbooks/ Fixing a YouTube markup change; cutting a release

Privacy

No data is collected, stored, or transmitted. The only host the extension can reach is youtube.com, and requests are made without your cookies attached. Full policy: PRIVACY.md (published copy).

Contributing

Issues and pull requests welcome — see CONTRIBUTING.md and the Code of Conduct. Report security issues privately per .github/SECURITY.md.

License

MIT — see LICENSE.