Backend: one SSE stream for messages, selection, poll and connection status; reconnect with backoff; no on-disk Innertube session cache; mock only with MOCK_CHAT=1; binds to 127.0.0.1; serves client/out so production runs on one port. Full URLs for links YouTube truncates in chat. Client: components split out, Lucide icons, stream title and status, on-air strip, search, pause, keyboard shortcuts, overlay settings dialog. Overlay themes, position, size, animation and auto-hide via URL, sized for 1080p and scaled with the source. New blueprint theme for the brand background. Removed Tailwind, better-sqlite3, zod, the timezone helpers, Cline memory bank and AGENTS.md. Added ESLint, node:test tests and CI.
YTChatHub
Open-source YouTube Live chat client for streamers. Watch the chat in a fast dashboard, click a message and it appears on an OBS browser-source overlay. Super Chats, super stickers, memberships, gifted memberships, badges, custom emojis and the chat leaderboard are all shown. Long links in chat arrive with their full URL, not the truncated text YouTube displays.
Running it
Requires Node.js 20+ and pnpm.
pnpm install
pnpm build
pnpm start
Open http://localhost:4100, paste the live stream URL or video id, and add the overlay URL from the dashboard's Overlay button as an OBS Browser Source. The overlay's theme, position, size, animation and auto-hide are set in that URL, so different sources can look different.
pnpm dev runs the backend on 4100 and the Next.js client on 3100 with hot reload. Optional environment variables: YOUTUBE_LIVE_ID connects at startup, PORT and HOST change where the backend listens (it binds to 127.0.0.1 by default), MOCK_CHAT=1 generates fake messages when nothing is connected.
Keyboard: / focuses search, P pauses the chat, Esc clears the overlay.
Stack
Fastify backend with youtubei.js for chat ingestion, one Server-Sent Events stream for messages, selection and connection status, and a Next.js static export served by the same backend. Chat runs entirely on your machine; YouTube CDN images are proxied and cached locally so OBS never hits rate limits.
