ReplayVOD is a self-hosted Twitch VOD recorder for your homelab. It watches the channels you follow, automatically records the streams that match your rules, archives them on your own storage, and gives you a dashboard to browse and replay the ones you missed.
Status: active development. Stable enough for personal use, expect breaking changes between releases.
- Auto-record live streams from followed channels, gated by per-schedule rules: quality, viewer threshold, category match, tag match
- Capture stream context — title and category history are recorded throughout the broadcast, plus a snapshot strip the dashboard cycles through on hover
- Browse and watch with category, channel and date views, then play back in-browser
- Live indicators — followed channels show a live dot pushed via EventSub deltas, no polling
- Multi-language — interface in English and French
- Lightweight runtime — single Go binary, choice of Postgres or SQLite, optional S3-compatible storage backend
(coming soon)
The bundled Docker Compose stack pulls a prebuilt multi-arch image
(ghcr.io/befabri/replayvod:latest, linux/amd64 and linux/arm64) and serves
the dashboard from the Go server on one origin. Pick a database profile:
sqlite for the simplest single-container deploy, or postgres for a
two-container setup:
macOS / Linux:
curl -fsSL https://replayvod.com/install.sh | shOr clone the repo and run Docker Compose yourself:
git clone https://github.com/befabri/replayvod.git
cd replayvod
cp server/.env.example server/.env
$EDITOR server/.env # fill in Twitch credentials, see below
docker compose --env-file server/.env --profile sqlite up -d
# pulls ghcr.io/befabri/replayvod:latest. Add --build to build from source,
# or --profile postgres to add a Postgres container.Windows (Docker Desktop, PowerShell):
git clone https://github.com/befabri/replayvod.git
Set-Location replayvod
Copy-Item server/.env.example server/.env
notepad server/.env # fill in Twitch credentials, see below
docker compose --env-file server/.env --profile sqlite up -d
# pulls ghcr.io/befabri/replayvod:latest. Add --build to build from source,
# or --profile postgres to add a Postgres container.Open http://localhost:8080 and sign in with Twitch. If OWNER_TWITCH_ID is
empty, the first successful login becomes the owner.
To skip the --profile flag on every command, set COMPOSE_PROFILES=sqlite
(or =postgres) in server/.env.
Update later by pulling the newest published image:
docker compose --env-file server/.env --profile sqlite pull
docker compose --env-file server/.env --profile sqlite up -dFor real deployments, set PUBLIC_BASE_URL=https://your-domain in
server/.env before starting. The server derives the OAuth callback and
frontend redirect URL from that base URL and trusts the public origin for
browser mutations. If you host a separate dashboard origin, add it with
TRUSTED_ORIGINS=https://dashboard.example.
Register an application in the Twitch developer console with this OAuth redirect URL:
http://localhost:8080/api/v1/auth/twitch/callback
For a public deployment, replace the origin with your PUBLIC_BASE_URL, for
example https://replayvod.example/api/v1/auth/twitch/callback.
Copy the resulting Client ID and Client Secret into server/.env:
TWITCH_CLIENT_ID=...
TWITCH_SECRET=...
SESSION_SECRET=... # any random 32+ byte hex
OWNER_TWITCH_ID=... # optional numeric Twitch user id; empty = first login ownsTwo files control runtime behavior, both well-commented:
server/.env— credentials, database, paths, network. Start fromserver/.env.example.server/config.toml— operational tuning: download quality and concurrency, retry policy, scheduler intervals, and server-mode poll interval.
Live detection and title tracking are configured by the owner-facing server
mode. Environment variables are still supported for Docker/ops workflows: when
SERVER_MODE is set and complete, env wins and onboarding is skipped. When it
is empty, the dashboard asks the owner to configure the mode. Dashboard-saved
mode changes are applied on the next server start; restart when the dashboard
reports that a restart is required.
Server modes:
off— no live detection, live-dot feed, or mid-stream title tracking.poll— poll Helix for live detection and mid-stream title changes.direct— Twitch posts directly to your publicWEBHOOK_CALLBACK_URL.relay— Twitch posts to the Cloudflare relay and this server dials the relay overRELAY_SUBSCRIBE_URL.
ReplayVOD Connect supplies that public callback without port forwarding. In that
mode, RELAY_INGEST_URL is the public HTTPS URL Twitch posts to, while
RELAY_SUBSCRIBE_URL is the outbound WebSocket URL your self-hosted server
dials. The local replay target is separate and defaults to
http://127.0.0.1:8080/api/v1/webhook/callback:
SERVER_MODE=relay
RELAY_INGEST_URL=https://relay.replayvod.com/u/<token>
RELAY_SUBSCRIBE_URL=wss://relay.replayvod.com/u/<token>/subscribe
# Optional override only if the local API is not on 127.0.0.1:8080
RELAY_LOCAL_CALLBACK_URL=http://127.0.0.1:8080/api/v1/webhook/callbackRELAY_LOCAL_CALLBACK_URL must be a loopback URL ending in
/api/v1/webhook/callback; it is intentionally not a general-purpose local
forwarding target. The public ingest URL and subscribe URL must use the same
relay host and token, and the subscribe URL must use wss://.
data/
├── videos/ recorded VODs
├── thumbnails/ poster images and snapshot strips
└── replayvod.db SQLite (when DATABASE_DRIVER=sqlite)
Override individual paths with VIDEO_DIR, THUMBNAIL_DIR, SQLITE_PATH in
server/.env. S3-compatible storage is wired through [storage.s3] in
server/config.toml.
Requires Go 1.26+, Node 22+, Task,
and ffmpeg on $PATH.
task setup # go mod download + npm install
task dev # server on :8080, dashboard on :3000
task # list every available task
task check # vet + lint + typecheck
task test # full test suite
task build # production buildsThe dashboard's Vite proxy forwards /api/* and /trpc/* to the backend, so
the SPA works at http://localhost:3000 during development.
The bundled docker-compose.yml is not a live-reload dev environment; it is a
deployment path that serves the built SPA from the backend on :8080.
server/ Go backend (cmd/server, internal/api, internal/downloader, ...)
dashboard/ React SPA (TanStack Router + Query, Base UI, Tailwind v4)
ReplayVOD is built on top of a sibling project of mine:
- trpcgo — tRPC server and TypeScript
type generator for Go. Drives every API route in
server/internal/api/and produces the typed client used by the dashboard.
The recorder, dashboard, and supporting code in this repository are licensed under the GNU General Public License v3.0.
The webhook relay in relay/ is licensed separately under the
MIT License — it's a small piece of generic infrastructure
licensed permissively so it can be audited, self-hosted, or embedded in
unrelated projects without copyleft obligations.