StreamHive lets you watch multiple Twitch channels at once in a single grid, using the official Twitch Embed API for video and chat. No setup is required on the streamers' side.
- Three audio modes — Selection, Both/All, and an exploratory SmartVoiceSwitch
- Layout templates saved to a lightweight account via Twitch OAuth login
Note
Live app: stream-hive-ten.vercel.app — the backend runs on Render's free tier, so the first request after a period of inactivity can take up to a minute to wake up.
| Layer | Technology |
|---|---|
| Frontend | React (Vite) |
| Backend | Node.js + Express |
| Database | Postgres, hosted free on Neon |
| Hosting | Backend on Render's free web service tier, frontend on a static host (Vercel/Netlify) |
Note
Full architecture, data model, and reasoning behind these choices are kept in local planning notes outside this repository (not part of what's cloned from GitHub).
Core viewing experience — works end to end against real Twitch channels:
- 1–6 channel video grid with add/remove
- Both audio modes (Selection with focus-follows-audio layout, Both/All with per-panel volume)
- Online/offline detection via a backend Helix poll
- Chat bar with one always-mounted tab per channel (chat follows the active audio channel until manually overridden)
- Native per-panel actions (follow, donate, channel link)
- Twitch OAuth login wired into the app shell, gating the follow action — anonymous read-only viewing works without login
Account features (Phase 2):
- Saving/loading/deleting named grid templates from the top bar (login-gated, with channel validation on load — renamed or banned channels render a "channel not found" panel)
- An "Online now" menu with two sections — channels the logged-in user follows that are live right now, and the current top live channels on Twitch by viewer count — each with one-click add-to-grid
Warning
Following requires the user:read:follows OAuth scope; users who logged in before the scope change are re-prompted to log in. Twitch tokens are refreshed server-side on expiry — nothing from the Twitch API is ever persisted.
Requires a Twitch app (Confidential client type) registered in the Twitch Developer Console, with http://localhost:3000/auth/twitch/callback as a registered redirect URI, and a Postgres database (this project uses Neon's free tier).
-
Create a
.envfile (never committed) with:PORT=3000 FRONTEND_URL=http://localhost:5173 TWITCH_CLIENT_ID=<your client id> TWITCH_CLIENT_SECRET=<your client secret> TWITCH_REDIRECT_URI=http://localhost:3000/auth/twitch/callback DATABASE_URL=<your Postgres connection string> TOKEN_ENCRYPTION_KEY=<64-char hex string, 32 bytes, for AES-256-GCM>Generate
TOKEN_ENCRYPTION_KEYwithopenssl rand -hex 32.[!WARNING] The backend refuses to start without
TOKEN_ENCRYPTION_KEY. Keep it stable: changing it makes every stored token undecryptable and forces all users to log in again. -
Run
schema.sqlagainst that database to create theusers,templates, andsessionstables. -
npm install -
npm run dev
Tip
For a deployed backend, also set NODE_ENV=production (the backend only marks the session cookie Secure outside local dev) and point TWITCH_REDIRECT_URI at the frontend's callback URL, e.g. https://<your-frontend>/auth/twitch/callback, so the callback reaches the backend through the proxy described below. That URL also has to be registered under OAuth Redirect URLs in the Twitch console.
npm installnpm run dev, then openhttp://localhost:5173
No .env needed for local dev — it defaults to http://localhost:3000.
Important
A deployed build needs no backend URL either, and VITE_BACKEND_URL should be left unset: vercel.json proxies /api/* and /auth/* to the backend, so the frontend calls them as relative paths on its own origin. That keeps the session cookie first-party. Hosting the two on separate domains instead makes it a third-party cookie, which browsers drop — the login then completes without ever signing you in. Update the destination URLs in vercel.json if the backend moves.
Setting VITE_BACKEND_URL overrides the proxy and calls the backend directly; it exists for local dev and non-proxied hosts. Vite only exposes VITE_-prefixed vars to client code and bakes them in at build time, so it has to be set wherever the frontend is built, not just at runtime.
Sessions map a session cookie to a users.id and are persisted in Postgres (see schema.sql), so they survive a backend restart or redeploy.
| Branch | Purpose |
|---|---|
dev |
All development happens here |
main |
Stable branch, merged from dev manually, only when a milestone is ready |
docs |
Owns documentation-only changes (wiki, README, contributing guidelines, PR templates) |
Commit messages follow Conventional Commits (feat:, fix:, chore:, docs:, refactor:, perf:, test:).
Contributions are welcome! Please read the Contributing guide and Code of Conduct before opening a pull request. Found a security issue? See SECURITY.md instead of opening a public issue.
Licensed under MIT