# yt-dlp-web-ui: a self-hosted web UI and RPC server for yt-dlp

> yt-dlp-web-ui wraps the yt-dlp command line in a Go server with a browser frontend, a download queue and an optional RPC layer. It is built for people who want downloads to land on a NAS or home server, and its v4 release is a breaking migration.

**marcopiovanello/yt-dlp-web-ui** — A terrible web ui and RPC server for yt-dlp. Designed to be self-hosted.

- Repository: https://github.com/marcopiovanello/yt-dlp-web-ui
- Stars: 2,589 · Forks: 252
- Language: Go
- License: GPL-3.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/marcopiovanello-yt-dlp-web-ui

## What yt-dlp-web-ui is for, and who it is not for

yt-dlp is a command line program. That is fine when you are sitting at a terminal, and awkward when the machine doing the downloading is a headless NAS in another room and you want to check on a queue from a laptop. yt-dlp-web-ui exists to close that gap: the README says it was "Created for the only purpose of fetching videos from my server/nas and monitor upcoming livestreams." The author's own description of the frontend is "A not so terrible web ui for yt-dlp," which sets the tone better than any marketing line would.

The audience is narrow and specific. You need a host that runs continuously, a place to put the files, and enough patience to mount two volumes correctly. In exchange you get a browser interface, a bounded download queue, and an RPC surface that other programs can call. The topics list on the repository names raspberrypi and self-hosted, which matches the design: a Go binary with a static frontend, low resource use, no external database server required.

It is the wrong tool for three groups. Anyone who wants a desktop application with a file picker and a progress bar in a native window will find a web page served on port 3033 instead. Anyone who wants a managed service that handles updates, storage and legal exposure for them is looking at the wrong category entirely. And anyone who needs a frozen API contract should read the v4 migration note before anything else, because the server changed shape between v3 and v4.

## The Go server, the queue, and the RPC layer

The repository layout tells most of the story. main.go sits at the top level, with server/ and frontend/ beside it, plus proto/ and openapi/ directories. The Go module is github.com/marcopiovanello/yt-dlp-web-ui/v4, and go.mod pins go 1.26 along with go-chi/chi for routing, gorilla/websocket, golang-jwt/jwt, robfig/cron, spf13/viper for configuration and go.etcd.io/bbolt for local storage. That is a single self-contained process: HTTP routes, a websocket channel for live updates, an embedded key-value store, and a scheduler.

The download queue is the part that matters operationally. The -qs flag sets the queue size, and the README shows the Docker invocation for limiting to two concurrent downloads. The config file comment describes queue_size as optional with a default of logical CPU cores and a minimum of 2. Downloads are therefore serialised through a pool rather than fired off freely, which is what keeps a Raspberry Pi from thrashing when someone pastes twenty URLs.

yt-dlp itself is not vendored. The server shells out to an executable, located by the -driver flag (default "yt-dlp"), and the Dockerfile installs it from PyPI with a long extras list: default, curl-cffi, mutagen, pycryptodomex, phantomjs and secretstorage, on top of ffmpeg, deno, curl and wget from Alpine. So the container is not a thin wrapper around a Go binary. It is a Python image carrying a full yt-dlp installation plus a JS runtime for extractors that need one. The proto/ and openapi/ directories suggest the RPC interface is specified rather than improvised, though the README does not document the individual endpoints.

## Installing yt-dlp-web-ui via Docker and running a first download

The README's preferred path is Docker, and the published images are on Docker Hub and ghcr.io. Pull the v4 tag:

```bash
docker pull marcobaobao/yt-dlp-webui:v4
```

Run it with a host directory mounted at /downloads. The README example maps port 3033 to 3033, which is also the default listen port:

```bash
docker run -d -p 3033:3033 -v <your dir>:/downloads marcobaobao/yt-dlp-webui
```

Open http://localhost:3033 in a browser. The frontend is served from the same process, so there is no separate static host to configure. Paste a video URL and the job enters the queue; with the default settings the queue size is the logical CPU core count, and the -qs flag overrides it.

If you want authentication on the RPC surface, the README shows the flags and the environment variable together. Note that JWT_SECRET is passed with -e, and --auth, --user and --pass go after the image name:

```bash
docker run -d \
    -p 3033:3033 \
    -e JWT_SECRET randomsecret \
    -v /path/to/downloads:/downloads \
    marcobaobao/yt-dlp-webui \
    --auth \
    --user your_username \
    --pass your_pass
```

For a persistent setup, the compose file in the repository adds a /config volume and a healthcheck that curls localhost:3033. The Dockerfile's entrypoint runs the binary with --conf /config/config.yml, so a config.yml placed in that volume is read on start. The README notes that the config file will overwrite what has been passed as a CLI argument, which is a trap worth knowing before you spend an hour debugging a flag that is being ignored. Prebuilt binaries are also published on the releases page for people who do not want containers; the README shows moving the binary to /usr/local/bin and running it with --out and optionally --driver.

## Where the design gets in your way

The config precedence rule is the sharpest edge. A config file silently wins over command line flags. If you run the container with --qs 2 but a config.yml in the mounted /config volume sets queue_size: 4, you get four. The README states the behaviour plainly, but it inverts the usual expectation that explicit flags beat a file, and there is no warning printed at startup according to the documentation.

