January 2026
Video Grabber - Chromium MV3 Browser Extension
TypeScript, React, yt-dlp, ffmpeg.wasm, OPFS, Chrome Extension APIs
A YouTube downloader extension for friends and family that runs yt-dlp and ffmpeg entirely in the browser. No server, resumable jobs.
Visit source
Running yt-dlp from the command line isn't everyone's cup of tea, and I wanted my friends and family to be able to grab YouTube videos without it. So I built them a browser extension.
The first version ran on a VPS. That was easier to build and worse to live with. I had to run infrastructure, people had to trust my server, and the backend had to keep rotating IPs to get past bot detection. All of that for a job the user's own browser can do.
So I scrapped that direction completely and rebuilt it as a strict client-side Chromium Manifest V3 extension.
The runtime
Manifest V3 is a hard place to run long media jobs. The browser can put the service worker to sleep in the middle of a job, and anything heavy has to move out of it.
The new architecture uses:
- a background service worker that coordinates jobs
- an offscreen document for the heavy WASM work
- ffmpeg.wasm for media processing
- a WASM build of yt-dlp, also offscreen, for extraction and download
- OPFS checkpoints and
chrome.storagemetadata so jobs can resume
The browser does all the work. No VPS, no backend.
When things break
I'm proudest of the failure handling.
Media work inside an extension fails in a lot of annoying ways: network changes, tab state changes, runtime resets, permissions, storage limits, muxing errors, extraction breakage, and users who don't behave like the nice diagram in your head.
So I wrote down how the extension handles each one:
- An error taxonomy. Every runtime failure maps to a fixed error code, like
STORAGE_QUOTA_EXCEEDEDorDOWNLOAD_URL_EXPIRED. - A recovery matrix. It says what happens after each failure. If the browser kills the service worker mid-download, the job restores from its OPFS checkpoint and goes back in the queue.
- Mux guardrails. ffmpeg copies the streams first instead of re-encoding them, and rejects inputs over about 1.8 GB.
- A breakage triage runbook, for when extraction stops working.
- A support contract. It lists what the extension supports and what it won't, such as DRM-protected streams.
There's also an open-source distribution strategy. I can't publish this on the Chrome Web Store, since it breaks most of YouTube's T&Cs.
Sounds like overkill, until you realise that without it every failure is just "it broke" and every fix is vibes.
Why it was worth it
The constraints are the whole point of this project. MV3 makes you think about lifetimes. WASM makes you think about cost and memory. OPFS makes you think about recovery. Distribution policy decides what the project is allowed to be, whatever it can technically do.
It looks like a small extension. Underneath, it has an unreliable runtime, heavy media work, resumable state, and no server to fall back on. It was awkward to build and very satisfying once everything worked.
A couple of my friends and family now use it at least once a week, which is about the best review I could ask for.