Self-hosted Twitch VOD recorder.

Twitch deletes VODs after 14 days. ReplayVOD records the source stream to your disk so they don't disappear. One container, embedded SQLite, runs on a Pi 5.

GPLv3 zero telemetry amd64 · arm64 SQLite or Postgres

What it does. Honest list.

Single Go binary, embedded SQLite by default, optional Postgres. Runs in one container next to whatever else is on your stack.

Event-driven, not polling

Subscribes to Twitch EventSub. First segment hits disk within ~4s of stream.online. No 30-second poll loop missing the start.

Source-quality, no re-encode

1080p60 at the original bitrate, written straight to MP4. CPU stays idle; ffmpeg only runs to remux.

Resumable

Network drops, host reboots, ISP blips. Segments resume from the last good point — no half-broken files.

Per-channel rules

Quality, category, tag filters, viewer floor, retention window. Configure once per channel and forget.

Indexed metadata

Title, category, stream ID, viewer count, language, thumbnails — stored next to each MP4 and queryable from the dashboard.

Local or S3

Mount any volume the kernel can see (NAS, ZFS pool, USB) or write to S3-compatible storage. Per-schedule retention rules clean up old recordings.

One container. Your hardware.

One Docker Compose file, one Twitch dev app, one volume mount. Single binary with embedded SQLite. Zero phone-home.

Read full installation docs →
  • Docker / Compose macOS, Linux, Windows, NAS, or homelab rack.
  • Reverse-proxy ready Caddy, Nginx, or Traefik. Bring your own TLS.
  • SQLite by default Switch to Postgres when you want it.

Why not just Streamlink/yt-dlp + cron?

Most of us got here from a streamlink twitch.tv/foo best -o vod.mp4 or a yt-dlp one-liner in a cron. ReplayVOD is what falls out the day you find yourself hand-rolling resume logic and a metadata sidecar.

Streamlink/yt-dlp + cron
ReplayVOD
Trigger
30s polling or a minute-cron on the helix API
EventSub webhook, ~4s lag
Resume after disconnect
ffmpeg restarts from byte 0
Resumes from the last good chunk
Per-channel rules
Separate cron entries or a Python wrapper
Quality, category, tags, viewer floor
Metadata
Filename, plus a JSON sidecar you remember to write
Title, category, viewers, language, thumbnails
Retention
A second cron with find -mtime +N -delete
Per-schedule retention rules
Visibility
tail -f the journal and hope
Tagged event log, live job progress

Streamlink or yt-dlp in a cron is fine for one channel. ReplayVOD pays off the second you want multiple channels, indexed recordings, or to sleep without checking on it.

Live status, not log diving.

The dashboard shows current channel status, active jobs with progress and ETA, and a tagged event log.

  • stream.status SSE feed Followed channels go live → row turns purple within a second of the EventSub callback.
  • Per-job progress Stage (downloading / remuxing / finalizing), bytes written, MB/s, ETA, percent complete.
  • Tagged event log recorder, eventsub, scheduler, remuxer, storage. Filterable. Persisted to the same DB.
Cost of adding ReplayVOD to your stack

The numbers, at a glance.

Disk per hour
~ 3.5 GB
1080p60 source bitrate. No re-encode.
EventSub → first byte
< 4 s
stream.online callback to first segment on disk.
Concurrency
32
Parallel recordings on a 4-core host.
RAM idle / under load
~ 240 MB
~ 320 MB with eight live recordings.
Architectures
amd64 · arm64
Multi-arch image. Pi 5 with external storage works.
Reverse proxy
any
Caddy, Nginx, Traefik, HAProxy. Bring your own TLS.
replayvod connect

Live notifications without touching your router.

Twitch's EventSub needs a public HTTPS endpoint. Getting one at home means port forwarding, a static IP or dynamic DNS, and certificate management. Connect handles all of that through an outbound connection from your machine, so there's nothing to configure, and we never see your video files or your Twitch credentials.

Self-host alternatives, all documented in the install guide
  • Cloudflare Tunnel free, outbound, terminates TLS for you
  • Tailscale Funnel one command if you already run Tailscale
  • Caddy + DuckDNS classic if you have port 80/443 open
  • Reverse SSH to a VPS a $4 box and an autossh unit file

Webhook in. MP4 out.

Twitch tells your recorder when a stream goes live. The recorder fetches the source video and writes a finalized MP4 to your disk. Nothing else sits in the path.

Free to run. $5 if you don't want to fight your router.

Self-host

$0/forever

Your hardware. GPLv3.

  • Unlimited channels & recordings
  • Full feature set, no gates
  • Source code on GitHub
Read the install guide →

Connect

$5$50 /month /year

Self-host the recorder. We handle the annoying parts. $4.17 / month, billed once a year.

  • Public webhook URL. No port forwarding, no domain, no certs.
  • Live notifications via EventSub (works behind CGNAT)

Webhook relay only. Videos stay on your hardware.

Terms · Privacy

The honest questions first.

Is this affiliated with Twitch? +
No. ReplayVOD is independent and open-source. You register your own Twitch developer app — we never hold your credentials.
What is Connect, exactly? +
A webhook relay on Cloudflare Workers. Twitch's EventSub needs a public HTTPS endpoint; Connect gives you one and forwards bytes to your home machine over an outbound WebSocket. We don't parse or log payloads, don't store videos, don't hold Twitch credentials. Source is public.
Do I need a Twitch developer account? +
Yes. Register your own app at dev.twitch.tv. Takes about two minutes, whether you use Connect or self-host alone.
Where are my videos stored? +
On your hardware. Connect only relays webhooks; videos never leave your machine.
What happens to my recordings if I cancel Connect? +
Nothing breaks. Your recorder and recordings keep working. You just lose the public webhook URL.
What if Twitch changes its API? +
We update; you pull the release. If Twitch ever forces Connect to shut down, subscribers get notified and a pro-rated refund. The recorder itself is unaffected.
How much storage do I need? +
~3.5 GB per hour of 1080p60. Dashboard shows live sizes. Monitor free disk yourself.
Synology, TrueNAS, Unraid, Raspberry Pi? +
Docker Compose is the supported path. The arm64 build runs on a Pi 5 with external storage; concurrency depends on network and disk.
Why not just Streamlink/yt-dlp + cron? +
It works for one channel until it doesn't. EventSub triggers in ~4 s instead of waiting for the next poll, captures resume from the last good chunk after a network blip, metadata is indexed instead of guessed from the filename, and you get per-channel rules + retention without a second cron. If you have one channel and a forgiving uplink, either CLI is fine. The dedicated tool just stops being annoying past two.
Plays nice with Jellyfin / Plex / the *arr stack? +
Yes. Recordings land in a folder structure your media server can scan (configurable). The dashboard sits behind whatever reverse proxy you already run — Caddy, Nginx, Traefik, HAProxy — and respects forward-auth headers from Authelia or Authentik.

One container. Your hardware. Your archive.

Pull the image, mount a volume, paste your Twitch app credentials. Recording starts the next time a followed channel goes live.