Authentication is optional and off unless you ask for it. The README describes --auth as enabling RPC authentication, with a username and password, and the Docker example pairs it with a JWT_SECRET environment variable. The README does not document what happens if JWT_SECRET is unset while --auth is enabled, and it does not describe token lifetime or revocation. If the server is reachable from a network you do not control, that gap matters more than any feature on the settings page.

The v4 release is a breaking change. The README carries a note pointing to a wiki migration guide rather than a compatibility shim, and the release is titled "Server v4." Upgrading from v3.2.6 means reading that guide. There is also an open poll in the discussions about the future of the frontend, which tells you the interface is not settled. For a tool you check once a week that is acceptable; for something you script against, it is a reason to pin a tag.

Finally, the README does not document rollback, and it does not document the individual RPC endpoints despite shipping proto/ and openapi/ directories. You can see that an interface exists; you cannot learn its shape from the README alone.

## Alternatives and how they differ in approach

The most direct comparison is yt-dlp itself, driven from a shell. The difference is not capability, since the web UI is ultimately invoking the same binary with arguments you could type. The difference is state. A shell command is fire and forget; yt-dlp-web-ui keeps a queue in a bbolt database, exposes progress over a websocket, and lets a second person watch the same job list. If your downloads are one-off and you are already at the terminal, the wrapper adds a container, a port and a config file for no gain.

The other common approach is a desktop GUI frontend for yt-dlp. That inverts the deployment model: the binary runs on the machine with the screen, downloads land locally, and there is no server to reach. yt-dlp-web-ui is the opposite by construction. It is designed to be self-hosted and reached over the network, and the repository topics include raspberrypi and rpc-server. If your NAS has no display and your laptop is the only screen in the house, the desktop model does not work at all, and that is precisely the case this project targets.

A third option is writing a small wrapper yourself around the yt-dlp binary and a job table. That is a realistic choice for a team that needs a specific API shape, because the README does not document the RPC endpoints and the interface has already changed once at v4. The trade is maintenance: you own extractor updates, queue persistence and the frontend, all of which this project already ships.

## Licence, maintenance and what an upgrade costs

The licence is GPL-3.0. If you run it as a service for yourself, that is unremarkable. If you modify it and distribute the result, or offer a modified version over a network, the copyleft terms apply to the derived work. This is not legal advice; check with someone qualified before shipping a modified build to third parties. Note also that the container bundles yt-dlp and ffmpeg, which carry their own licences separate from this project's.

The last push to the repository was on 2026-08-21, and the most recent release is v4.0.0 from 2026-06-29. The repository is not archived. That is a roughly two-month gap between the v4 release and the last commit, which is consistent with a project that is still being worked on, but the release history is lumpy: v3.2.6 in March 2025, v3.2.5 in February 2025, then a jump to v4 in mid-2026. Do not read cadence into it either way.

Upgrade cost is the real budget item. The v4 migration guide is a wiki page, not a changelog entry, which suggests the server surface moved enough to need instructions. Because the config file overrides CLI arguments, an upgrade can change effective settings without any error, so diff your config.yml against the arguments you pass before and after. The Dockerfile pins pnpm@11.4.0 for the frontend build and installs yt-dlp from PyPI unpinned, so rebuilding the image yourself can pull a different yt-dlp than the published tag did. Pull the tag if you want reproducibility.

## Conclusion

Adopt it if you already run yt-dlp on a machine that stays on and you want a queue, a browser frontend and an RPC endpoint without writing your own wrapper. Do not adopt it if you need a desktop GUI, a hosted service, or a stable API surface you cannot re-test between releases, because v4 changed the server and ships a migration guide rather than a compatibility layer. Before committing, verify three things: that your downloads and config volumes are mounted where the image expects them, that JWT_SECRET is set if you enable --auth, and that config.yml does not silently override the flags you passed on the command line.

## FAQ

### Is there a GUI version of yt-dlp?

yt-dlp-web-ui is one: it serves a browser frontend on port 3033 and wraps the yt-dlp executable, which it locates via the -driver flag. The README describes it as a web ui and RPC server designed to be self-hosted, so the interface runs on a server you control rather than on your desktop.

### Is yt-dlp illegal?

The repository does not address the legality of downloading. It ships under GPL-3.0 and documents installation, flags and configuration only, so questions about what you are permitted to download from a given site are outside what this material can answer.

### How to use yt-dlp gui?

Run the container with a downloads directory mounted, then open port 3033 in a browser and paste a URL. The README's example is a single docker run with -p 3033:3033 and -v <your dir>:/downloads; format selection is off by default and is enabled from the settings page.

### Is there a YouTube dl gui available?

Yes, and this project is one of them. It is a self-hosted web UI rather than a desktop application, so it is reached over the network and its download queue lives in a local database on the host.

## Sources

- [Issues](https://github.com/marcopiovanello/yt-dlp-web-ui/issues)
- [License: GPL-3.0](https://github.com/marcopiovanello/yt-dlp-web-ui/blob/master/LICENSE)
- [marcopiovanello/yt-dlp-web-ui on GitHub](https://github.com/marcopiovanello/yt-dlp-web-ui)
- [README](https://github.com/marcopiovanello/yt-dlp-web-ui/blob/master/README.md)
- [Releases](https://github.com/marcopiovanello/yt-dlp-web-ui/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/marcopiovanello-yt-dlp-web-ui
