Download Twitch VOD metadata, video and chat
Project description
twitch-vod-lib
A clean Python library for downloading Twitch VOD metadata, video files, and chat logs.
Features
- Fetch VOD metadata via Twitch Helix API
- Download video via yt-dlp (supports quality selection, cookies for sub-only VODs)
- Download full chat replay via Twitch GQL with pagination, deduplication and caching
- Structured logging (stdlib or
structlog) - Retry logic with exponential back-off on transient errors
- File-based caching — re-running skips already completed work
- Config from environment variables, dict, or YAML (bring your own loader)
Requirements
- Python 3.10+
yt-dlponPATH(only needed for video downloads)- Twitch Developer Application credentials → https://dev.twitch.tv/console/apps
Installation
Poetry (recommended)
git clone https://github.com/sontiago/twitch-vod-lib.git
cd twitch-vod-lib
poetry install # installs main deps
poetry install --with dev # installs dev deps (pytest, ruff, mypy)
Copy the env file and fill in your credentials:
cp .env.example .env
# edit .env — set TWITCH_CLIENT_ID and TWITCH_CLIENT_SECRET
Run the library:
poetry run python your_script.py
pip (alternative)
pip install -e ".[dev]"
Quick start
from twitch_vod import TwitchVodClient, TwitchConfig
# Reads TWITCH_CLIENT_ID and TWITCH_CLIENT_SECRET from environment
with TwitchVodClient() as client:
vod = client.get_latest_vod("xqcow")
print(f"VOD: {vod.title} ({vod.duration / 3600:.1f}h)")
video_path = client.download_video(vod.id, quality="720p")
messages = client.download_chat(vod.id, vod_duration=vod.duration)
print(f"Downloaded {len(messages)} chat messages → {video_path}")
Or use the one-shot helper:
vod, video_path, messages = client.fetch_all("xqcow", quality="480p")
Environment variables
Copy .env.example to .env and fill in your values (use python-dotenv or export manually):
| Variable | Required | Default | Description |
|---|---|---|---|
TWITCH_CLIENT_ID |
✅ | — | Twitch app client ID |
TWITCH_CLIENT_SECRET |
✅ | — | Twitch app client secret |
TWITCH_USER_ACCESS_TOKEN |
❌ | "" |
User token for sub-only VODs |
TWITCH_COOKIES_FILE |
❌ | None |
Path to Netscape cookies file |
TWITCH_DOWNLOAD_QUALITY |
❌ | best |
best, 1080p60, 1080p, 720p60, 720p, 480p, worst |
TWITCH_OUTPUT_DIR |
❌ | output/raw |
Directory for video and chat files |
TWITCH_API_TIMEOUT |
❌ | 30 |
HTTP timeout in seconds |
TWITCH_API_RETRIES |
❌ | 3 |
Number of retry attempts |
TWITCH_CHAT_MAX_PAGES |
❌ | 10000 |
Hard cap on GQL pagination pages |
TWITCH_CHAT_RATE_LIMIT_MIN |
❌ | 0.05 |
Min sleep between GQL pages (s) |
TWITCH_CHAT_RATE_LIMIT_MAX |
❌ | 0.5 |
Max sleep between GQL pages (s) |
LOG_LEVEL |
❌ | INFO |
DEBUG, INFO, WARNING, ERROR |
Configuration from dict / YAML
import yaml
from twitch_vod import TwitchVodClient, TwitchConfig
with open("config.yaml") as f:
raw = yaml.safe_load(f)
cfg = TwitchConfig.from_dict(raw["twitch"])
client = TwitchVodClient(cfg)
Example config.yaml:
twitch:
client_id: abc123
client_secret: secret
download_quality: 720p
output_dir: data/raw
Project layout
twitch_vod/
├── __init__.py # Public API: TwitchVodClient, TwitchConfig, VODInfo, ChatMessage
├── client.py # TwitchVodClient — façade / entry point
├── config.py # TwitchConfig — env-based configuration
├── api/
│ ├── helix_client.py # Twitch Helix REST API (auth, VOD metadata)
│ └── gql_client.py # Twitch GQL (chat pagination)
├── downloader/
│ ├── video.py # yt-dlp wrapper
│ └── chat.py # GQL chat downloader with caching
├── models/
│ ├── vod.py # VODInfo dataclass
│ └── chat.py # ChatMessage dataclass
└── utils/
└── logger.py # Structured logging (structlog / stdlib)
Running tests
pytest # or poetry run pytest
With coverage:
pytest --cov=twitch_vod --cov-report=term-missing
Linting & type-checking
ruff check .
mypy ./
Caching behaviour
| File | When created | Skip condition |
|---|---|---|
output/raw/{vod_id}.mp4 |
download_video() |
File exists and > 1 MB |
output/raw/{vod_id}_chat.json |
download_chat() |
File exists |
Delete the relevant file to force a re-download.
License
MIT
Known issues
Chat pagination may miss messages in high-traffic streams
The Twitch GQL API paginates chat by contentOffsetSeconds, meaning each page
is fetched starting from the timestamp of the last seen message.
This approach has a fundamental limitation:
- The API returns messages matching
ts >= offset - Multiple messages can share the same
ts(same second) - If more messages exist within a single second than the page size allows, the overflow messages will never appear in any subsequent page request
Deduplication by message id prevents duplicates but cannot recover
messages that were never returned by the API in the first place.
In practice this means very popular streams (e.g. large hype moments with thousands of messages per second) may have small gaps in the chat log. This is a limitation of the Twitch GQL API itself, not of this library.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file twitch_vod_lib-1.0.0.tar.gz.
File metadata
- Download URL: twitch_vod_lib-1.0.0.tar.gz
- Upload date:
- Size: 15.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.0.1 CPython/3.13.1 Darwin/24.6.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98aa16498893880bfc27f7a68175ba7185e280ea4e8cc6ba20fef4370cc353c4
|
|
| MD5 |
59b9e1c293a6a64e73755bfa8f0d98c3
|
|
| BLAKE2b-256 |
227e5ec0ad1a6b1058a08d26116fdc5dc31712d8640b1cc32d17e78507bca0b6
|
File details
Details for the file twitch_vod_lib-1.0.0-py3-none-any.whl.
File metadata
- Download URL: twitch_vod_lib-1.0.0-py3-none-any.whl
- Upload date:
- Size: 18.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.0.1 CPython/3.13.1 Darwin/24.6.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1a6aa7621f4e20e598af98eb830ee83c8e2a276ef8bfc3100aedadc00feb189c
|
|
| MD5 |
85db47a8d1fc8f42d6d18acf4c3fbbb1
|
|
| BLAKE2b-256 |
7cea74a644c83d4a783e8b9ec500a02fa98650d2fa0820b46f96ac16a6f22b9f
|