StreamCapture is a Bash script for monitoring Twitch and Kick streamers and automatically recording their live streams with Streamlink. It can be setup to record only when a streamer is in one of your configured games/categories, stop when they switch away, and publish a local dashboard for quick status checks.
The script is designed to be run repeatedly, typically from cron once per minute. Active recordings run in detached screen sessions so the monitor command can exit while recording continues in the background.
- Monitor Twitch and Kick streamers from one script.
- Record all live streams or only streams matching configured games/categories.
- Stop an active recording when the streamer changes away from a monitored game/category.
- Store recordings by streamer under a destination directory.
- Automatically request and refresh Twitch and Kick app access tokens.
- Write status data for a local browser dashboard.
- Keep standard, error, and optional Streamlink/ffmpeg debug logs.
Install these command-line tools before running StreamCapture:
bashcurljqcmpscreenffmpegstreamlinkpython3, only required whendashboard=1
On Debian or Ubuntu-based systems, most dependencies can be installed with:
sudo apt update
sudo apt install bash curl jq diffutils screen ffmpeg python3 pipxStreamlink packages in some distro repositories may be outdated. Installing it with pipx is recommended:
pipx install streamlink
pipx ensurepathOpen a new shell after pipx ensurepath, then confirm Streamlink is available:
streamlink --versionStreamCapture uses platform API credentials to check whether configured channels are live and what game/category they are streaming. It uses app/client-credentials tokens for public stream status checks.
- Register a Twitch application using the Twitch developer documentation: https://dev.twitch.tv/docs/authentication/register-app
- Generate or copy the application Client ID and Client Secret.
- Twitch's client credentials flow is documented here: https://dev.twitch.tv/docs/authentication/getting-tokens-oauth
- Register a Kick app using the Kick app setup documentation: https://docs.kick.com/getting-started/kick-apps-setup
- Generate or copy the app Client ID and Client Secret.
- Kick's OAuth client credentials flow is documented here: https://docs.kick.com/getting-started/generating-tokens-oauth2-flow
Create the file referenced by authorizationfile in streamcapture.sh. The script creates this template automatically if the file is missing, but you still need to fill in the values:
twitch_clientid=
twitch_clientsecret=
kick_clientid=
kick_clientsecret=Example:
nano /path/to/.streamcreds.conf
chmod 600 /path/to/.streamcreds.confThe file referenced by configfile is managed by StreamCapture. It stores the current access tokens and expiration timestamps:
twitch_access_token=""
twitch_access_token_expires_at=0
kick_access_token=""
kick_access_token_expires_at=0You normally do not need to edit configfile manually.
Edit the configuration block at the top of streamcapture.sh before running the script.
Set the Twitch and Kick channels you want to monitor:
twitchstreamers=(streamerone streamertwo)
kickstreamers=(streamerthree streamerfour)Streamer names are converted to lowercase internally for consistency with API responses.
Set the games/categories you want to record:
game=(VRChat ASMR)Use quotes around names that include spaces:
game=("Just Chatting" VRChat)Enable or disable game/category filtering per platform:
monitortwitchgame=1
monitorkickgame=11records only when the streamer is in one of the configuredgameentries.0records whenever the streamer is live.
Control whether StreamCapture should stop an active recording when a streamer switches away from a configured game/category:
stoptwitchrecord=1
stopkickrecord=1These stop settings only apply when the matching monitor...game setting is enabled.
Configure where recordings, credentials, tokens, and the dashboard status filename should live:
destpath="/path/to/Recordings"
authorizationfile="/path/to/.streamcreds.conf"
configfile="/path/to/.streamtokens.conf"
status_name="status.json"destpath must already exist and be writable. StreamCapture creates log directories and per-streamer recording directories under it as needed.
status_name is only the JSON filename. StreamCapture builds the absolute dashboard status path automatically from the directory containing streamcapture.sh, then appends Dashboard/$status_name.
Enable or disable the local dashboard:
dashboard=11starts a local dashboard server when the script runs.0disables dashboard startup.
When enabled, StreamCapture serves the dashboard from the script's Dashboard/ directory:
http://localhost:8080
The dashboard reads status.json, polls for updates, and displays live, recording, and offline states. It also includes search/filter controls, platform filters, audio alerts, grid/table views, and a local destination-path helper for copying recorded file paths.
Configure normal logging and debug logging:
logging=2
debug=0logging levels:
0: no file logging1: standard start, stop, warning, and status logging2: standard logging plus errors3: standard, error, and verbose logging
debug levels:
0: no Streamlink/ffmpeg debug logs1: write Streamlink and ffmpeg screen logs under$destpath/logs/debug/
Make the script executable:
chmod +x streamcapture.shRun it manually:
./streamcapture.shFor normal use, run it from cron every minute:
* * * * * /path/to/StreamCapture/streamcapture.shUse absolute paths in cron. Cron runs with a limited environment, so make sure streamlink, jq, ffmpeg, and the other dependencies are available in the cron user's PATH.
When StreamCapture starts a recording, it launches Streamlink in a detached screen session named:
<streamer>-<platform>
Examples:
streamerone-Twitch
streamerthree-Kick
Recordings are first written as temporary .tmp files:
$destpath/<streamer>/<streamer> - S<year>E<julian-day> - <stream title> [<stream id><random>].tmp
When Streamlink exits, the script remuxes the file to MP4:
ffmpeg -y -i "$tmpfile" -c copy -movflags faststart "$output.mp4"Final recordings are saved under:
$destpath/<streamer>/
Standard logs are written to:
$destpath/logs/log.txt
$destpath/logs/errlog.txt
Debug logs, when enabled, are written under:
$destpath/logs/debug/
The dashboard files live in Dashboard/. When dashboard=1, the script starts:
python3 -m http.server 8080from the script's Dashboard/ directory. The dashboard is then available at:
http://localhost:8080
The script creates and updates status.json automatically. It includes each configured streamer, platform, live state, current game/category, stream title, viewer count, recording state, filename, and last update timestamp.
Change status_name if you want a different JSON filename. Keep the generated status JSON in Dashboard/ unless you also update the dashboard/server behavior, because dashboard.html loads the status file from the same served directory.
StreamCapture's Twitch API checks use app credentials from authorizationfile. Separately, Streamlink can use your Twitch account token to avoid ads when you have Twitch Turbo or are subscribed to the streamer being recorded.
Streamlink's Twitch plugin documentation is here:
https://streamlink.github.io/cli/plugins/twitch.html
Streamlink configuration details are here:
https://streamlink.github.io/cli/config.html#plugin-specific-configuration-file
This optional Streamlink configuration is separate from StreamCapture's Twitch API credentials.
- If the script reports a missing destination path, create
destpathfirst and make sure the script user can write to it. - If API token requests fail, verify the client IDs and client secrets in
authorizationfile. - If the dashboard does not load, confirm
dashboard=1,python3is installed, and port8080is available. - If recordings do not start, test Streamlink directly with
streamlink <stream-url> best. - If cron runs but recordings do not start, use absolute paths and check the cron user's
PATH. - If a recording appears stuck, list sessions with
screen -listand inspect the matching<streamer>-<platform>session.