Runs 24/7 for a live Twitch channel. Overlays are public; the admin panel sits behind Twitch login.
Twitch Stream Toolkit
A config-driven Twitch bot with a real-time OBS overlay system and a Twitch-authenticated web admin panel, built on Node with zero web dependencies and deployed on AWS behind automatic HTTPS, paired with a companion Chrome extension that automates on-stream privacy protection. Built for a live channel (internally “bob-a-bot”), then generalized into a reusable, secret-free template.
Channels It Runs For
bobavillain
Runs 24/7 as “bob-a-bot” on the Twitch channel bobavillain, the channel it was originally built for.
Ready for More
Because the whole platform is config-driven, the same bot can be stood up for additional channels from a single JSON file, with no code changes.
Project Overview
One self-hosted app that covers counters, song requests, alerts, moderation, and on-stream overlays, fully controllable by the streamer and their mods from chat or a web dashboard.
Streamers usually stitch together several paid third-party services to cover these features. This replaces them with a single app the streamer owns and controls.
Built for one specific channel, then generalized into a config-driven template so the same platform can be stood up for anyone.
Core Features
Chat & Channel Points
- Counters via Channel Points, bit cheers, and chat commands
- Custom commands matched on the first word
- Timers and timed challenges
- Clips and stream title / category controls
Moderation & Community
- Shoutouts (/announce plus native Twitch popup)
- Follower thanks and follow-age lookups
- Chat moderation: timeout, ban, and unban
- Redeem logs and a game backlog
OBS Overlays
- Three independent, movable browser sources
- Countdown timer that cycles through multiple timers
- Live counters ticker
- Spotify now-playing card that auto shows / hides
Web Admin Panel
- Twitch login, gated to broadcaster, allowlist, and mods
- Live counters and command / quote / game management
- Timeout, ban, unban, and redeem history
- Diagnostics page that fires overlay tests
External Services
- Spotify song requests
- DeepL live translation
- Weather (Open-Meteo) and other no-key APIs
- Each integration stays off until it's configured
Live Events (EventSub)
- Channel Point redemptions
- Raids and go-live notifications
- New follows
- Delivered over an EventSub WebSocket listener
Overlay Preview
Countdown timer: label, note, live countdown, and a progress bar, cycling through multiple configured timers.
Live counters ticker: one card per active counter, driven by Channel Points, bit cheers, and chat commands.
Spotify now-playing card: current track and artist with a progress bar, auto showing and hiding with playback.
How It Works
One Long-Lived Node Process
A single process connects to Twitch chat and EventSub and starts an embedded web server in the same process, with no separate services to orchestrate.
One Server, Three Jobs
The embedded server serves the OBS overlays (pushing live state over SSE), serves the Twitch-OAuth admin panel, and exposes a small JSON API the panel calls.
Reverse Proxy
Caddy sits in front on port 443 for HTTPS and proxies to the bot on an internal port, keeping the Node process off the public interface.
Flat-File Persistence
Counters, commands, quotes, and timers persist to JSON files on disk, one file per feature. Simple, transparent, and trivially backed up, with no database to run.
Streamer Privacy Guard
An unpacked Chrome extension that redacts personal information and blocks mail sites, but only while the stream is live. Offline, it is fully unloaded rather than merely disabled: no content script runs, no blocking rules exist, nothing executes on any page. Not published to the Chrome Web Store by design; loaded unpacked on the streaming machine.
Search results redacted live: the map thumbnail is blurred and location detail lines are blacked out, matching the Redaction and Location Guard behavior.
A mail host swapped for the self-restoring placeholder: nothing is closed, and the tab returns to Gmail on its own once the stream ends.
Live State from the Bot
Polls a public /live endpoint added to the existing bot server, backed by an in-memory value that Twitch EventSub keeps current, so checking it costs nothing. A missing or stale signal is treated as live, so a dropped connection can never silently un-blur the screen.
Text, Two Layers Deep
A personal list of exact strings (name, address, old handles) plus generic safety-net patterns for emails, phones, addresses, and Luhn-checked card numbers. Three looks are available: blend, black bars, and a tunable blur, chosen per field.
Maps and Place Names
Blurs and desaturates map surfaces across Google Maps, embedded iframes, and Leaflet/Mapbox/OpenLayers widgets, and hides the location furniture search engines and shops wrap around a city, down to context-matched ZIPs and a curated place-name list.
Self-Restoring Mail Blocks
Mail hosts redirect to a local placeholder that carries the original URL and navigates back on its own once the stream ends. Nothing is closed and no draft is lost; the tab title is blanked before the redirect so the address never flashes.
Auto, Always On, Always Off
Auto follows the live signal for normal use. Always On arms it for testing or a minute before going live. Always Off stays fully dormant. Both forced modes badge purple so a test can never be mistaken for a real live signal.
Hold to Peek
A configurable hold-to-peek shortcut reveals redactions only while held, with a warning banner across the top. Releasing the key, switching tabs, or leaving the window all re-hide immediately.
Privacy Guard Decisions
Unknown State Means Stay Redacted
A missing check or one older than two minutes is treated the same as live. Worst case is mild annoyance browsing off-stream; the alternative worst case is a doxx on stream, so the fallback only ever leans toward more redaction, never less.
Text Is Barred or Blended, Never Blurred
A blurred string can be undone by rendering candidate text at the same radius and matching against the frame, since the alphabet is small and known, a documented attack a VOD gives unlimited time to run. Maps get heavy blur instead, since deblurring imagery isn't practical the same way.
Dormant Means Unloaded, Not Idle
The content script is registered when live and unregistered when offline through chrome.scripting, so when the stream is down no extension code runs on any page at all rather than sitting idle on every tab.
Two Independent Blocking Paths
Chrome silently refuses declarativeNetRequest redirects for null-initiator navigations, like a typed URL, with no error anywhere. A second, independent tabs listener does the same job so either path alone can fail without the block failing.
Tools + Build
Decisions Worth Calling Out
Config-Driven, Not Hard-Coded
Around 40 features toggle and tune through a single JSON file, so a non-developer can reconfigure the bot and it generalizes cleanly into a template. This is the core architectural bet.
Zero Web Dependencies
Routing, SSE, sessions, OAuth, and CSRF are all built on Node built-ins plus fetch: no Express, no framework, no build step. Tiny footprint and minimal supply-chain surface.
SSE-Driven Overlays
Overlay updates are one-directional, so Server-Sent Events beat WebSockets here: simpler, auto-reconnecting, no library. Countdowns tick locally in the browser from a server-sent end timestamp, so they stay smooth and network-light.
Security by Least Exposure
Overlays are gated by a secret key; the admin panel is Twitch-OAuth gated to an allowlist and mods, with HMAC-signed SameSite=Lax session cookies and a custom-header CSRF check. No secrets ever reach the client.
Deployment & Reliability
Self-Hosted on AWS
Runs on an AWS EC2 instance (Amazon Linux) with pm2 for process management and reboot persistence, on a static Elastic IP with DNS via a subdomain.
Automatic TLS
A Caddy reverse proxy provisions and renews Let's Encrypt certificates automatically, so HTTPS is hands-off.
Backups & Monitoring
Nightly cron backups protect the flat-file data, and UptimeRobot health-checks a /health endpoint so outages surface immediately.
Reusable Template
Extracted a generic, secret-free template from the live bot without taking the running instance down, genericizing hard-coded labels into config along the way.
Engineering Challenges
Multi-Timer Reconciliation
Several timers can run at once (challenge redeems plus reminders). The overlay reconciles a live list over SSE and cycles through them (~15s each), giving each its own style and an independent local countdown.
Readable Over Any Scene
Overlays have to read over arbitrary gameplay footage. Solved with solid tile backings and text outlines (no drop shadows), tested against both bright and dark scenes.