Self-hosted live stream recorder with a beautiful web UI.
Automatically monitor and record live streams from 30+ platforms — all from a single dashboard.
- Features
- Screenshots
- Getting Started
- Updating
- VPN / Proxy Setup
- Cookies / Age-Restricted Streams
- Configuration
- Architecture
- Project Structure
- API Reference
- Raspberry Pi / Low-Power Devices
- Troubleshooting
- Contributing
- License
Record live streams from 30+ platforms including:
| Platform | Platform | Platform | Platform |
|---|---|---|---|
| YouTube | Twitch | TikTok | Kick |
| Bilibili | Twitter/X | ||
| Rumble | Vimeo | Dailymotion | Niconico |
| Douyin | Huya | Douyu | Afreeca |
| Sooplive | Naver | Bigo | |
| Twitcasting | Pandalive | Stripchat | Chaturbate |
| Cam4 | MyFreeCams | BongaCams | CamSoda |
| CamModels | Streamate | Flirt4Free | …and more via yt-dlp |
- Automatic Live Detection — Periodically checks if a channel is live and starts recording automatically
- Multi-Channel Monitoring — Monitor dozens of channels simultaneously from a single dashboard
- One-Click Recording — Manually start/stop recordings at any time
- Quality Selection — Choose from Best, 1080p, 720p, 480p, or Lowest quality per channel
- Multiple Formats — Record in MP4, MKV, or TS container formats
- Live-from-Start — Captures the stream from the very beginning (on supported platforms)
- Bulk Actions — Multi-select channels and record, stop, delete, or edit quality/format in bulk
- Channel Reordering — Drag-and-drop to organize your channel list
- Per-Channel Notes — Add private notes to each channel for context
- Stream Title Tracking — See what the streamer is currently broadcasting
- Auto-Retry on Disconnect — Automatically reconnects when a stream drops, with configurable retry count and delay
- Post-Processing — Optionally auto-convert recordings to MP4 after completion (lossless remux)
- Container Fix — Automatically remuxes interrupted recordings to fix broken containers
- Progress Tracking — Real-time file size, download speed, and duration displayed per recording
- Max Duration Enforcement — Set a per-channel or global time limit; recordings auto-stop gracefully when reached
- Recording Retention — Auto-delete recordings older than N days to manage disk space (0 = keep forever)
- Stalled Detection — Warns (or auto-stops) when a stream stops sending data silently
- Webhook Notifications — POST JSON to any HTTP endpoint when streams go live or recordings complete
- Archive & Restore — Move completed recordings to an archive folder and restore them later
- Dark & Light Themes — Toggle between dark and light mode with one click
- Responsive Design — Works on desktop, tablet, and mobile
- Search & Filter — Quickly find channels by name, platform, notes, or stream title
- Sort Channels — Order by name, platform, recently added, last checked, or live first
- Recordings Filter & Sort — Filter by status and sort by date, size, or name
- In-Browser Preview — Play back completed recordings directly in the browser
- Live Log Panel — View real-time yt-dlp output from the channels or recordings page
- Disk Usage Stats — Monitor your storage usage from the recordings page
- Concurrent Slot Indicator — See how many recording slots are in use (e.g. 2/6)
- Keyboard Shortcuts — Press
Nto add,1-4to navigate pages,R/S/Delfor bulk actions
- Per-Channel Overrides — Set quality, format, proxy, and post-processing options individually per channel
- VPN / Proxy Support — Route any channel through a proxy or WireGuard VPN (built-in wireproxy sidecar)
- Cookies / Credentials — Record age-restricted streams using browser cookies or username/password
- Import / Export — Back up and restore your channel list and settings as a JSON file
- Persistent State — All channels, settings, and finished recordings survive container restarts
- Raspberry Pi Mode — Built-in resource-constrained mode for low-power devices (
STREAMREC_PI_MODE=1)
- Personalize the dashboard — Pick a username and a profile picture that shows in the top-right corner across every page
- Password-protected — Stored with PBKDF2-HMAC-SHA256 (200k iterations) over a 32-byte random salt; the plaintext is never written to disk
- Skip anytime — A Skip for now button on the welcome screen keeps the full dashboard usable without an account
- Account settings menu — Edit username, change password (with current-password verification), swap or remove your profile picture, or delete the account entirely
- Private on-disk — Account file (
account.json) ischmod 600on Unix and lives inside the recordings volume, not in the exported config
- Supervised monitor loop — Per-channel live checks run in parallel and crash-isolated; one broken URL can't stall detection for the rest
- Graceful shutdown — In-flight recordings are stopped cleanly and state is flushed when the server exits
- Proper concurrency caps — Concurrent
yt-dlpandcurlsubprocesses honour the process semaphore - Per-channel recording lock — Prevents accidental double-recording from concurrent calls
- Stalled recording detection — Warns (or auto-stops) when a stream stops sending data silently
- Upload limits — Cookies files capped at 5 MiB, profile pictures at 2 MiB
- PBKDF2 password hashing — Account passwords hashed with 200k SHA256 iterations; plaintext never stored
- Atomic file writes — State and account files written to
.tmpthen atomically renamed to prevent corruption
The main dashboard showing all monitored channels with live status, recording controls, and real-time stats.
The same channel dashboard in light theme — switch with one click.
Add any channel by pasting a URL — StreamRec auto-detects the platform and fetches metadata.
Configure global defaults, proxy, cookies, auto-retry behavior, and more.
Browse, preview, download, or delete completed recordings — all from the web UI.
View all 30+ supported streaming platforms at a glance.
-
Clone the repository:
git clone https://github.com/orhogi/streamerREC.git cd streamerREC -
Start the application:
docker compose up -d
-
Open your browser:
http://localhost:8080
That's it! Your recordings will be saved in the ./recordings directory.
docker build -t streamrec .
docker run -d \
--name streamrec \
-p 8080:8080 \
-v ./recordings:/recordings \
--restart unless-stopped \
streamrecPrerequisites:
pip install -r requirements.txt
mkdir -p recordings
uvicorn main:app --host 0.0.0.0 --port 8080cd streamerREC
git pull
docker compose down
docker compose build --no-cache
docker compose up -dYour channels, settings, and completed recordings are stored in ./recordings/state.json and will persist across updates. If you created a local account, the hashed credentials live in ./recordings/account.json and your profile picture in ./recordings/avatars/ — back these up alongside the rest of the recordings folder.
cd streamerREC
git pull
pip install -r requirements.txt --upgrade
# Restart the serverStreamRec includes a built-in WireGuard proxy (wireproxy) that runs as a sidecar container. It exposes a SOCKS5 proxy at socks5://wireproxy:1080 that you can assign to individual channels or globally.
This is useful for:
- Recording geo-blocked streams
- Routing cam site traffic through a VPN
- Bypassing IP bans on specific platforms
Place your WireGuard config file at streamerREC/wg0.conf:
[Interface]
PrivateKey = <your private key>
Address = 10.x.x.x/32
DNS = 1.1.1.1
[Peer]
PublicKey = <server public key>
Endpoint = <server>:<port>
AllowedIPs = 0.0.0.0/0You can get a WireGuard config from any VPN provider (Mullvad, ProtonVPN, etc.) or your own server.
docker compose down && docker compose build && docker compose up -dIn the web UI:
- Open a channel's settings
- Set the Proxy field to:
socks5://wireproxy:1080 - Save
That channel will now record and check live status through the VPN.
To route all channels through the VPN:
- Go to Settings
- Set the Proxy field to:
socks5://wireproxy:1080 - Save
The proxy is opt-in — channels without a proxy set go direct. Live detection also routes through the proxy, so geo-blocked channels are detected correctly.
For platforms that require login (age-restricted content, private streams):
- Export your browser cookies using a browser extension (e.g. Get cookies.txt LOCALLY)
- Go to Settings → Cookies in the web UI and upload the file
- Assign the cookies file to the channel in its settings
You can also set a username/password per channel for platforms that support it.
stream_live — fired when a monitored stream goes live
{
"event": "stream_live",
"channel_id": "abc12345",
"name": "StreamerName",
"url": "https://twitch.tv/streamer",
"platform": "Twitch",
"recording_id": "def67890"
}recording_complete — fired when a recording finishes (success or error)
{
"event": "recording_complete",
"recording_id": "def67890",
"channel_id": "abc12345",
"status": "completed",
"filename": "StreamerName_2026-05-03_14-30-00.mp4",
"bytes": 150994944,
"error": "",
"platform": "Twitch"
}| Variable | Default | Description |
|---|---|---|
STREAMREC_PI_MODE |
0 |
Set to 1 to enable Raspberry Pi mode |
RECORDINGS_DIR |
~/StreamRec/recordings |
Override recordings directory |
| Setting | Default | Description |
|---|---|---|
| Potato / Pi mode | Off | Reduce CPU/RAM/I/O for low-power devices |
| Check Interval | 60s (120s Pi) | How often to check if channels are live |
| Auto-record when live | Off | Start recording automatically when a stream goes live |
| Default Quality | best |
Default recording quality for new channels |
| Default Format | mp4 |
Default container format |
| Auto-convert to MP4 | Off | Remux completed recordings to MP4 |
| Delete Original | Off | Remove source file after MP4 conversion |
| Auto-Retry | On | Reconnect on unexpected disconnections |
| Max Retries | 5 | Maximum reconnect attempts |
| Retry Delay | 15s | Wait time between retries |
| Proxy | — | Global proxy for all channels |
| Extra yt-dlp args | — | Additional yt-dlp arguments applied globally |
| Cookies File | — | Global cookies file for authentication |
| Retention Days | 0 (keep forever) | Auto-delete recordings older than this |
| Max Duration | 0 (no limit) | Auto-stop recordings after N minutes (global) |
| Webhook URL | — | POST JSON on stream live & recording complete |
| Auto-stop stalled | Off | Force-stop recordings that stop receiving data |
─────────────────────────────────────────────
Browser
(index.html – SPA)
─────────────────┬───────────────────────────
│ REST API
─────────────────▼───────────────────────────
FastAPI Server
(main.py)
┌────────────┐ ┌────────────┐ ┌─────────┐
│ Channel │ │ Recording │ │ Monitor │
│ Manager │ │ Engine │ │ Loop │
└────────────┘ └─────┬──────┘ └─────────┘
│
┌─────▼──────┐
│ yt-dlp + │
│ FFmpeg │
└────────────┘
─────────────────────────────────────────────
│
┌──────▼──────┐ ┌─────────────┐
│ /recordings │ │ wireproxy │
│ (volume) │ │ (WireGuard) │
└─────────────┘ └─────────────┘
- Frontend: Single-page HTML/CSS/JS (no build step)
- Backend: Python FastAPI with async subprocess management
- Recording: Powered by yt-dlp and FFmpeg
- State: JSON file persisted to the recordings volume
- VPN: Optional wireproxy sidecar (WireGuard → SOCKS5)
streamerREC/
├── main.py # FastAPI backend — API routes, recording engine, monitor loop
├── index.html # Complete frontend — single-file SPA with embedded CSS/JS
├── Dockerfile # Container image definition
├── Dockerfile.wireproxy # Wireproxy sidecar image
├── docker-compose.yml # Docker Compose service configuration
├── requirements.txt # Python dependencies
├── screenshots/ # App screenshots used in README
├── LICENSE # MIT License
└── README.md
Channels
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/channels |
Add a new channel |
GET |
/api/channels |
List all channels |
PATCH |
/api/channels/{id} |
Update channel settings |
DELETE |
/api/channels/{id} |
Delete a channel |
POST |
/api/channels/{id}/record |
Start recording |
POST |
/api/channels/{id}/stop |
Stop recording (graceful) |
POST |
/api/channels/{id}/kill |
Force-stop recording |
POST |
/api/channels/{id}/refresh |
Refresh channel metadata |
POST |
/api/channels/reorder |
Reorder channel list |
POST |
/api/channels/bulk |
Bulk record/stop/delete |
POST |
/api/channels/bulk-edit |
Bulk edit quality/format |
Recordings
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/recordings |
List all recordings |
GET |
/api/recordings/{id}/log |
Get recording log |
GET |
/api/download/{id} |
Download a recording |
GET |
/api/preview/{id} |
Stream/preview a recording |
DELETE |
/api/recordings/{id} |
Delete a recording |
POST |
/api/recordings/{id}/archive |
Archive a recording |
POST |
/api/recordings/{id}/restore |
Restore an archived recording |
Settings & System
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/settings |
Get current settings |
PATCH |
/api/settings |
Update settings |
GET |
/api/health |
Health check |
GET |
/api/version |
Get StreamRec version |
GET |
/api/disk |
Disk usage stats |
GET |
/api/export |
Export configuration |
POST |
/api/import |
Import configuration |
Account
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/account |
Get current account ({exists: false} if none) |
POST |
/api/account |
Create account (username, password, confirm_password) |
PATCH |
/api/account |
Update username or change password |
DELETE |
/api/account |
Delete the account and its avatar |
POST |
/api/account/avatar |
Upload a profile picture (multipart, max 2 MiB) |
DELETE |
/api/account/avatar |
Remove the current profile picture |
POST |
/api/account/login |
Verify username + password against the stored hash |
environment:
- STREAMREC_PI_MODE=1When enabled:
- Concurrent subprocess limit reduced from 6 → 3
- Default monitor interval increased from 60s → 120s
- FFmpeg threads limited to 1 (vs 2 normally) for lower CPU usage
- yt-dlp download buffer capped at 32 KB to reduce memory usage
- File-size polling interval increased from 3s → 8s
- Log buffer trimmed more aggressively (60 → 30 lines)
- Disk usage cache extended from 30s → 60s
- State saves debounced (2s coalesce window) to reduce disk I/O
- Frontend poll interval increased from 5s → 10s
- Search inputs debounced to reduce DOM queries
Tip: Uncomment the
deploy.resources.limitssection indocker-compose.ymlto also limit RAM and CPU usage.
Stream is live but not detected
- Check that the URL is correct and accessible from your server
- If the channel is geo-blocked, set up a proxy or VPN
- Try increasing the check interval in Settings if you have many channels
- Use the Refresh button on the channel card to manually re-check
Recording starts but file is 0 bytes or very small
- Some platforms require cookies for full access — see Cookies setup
- Try changing the recording quality (some streams don't support all quality levels)
- Check the recording log (click the channel card → view log) for error details
Container won't start / port conflict
- Make sure port 8080 isn't already in use:
lsof -i :8080 - Change the port mapping in
docker-compose.yml:"3000:8080"to use port 3000 instead - Check Docker logs:
docker compose logs streamrec
wireproxy container keeps restarting
- Make sure
wg0.confexists and is valid - If you don't need the VPN feature, you can comment out the
wireproxyservice and thedepends_online indocker-compose.yml
yt-dlp errors / unsupported site
- Rebuild the Docker image to get the latest yt-dlp:
docker compose build --no-cache - For manual installs, update yt-dlp:
pip install -U yt-dlp - Check yt-dlp supported sites for compatibility
Contributions are welcome! Here's how to get started:
- Fork this repository
- Create a feature branch:
git checkout -b my-feature - Commit your changes:
git commit -m "Add my feature" - Push to the branch:
git push origin my-feature - Open a pull request
- 🌐 Add translations / i18n support
- 📨 Add more notification targets (Telegram, Pushover, Apprise, email)
- 🧪 Add test coverage
- 📊 Add recording analytics / statistics dashboard
- ☁️ Automatic cloud backup (S3, R2, Backblaze B2)
- 🧩 Plugin system for custom post-processing scripts
- 📱 PWA support (offline mode, push notifications)
This project is licensed under the MIT License.