๐ฎ Automate Twitch Drop Farming โ Effortlessly, Headlessly, and Bandwidth-Free
This is an independently developed and maintained fork originally based on rangermix/TwitchDropsMiner.
It has diverged significantly and is now its own standalone project with active development, independent features, and bug fixes that go well beyond the upstream codebase.
Upstream changes that make sense will continue to be merged when applicable, but this project follows its own roadmap.
The following features and fixes have been added on top of the upstream codebase:
- Each Twitch account lives in its own isolated
data/accounts/<name>/directory (cookies, settings, drop history, channel points) - Switch accounts from the System tab in the web UI โ no config files needed
- Full CRUD via REST API:
/api/accounts(list, add, switch, delete) - Drop history and channel points are saved per-account; switching accounts shows the correct data instantly
Run unlimited independent miner instances at the same time โ each as a fully isolated process with its own data, settings, and login session.
- Dynamic management โ add/remove instances directly from the System โ Instances tab in the dashboard; no manual config needed
- Instance 1 runs on port 8080 with data stored in
data/(always present, cannot be removed) - Additional instances use ports 8082, 8084, ... and data dirs
data2/,data3/, ... - Each instance is fully isolated: cookies, settings, drop history, channel points
- Nginx config regenerates automatically when instances are added or removed
- Proxy warning shown in the dashboard when running 3+ instances on one IP (Twitch may flag the account)
- Configured via
TDM_PORT(listening port) andTDM_DATA_DIR(data directory) environment variables
Docker Compose (both instances):
services:
tdm-account1:
build: .
ports:
- "8080:8080"
volumes:
- ./data:/app/data
- ./logs:/app/logs
environment:
- TZ=Europe/Vienna
- WEB_PASSWORD=yourpassword
- TDM_PORT=8080
- TDM_DATA_DIR=data
restart: unless-stopped
tdm-account2:
build: .
ports:
- "8082:8082"
volumes:
- ./data2:/app/data
- ./logs2:/app/logs
environment:
- TZ=Europe/Vienna
- WEB_PASSWORD=yourpassword
- TDM_PORT=8082
- TDM_DATA_DIR=data
restart: unless-stoppedFrom source โ PM2 (two named processes):
TDM_PORT=8080 TDM_DATA_DIR=data pm2 start main.py --name twitchdrops --interpreter python3
TDM_PORT=8082 TDM_DATA_DIR=data2 pm2 start main.py --name twitchdrops2 --interpreter python3
pm2 saveFrom source โ two terminals:
# Terminal 1
TDM_PORT=8080 TDM_DATA_DIR=data python main.py
# Terminal 2
TDM_PORT=8082 TDM_DATA_DIR=data2 python main.pyNginx reverse proxy (single domain, two accounts):
server {
listen 443 ssl;
server_name tdm.example.xyz;
# Account 1 โ root path
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
# Account 2 โ /acc2/ path
location /acc2/ {
proxy_pass http://127.0.0.1:8082/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}Accessing both dashboards:
- Account 1:
https://tdm.example.xyz/(orhttp://localhost:8080) - Account 2:
https://tdm.example.xyz/acc2/(orhttp://localhost:8082) - The web dashboard shows account switcher buttons labeled with each account's Twitch username. Click to jump between dashboards, or append
?acc=2to the URL to go directly to account 2.
- Automatically claims bonus channel point chests via both WebSocket (PubSub) and GQL polling (60s fallback)
- Fixes upstream issues where chests were missed due to unreliable PubSub delivery
- Toggle in Settings tab; real-time balance shown in the Main tab
- Points (Session) stat tracks total bonus points claimed in the current session
- When no drop campaigns are active, automatically watches configured channels to farm channel points
- Auto: use followed channels โ fetches all channels you follow on Twitch that are currently live (via Helix API); no manual config needed
- Manual channel list with priority ordering
- Quick Controls show a "Start Idle Watch" button when idle channels are available, and a "Switch Channel" button while idle-watching
- The switch endpoint skips offline channels and cycles through the full list
- Live per-channel balance with session history
- Compact "Recent channels" section showing the 3 most recently active channels in the main view
- Full ranked list in the Channel Points tab
- Drop claimed โ embed with game, drop name, reward, item thumbnail image, and account name
- Channel points bonus chest โ embed with channel, bonus amount, balance, and account name
- Two separate webhook URLs (drops / channel points) configurable in Settings
- Test button included to verify webhooks without waiting for a real event
- Account name in footer makes it easy to distinguish multiple accounts using the same webhook
A dedicated Discord bot that pairs with your miner instance and sends rich, live-updating notifications โ no webhook URLs needed.
Slash Commands
| Command | Description |
|---|---|
/link <url> <code> |
Pair the bot with your miner dashboard |
/unlink |
Remove the pairing |
/setchannel drops |
Add a channel for drop notifications (multi-server) |
/setchannel points |
Add a channel for channel points notifications (multi-server) |
/dashboard |
Post a live-updating embed with control buttons |
/devpanel |
(Dev-restricted) Global stats + "Post Live Stats" embed |
Key features:
- Multi-server support โ run
/setchannelin multiple Discord servers; all configured channels receive notifications simultaneously - Drop notifications โ one embed per drop, with reward thumbnail image, game, drop name, reward name, and account name in the footer
- Channel points notifications โ fires on gains โฅ 25 pts, showing channel, amount, balance, and account name
- Live dashboard embed โ auto-updates every 30s on state change; shows status, watching channel, points balance, and drop count; owner-only control buttons (Pause/Resume, Switch Mode, View Campaigns, Last Drops, Refresh)
- Live global stats embed โ
/devpanel โ Post Live Stats Hereposts a public embed showing total drops, drops today, channel points, and paired accounts; auto-updates every 30 min and survives bot restarts - Web UI channel config โ Settings โ Discord Bot shows all configured notification channels with name, server, and individual Remove buttons per channel
Invite the bot: โ Add TwitchDropsMiner Bot to your server
Setup:
- Invite the bot to your server using the link above
- In the web dashboard, go to Settings โ Discord Bot โ Generate code
- In Discord, run:
/link https://your-server:8081 DROPS-XXXXXXXX - Run
/setchannel dropsand/setchannel pointsin the channels where you want notifications - Run
/dashboardto post a live-updating stats embed with control buttons
- Click any campaign name in the Inventory to see all its drops in a popup โ images, progress bars, and status badges
- Click โธ N drops left to open the same modal filtered to unclaimed drops only
- "X drops left" count is only shown for linked campaigns
- 3-column CSS Grid layout โ all cards in a row are always the same height
- Farm toggle button shows โ Farming / โ Skip with hover swap animation
- Game name no longer truncates with
... - Campaign end date is always pinned to the bottom of the card
- State-aware Quick Controls โ equal-size 2ร2 grid; buttons highlight based on what the miner is currently doing:
- ๐ข Green: Drop Mining Active (currently farming drops)
- ๐ก Yellow: Skip Game (while a drop is active)
- ๐ฃ Purple: Start Drop Mining / Switch Channel (while idle-watching)
- Channel Points total in Analytics โ replaces "Last Claim" with total session points farmed across all accounts
- Twitch username displayed in login form instead of raw user ID
- Drop Name Blacklist โ comma-separated keywords; drops whose name contains any keyword are skipped
- Inventory filter fixes โ correct AND/OR logic; both Linked/Not-Linked unchecked shows all campaigns
- Dark 7-tab layout: Main, Inventory, Channel Points, History, Analytics, Settings, System, Help
- Drop History tab โ grouped by date, compact single-line rows with item thumbnail images
- Mobile-responsive โ full
@mediabreakpoints at 768px and 480px; compact progress bars on small screens - No-cache headers for web assets; auto-updating cache hash on deploy
- Discord support link in footer โ discord.gg/X5YKZBh9xV
- Set
WEB_PASSWORDto lock the web UI behind a password with 30-day session cookie - Change or remove the password from the Settings tab at any time
| Fix | Upstream issue |
|---|---|
Topics overflow crash (MinerException) โ reserve buffer, catch gracefully |
โ |
| Sub-drops (0-minute timers) hidden by default | #37 |
| Not-Linked drops hidden by default | #51 |
| Spade watch events sent for all channels (not only idle) | โ |
| Channel points webhook missing on WebSocket path | โ |
sendSpadeEvents crash on None response |
โ |
show_sub_drops, claim_channel_points, idle_channels not persisted across restarts |
โ |
| Discord webhooks not populating from saved settings on page load | โ |
update.shโ one-command update that preservesdata/accounts/and all customizations- Docker Compose with
WEB_PASSWORDenv support
- ๐ Streamless Mining โ Earn drops without streaming video by sending Twitch watch events
- ๐ Automatic Campaign Discovery โ Detects new drop events automatically
- โ๏ธ Auto Channel Switching โ Always mines the best available stream
- ๐พ Persistent Login โ OAuth login saved via cookies
- ๐น๏ธ Simple Web UI โ Manage everything from your browser
- ๐ก๏ธ Safe Frontend Rendering โ Dynamic UI content is rendered with DOM APIs to avoid HTML injection
- ๐งฉ Docker-Ready โ One command to deploy anywhere
- ๐ฐ Channel Points Auto-Claimer โ Bonus chests claimed within 60s automatically
- ๐ค Idle Watch โ Earns channel points on favorite channels when no drops are active
- ๐ Channel Points Tracker โ Live balance display with persistent history
- ๐ค Discord Bot โ Live dashboard embed + drop/points notifications across multiple Discord servers
git clone https://github.com/SimpliAj/twitchdropsminer.git
cd twitchdropsminer
docker compose up -dservices:
twitch-drops-miner:
build: .
ports:
- "8080:8080"
volumes:
- ./data:/app/data
- ./logs:/app/logs
environment:
- TZ=Europe/Vienna # Set your timezone
- WEB_PASSWORD=yourpassword # Optional: lock the dashboard
restart: unless-stoppedpip install -e .
python main.pyVisit ๐ http://localhost:8080
Run both accounts simultaneously with Docker Compose:
services:
tdm-account1:
build: .
ports:
- "8080:8080"
volumes:
- ./data:/app/data
- ./logs:/app/logs
environment:
- TZ=Europe/Vienna
- WEB_PASSWORD=yourpassword
- TDM_PORT=8080
- TDM_DATA_DIR=data
restart: unless-stopped
tdm-account2:
build: .
ports:
- "8082:8082"
volumes:
- ./data2:/app/data
- ./logs2:/app/logs
environment:
- TZ=Europe/Vienna
- WEB_PASSWORD=yourpassword
- TDM_PORT=8082
- TDM_DATA_DIR=data
restart: unless-stoppedThen visit:
- Account 1: http://localhost:8080
- Account 2: http://localhost:8082
- Open
http://localhost:8080 - Login with your Twitch account (OAuth device flow)
- The miner auto-fetches available campaigns
- Go to Settings โ Games to Watch and select games:
- Select Linked โ auto-selects games where your account is linked
- Add Game โ add any custom game by name
- Drag to reorder โ top = highest priority
- Select All / Deselect All for quick changes
- Click Reload to apply changes
- TDM starts mining drops automatically ๐
Channel Points (Settings tab):
- Enable Auto-claim bonus channel points to claim chests automatically
- Add channels to Idle Watch to earn points when no drops are active
- Balance is shown in the Main tab and updates every 5 minutes
๐ Tip:
Make sure your Twitch account is linked to your game accounts โ
๐ https://www.twitch.tv/drops/campaigns
To protect the web UI when exposing it publicly (e.g. running on a VPS), set the WEB_PASSWORD environment variable:
# From source
WEB_PASSWORD=yourpassword uv run main.py# Docker Compose
environment:
- WEB_PASSWORD=yourpasswordThe dashboard will show a password prompt on first visit. Auth is stored as a 30-day session cookie. Change or remove the password from the Settings tab in the web UI at any time.
No
WEB_PASSWORDset? The dashboard is open to anyone who can reach the port โ fine for localhost, not for public servers.
โ ๏ธ Avoid Watching on the Same Account
Watching Twitch manually while the miner runs can cause progress desync.
Use a different account if you want to watch live streams while mining.
๐ก Requirements
Python 3.12+
Docker optional but recommended
Persistent data stored in/data
โญ Star this repo if it's useful!
๐ฌ Open an issue or submit a PR for bugs and improvements.
| Goal | Description |
|---|---|
| ๐ฏ Focus | Twitch Drops automation |
| ๐งฉ Ease of Use | Simple web UI |
| ๐ก๏ธ Reliability | Designed for continuous operation |
| โ๏ธ Efficiency | Minimal API calls, Twitch-friendly |
| ๐ณ Deployment | Docker-first, headless operation |
This project builds on the work of:
- @DevilXD โ original creator of TwitchDropsMiner
- @rangermix โ upstream fork this project branched from
For translation credits, see the Original Project Credits section below.
This project is actively developed. It is stable and runs continuously in production,
but use it at your own risk. Always back up yourdata/directory before updating.
@guihkx - For the CI script, CI maintenance, and everything related to Linux builds.
@kWAYTV - For the implementation of the dark mode theme.
@Bamboozul - For the entirety of the Arabic (ุงูุนุฑุจูุฉ) translation.
@Suz1e - For the entirety of the Chinese (็ฎไฝไธญๆ) translation and revisions.
@wwj010 - For the Chinese (็ฎไฝไธญๆ) translation corrections and revisions.
@zhangminghao1989 - For the Chinese (็ฎไฝไธญๆ) translation corrections and revisions.
@Ricky103403 - For the entirety of the Traditional Chinese (็น้ซไธญๆ) translation.
@LusTerCsI - For the Traditional Chinese (็น้ซไธญๆ) translation corrections and revisions.
@nwvh - For the entirety of the Czech (ฤeลกtina) translation.
@Kjerne - For the entirety of the Danish (Dansk) translation.
@roobini-gamer - For the entirety of the French (Franรงais) translation.
@Calvineries - For the French (Franรงais) translation revisions.
@ThisIsCyreX - For the entirety of the German (Deutsch) translation.
@Eriza-Z - For the entirety of the Indonesian translation.
@casungo - For the entirety of the Italian (Italiano) translation.
@ShimadaNanaki - For the entirety of the Japanese (ๆฅๆฌ่ช) translation.
@Patriot99 - For the Polish (Polski) translation and revisions (co-authored with @DevilXD).
@zarigata - For the entirety of the Portuguese (Portuguรชs) translation.
@Sergo1217 - For the entirety of the Russian (ะ ัััะบะธะน) translation.
@kilroy98 - For the Russian (ะ ัััะบะธะน) translation corrections and revisions.
@Shofuu - For the entirety of the Spanish (Espaรฑol) translation and revisions.
@alikdb - For the entirety of the Turkish (Tรผrkรงe) translation.
@Nollasko - For the entirety of the Ukrainian (ะฃะบัะฐัะฝััะบะฐ) translation and revisions.
@kilroy98 - For the Ukrainian (ะฃะบัะฐัะฝััะบะฐ) translation corrections and revisions.



