Self-hosted YouTube archive system. Add channels, playlists, or individual videos — YtVault indexes them, schedules recurring scans, and downloads everything to your own storage.
| Sources | Add New Source |
|---|---|
![]() |
![]() |
| Media Library | Settings |
|---|---|
![]() |
![]() |
- Sources — add YouTube channels, playlists, or single videos by URL
- Collections — group individual videos into custom local playlists
- YouTube search — search YouTube directly from the app to discover content
- Indexing — scans a source with
yt-dlpand stores all video metadata - Downloading — downloads video+audio merged to MP4 via
ffmpeg - Scheduler — set per-source intervals (1h–1 week); auto-download newly found videos
- Media management — pin videos, per-source retention policies, auto-cleanup
- Themes — YouTube 2026 (dark/light) and Classic Obsidian Glass (dark/light)
- Web UI — sidebar navigation, video thumbnails, responsive design
- REST API — full HTTP API for scripting and automation
- Persistent storage — JSON state file + download directory; survives restarts
Docker is the recommended way to run YtVault. The image includes all dependencies (yt-dlp, ffmpeg, Node.js, Python) pre-configured and supports
linux/amd64andlinux/arm64.Tip: For production use, pin a specific version tag (e.g.
ac13139/ytvault:1.1.0) instead of:latest. The:latesttag updates on every commit tomainand may contain unreleased changes.
# docker-compose.yml
services:
ytvault:
image: ac13139/ytvault:1.1.0 # pin version for stability; use :latest for newest
ports:
- "${YTVAULT_PORT:-8080}:8080"
volumes:
- ./data:/data
restart: unless-stoppeddocker compose up -dOpen http://localhost:8080 in your browser.
To pin a specific version:
image: ac13139/ytvault:1.1.0To use a custom port, create a .env file:
# .env
YTVAULT_PORT=9090docker run -d \
--name ytvault \
-p 8080:8080 \
-v ./data:/data \
--restart unless-stopped \
ac13139/ytvault:latestgit clone https://github.com/AC13139/ytvault.git
cd ytvault
docker compose up --build -dPrerequisites: Go 1.26+, yt-dlp, ffmpeg, and nodejs on your PATH.
pip install "yt-dlp[default]" # or: brew install yt-dlp
brew install ffmpeg nodejs # or: apt install ffmpeg nodejs
go run ./apps/apiYouTube blocks automated downloads with bot detection. You must provide cookies from a logged-in YouTube browser session. Without login cookies, most operations will fail with "Sign in to confirm you're not a bot" or "requires authentication" errors.
Chrome / Edge / Brave / Arc (Chromium browsers):
- Install Get cookies.txt LOCALLY extension
- Go to youtube.com and make sure you are logged in
- Click the extension icon → Export → save the file
Firefox:
- Install cookies.txt add-on
- Go to youtube.com and make sure you are logged in
- Click the add-on → "Current Site" → save the file
Safari (macOS):
- Install yt-dlp locally:
brew install yt-dlp - Run:
yt-dlp --cookies-from-browser safari --cookies cookies.txt --skip-download https://www.youtube.com - This generates a
cookies.txtfile in the current directory
Option A — Upload via Web UI (easiest):
- Open YtVault in your browser → go to the Cookies tab
- Upload the
cookies.txtfile or paste its content - Click Save Cookies — validation runs automatically
Option B — Copy to data directory:
- Copy
cookies.txtto thedata/directory on the host - Restart the container:
docker compose restart
Option C — Upload via API:
curl -X POST http://localhost:8080/api/v1/cookies \
--data-binary @cookies.txt \
-H 'Content-Type: text/plain'
curl -X POST http://localhost:8080/api/v1/cookies/validate- Cookies must be from a logged-in session — visitor-only cookies will not work
- Cookies can be exported from any machine — they're not tied to the server
- Cookies expire over time (weeks to months) — re-export when downloads start failing
- For age-restricted videos: verify your age at myaccount.google.com/birthday, then re-export cookies
- The Cookies tab shows validation status and warns when login cookies are missing
The home page. Manage your YouTube sources.
- + Create — add a new source by URL or search YouTube by keywords
- Each source card shows: title, type badge, URL, download progress bar
- Reindex — scan for new videos (with optional date filter)
- Schedule — set up recurring auto-scan (channel/playlist only)
- Retention — set per-source cleanup policy (delete old downloaded media)
- Clean up — manually run retention cleanup
- View — jump to the Media tab filtered to this source
Browse all indexed videos with thumbnails.
- Download All — start downloads for all pending/failed/missing media (respects source filter)
- Filter by source and filter by status (Pending / Downloading / Done / Failed / Missing)
- Pin (star icon) — protect a video from auto-cleanup
- Download / Retry / Re-download — per-video actions based on status
- Click the media info area to copy the file path to clipboard
- Metadata shown: channel, duration, file size, upload date, download date
Monitor all index and download operations.
- Start — manually start a queued task
- Stop — cancel a running task (kills the yt-dlp process)
- Retry — re-queue a failed task
- Stop running / Retry failed / Clear completed — bulk actions
- Filter by status (Queued / Running / Succeeded / Failed)
- Hover over a failed task's "details" link to see the error, click to copy
Overview of recurring scan schedules.
- Inline editing: change interval, date filter, or auto-download — saves automatically
- Start / Pause — enable or disable a schedule without removing it
- Shows last run and next run times
Manage YouTube authentication cookies.
- Status indicator: Valid (green) / Expired (amber) / Missing (red)
- Upload via file picker or paste
- Test Now — validates cookies against YouTube
- Browser-specific setup guides built in
Configure download behavior and appearance.
- Theme — YouTube 2026 or Classic Obsidian Glass
- Dark/Light — toggle via moon/sun button in sidebar
- Folder name / File name — download path templates
- Playlist overrides — use playlist name as folder, playlist index in filename
- Video quality — Best MP4, Best any, 1080p, 720p, Audio only
- Max concurrent downloads — 1 to 5 parallel downloads
- Default retention — global cleanup policy (per-source can override)
All settings are environment variables:
| Variable | Default | Description |
|---|---|---|
YTVAULT_ADDR |
:8080 |
Listen address |
YTVAULT_DATA_PATH |
/data/state.json |
State file path |
YTVAULT_DOWNLOAD_PATH |
/data/downloads |
Download directory |
YTVAULT_COOKIES_PATH |
/data/cookies.txt |
Path to cookies file |
CLI:
| Variable | Default | Description |
|---|---|---|
YTVAULT_API |
http://127.0.0.1:8080 |
API base URL |
go run ./apps/cli <command>Commands:
yd health # check server health
yd source list # list all sources
yd source add video <url> # add a video source
yd source add playlist <url> # add a playlist source
yd source add channel <url> # add a channel source
yd task list # list all tasks
yd task run <task_id> # stub-complete a queued task| Method | Path | Description |
|---|---|---|
GET |
/api/v1/sources |
List all sources |
POST |
/api/v1/sources |
Add a source |
DELETE |
/api/v1/sources/{id} |
Remove a source (cascades) |
GET |
/api/v1/sources/{id}/media |
List media items for a source |
POST |
/api/v1/sources/{id}/reindex |
Start a new index task |
POST |
/api/v1/sources/{id}/download-all |
Download all pending media for a source |
PUT |
/api/v1/sources/{id}/retention |
Set retention policy |
GET |
/api/v1/sources/{id}/cleanup-preview |
Preview cleanup |
POST |
/api/v1/sources/{id}/cleanup |
Run cleanup |
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/collections |
List all collections |
POST |
/api/v1/collections |
Create a new collection |
POST |
/api/v1/collections/{id}/items |
Add a video to a collection |
| Method | Path | Description |
|---|---|---|
POST |
/api/v1/media/{id}/download |
Download a single media item |
POST |
/api/v1/media/{id}/retry |
Retry a failed download |
POST |
/api/v1/media/{id}/pin |
Toggle pin status |
DELETE |
/api/v1/media/{id} |
Remove media (deletes file) |
POST |
/api/v1/media/download-all-pending |
Download all pending/failed |
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/tasks |
List all tasks |
POST |
/api/v1/tasks/{id}/start |
Start a queued task |
POST |
/api/v1/tasks/{id}/cancel |
Cancel a running task |
POST |
/api/v1/tasks/{id}/retry |
Retry a failed task |
POST |
/api/v1/tasks/{id}/run |
Stub-complete a task (legacy/testing) |
POST |
/api/v1/tasks/{id}/execute |
Execute with mode: stub or fail_stub |
DELETE |
/api/v1/tasks/{id} |
Remove a completed task |
DELETE |
/api/v1/tasks |
Clear all completed tasks |
POST |
/api/v1/tasks/stop-all |
Cancel all running tasks |
POST |
/api/v1/tasks/retry-failed |
Retry all failed tasks |
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/schedules |
List all schedules |
GET |
/api/v1/sources/{id}/schedule |
Get schedule for a source |
POST |
/api/v1/sources/{id}/schedule |
Create or update schedule |
DELETE |
/api/v1/sources/{id}/schedule |
Remove schedule |
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/cookies/status |
Cookie file status + validation |
POST |
/api/v1/cookies |
Upload cookies (file or raw text) |
DELETE |
/api/v1/cookies |
Delete cookies file |
POST |
/api/v1/cookies/validate |
Validate cookies against YouTube |
| Method | Path | Description |
|---|---|---|
GET |
/api/v1/config |
Get current config |
PUT |
/api/v1/config |
Update config |
GET |
/api/v1/youtube/search?q=keywords |
Search YouTube |
GET |
/api/v1/youtube/probe?url=URL |
Diagnostic: test index a URL |
GET |
/healthz |
Health check |
| Kind | Example URLs |
|---|---|
| Channel | https://www.youtube.com/@Handle |
| Channel | https://www.youtube.com/channel/UCxxxxxx |
| Playlist | https://www.youtube.com/playlist?list=PLxxxxxx |
| Video | https://www.youtube.com/watch?v=xxxxxxx |
| Video | https://youtu.be/xxxxxxx |
apps/
api/ HTTP server entry point
cli/ CLI client
internal/
api/ HTTP handlers and Web UI
models/ shared data types
scheduler/ background schedule runner
store/ JSON state persistence
worker/ async task executor (yt-dlp)
yt/ YouTube URL normalisation
ytdlp/ yt-dlp wrapper (index, download, search)
YtVault is built on these open-source projects:
- yt-dlp — video extraction (Unlicense)
- FFmpeg — media processing (GPL-2.0-or-later)
- Go — language and runtime (BSD-3-Clause)
- Node.js — JavaScript runtime for yt-dlp (MIT)
- Python — runtime for yt-dlp (PSF-2.0)
YtVault is licensed under the GNU General Public License v3.0.



