A lightweight live chat overlay that connects to a remote Streamer.bot instance over WebSocket and displays Twitch/YouTube chat messages in a clean dark-themed browser window.
Streamer.bot (Windows PC at 10.0.0.95)
│
│ WebSocket ws://10.0.0.95:8080
│
Linux machine
└── ./chat (bash script)
└── localhost HTTP server
└── brave-origin-nightly (Chromium-based)
└── chat.html (UI + streamerbot-client.js)
- The
chatscript starts a local HTTP server on127.0.0.1and launches an isolated Brave Nightly window pointed atchat.html. chat.htmlloads the bundledstreamerbot-client.jslibrary and opens a WebSocket connection to Streamer.bot.- Incoming
Twitch.ChatMessageandYouTube.ChatMessageevents are parsed and rendered in real time.
Using localhost avoids file:// browser security restrictions and works reliably in browsers and embedded previews.
| Dependency | Purpose |
|---|---|
brave-origin-nightly |
Chromium-based browser used to display the overlay |
bash |
Runs the launcher script |
python3 |
Serves the overlay over localhost |
curl is not required.
remote-streamerbot-chat/
├── chat # Bash launcher script
├── chat.html # Chat overlay UI
├── streamerbot-client.js # Bundled @streamerbot/client library (local copy)
├── install.sh # Installs the desktop entry for your app launcher
└── README.md # This file
- Open Streamer.bot.
- Go to Servers/Clients → WebSocket Server.
- Enable the WebSocket server.
- Set the bind address to your LAN IP (e.g.
10.0.0.95) — not127.0.0.1, otherwise remote connections will be refused. - Set the port to
8080(or updatechat.htmlto match your chosen port). - Make sure your Windows firewall allows inbound connections on that port.
Clone the repo:
git clone https://github.com/YOUR_USERNAME/remote-streamerbot-chat.git
cd remote-streamerbot-chatMake the script executable:
chmod +x chatEdit chat.html and update the host/port to match your Streamer.bot machine:
const client = new StreamerbotClient({
host: "10.0.0.95", // ← your Streamer.bot machine's LAN IP
port: 8080,
password: "", // ← fill in if you set a password in Streamer.bot
autoReconnect: true,
...
});./chatOr from anywhere:
~/github/remote-streamerbot-chat/chatThe overlay opens as a standalone app window (no browser chrome/address bar) with:
- A dark header showing "Live Chat" and a connection status badge
- 🟠 Orange = Connecting…
- 🟢 Green = Connected
- 🔴 Red = Disconnected
- Each chat message shows:
- 🟣 Twitch or 🔴 YouTube platform icon
- User badges (broadcaster, subscriber, etc.)
- Username in the user's chat colour
- Message text
- Timestamp
The window blocks the terminal until it is closed, then exits cleanly.
#!/usr/bin/env bash
CHAT_DIR="$HOME/github/remote-streamerbot-chat"
CHAT_FILE="$CHAT_DIR/chat.html"
PROFILE_DIR="$HOME/.config/streamerbot-chat-profile"
SERVER_HOST="127.0.0.1"
SERVER_PORT="${STREAMERBOT_CHAT_PORT:-8765}"
BROWSER_CMD="${STREAMERBOT_CHAT_BROWSER:-brave-origin-nightly}"CHAT_DIR— absolute path to the project directory so the local HTTP server can exposechat.htmlandstreamerbot-client.js.CHAT_FILE— absolute path to the HTML entry file, hardcoded to$HOME.PROFILE_DIR— a persistent isolated Chromium profile stored in~/.config. Keeping it persistent avoids a slow first-run initialisation on every launch.SERVER_PORT— the local port used for the temporary HTTP server. Override withSTREAMERBOT_CHAT_PORTif needed.BROWSER_CMD— browser executable used to open the overlay. Override withSTREAMERBOT_CHAT_BROWSERif you want a different Chromium-based browser.
rm -f "$PROFILE_DIR/SingletonLock" "$PROFILE_DIR/SingletonCookie" "$PROFILE_DIR/SingletonSocket"Chromium writes a SingletonLock file to prevent two instances sharing a profile. If the browser crashes or is killed, the lock is never cleaned up, causing subsequent launches to hand the URL off to a non-existent process (resulting in a grey window). Only the lock files are removed — the rest of the profile is preserved.
python3 -m http.server "$SERVER_PORT" \
--bind "$SERVER_HOST" \
--directory "$CHAT_DIR" \
>/dev/null 2>&1 &
"$BROWSER_CMD" \
--user-data-dir="$PROFILE_DIR" \
--disable-gpu \
--ozone-platform=x11 \
--no-first-run \
--no-default-browser-check \
--disable-extensions \
--class="StreamerBotChat" \
"http://${SERVER_HOST}:${SERVER_PORT}/chat.html"| Flag | Reason |
|---|---|
--user-data-dir |
Forces a new isolated browser process; prevents URL handoff to an existing browser session |
--disable-gpu |
Works around a vaInitialize failed GPU error that causes grey windows on some systems |
--ozone-platform=x11 |
Explicitly selects X11 rendering on X11 sessions |
--no-first-run |
Skips the new-profile welcome screen |
--no-default-browser-check |
Suppresses the browser default-check prompt |
--disable-extensions |
Prevents extensions (e.g. uBlock) from initialising, speeding up startup |
--class=StreamerBotChat |
Sets the X11 window class, useful for window manager rules |
The script runs the local server in the background, waits for it to become reachable, then runs the browser in the foreground. When the browser exits, the background server is cleaned up automatically.
streamerbot-client.js is a local copy of the
@streamerbot/client npm package.
It is bundled locally so the overlay works without internet access.
To update it to the latest version:
curl -sL "https://cdn.jsdelivr.net/npm/@streamerbot/client/dist/streamerbot-client.js" \
-o ~/github/remote-streamerbot-chat/streamerbot-client.jsEdit chat.html and update the StreamerbotClient constructor:
const client = new StreamerbotClient({
host: "10.0.0.95", // LAN IP of the machine running Streamer.bot
port: 8080, // WebSocket server port set in Streamer.bot
password: "", // Leave empty if no password is set
autoReconnect: true,
...
});Run the included install script to register the overlay as an application in your launcher (rofi, dmenu, GNOME, KDE, etc.):
./install.shThis will:
- Make the
chatscript executable - Write a
.desktopentry to~/.local/share/applications/streamerbot-chat.desktopusing the correct absolute path automatically - Refresh the desktop database so the entry appears in your launcher immediately
You can then launch StreamerBot Chat from your application launcher like any other app, no terminal needed.
If you want the local chat server to always be available (including the /notify endpoint for dunst), install the user service:
cd ~/github/remote-streamerbot-chat
./install-user-service.shThen open the page directly in any browser:
http://127.0.0.1:8765/chat.html
Useful commands:
systemctl --user status streamerbot-chat-server.service
systemctl --user restart streamerbot-chat-server.service
systemctl --user stop streamerbot-chat-server.service
systemctl --user disable streamerbot-chat-server.serviceTo start user services even when not logged in, enable lingering:
loginctl enable-linger "$USER"Grey/blank window on launch
The SingletonLock cleanup in the script handles this automatically. If it still happens, delete the entire profile and let it rebuild:
rm -rf ~/.config/streamerbot-chat-profileUnsafe file:// origin errors
Open the overlay through ./chat, not by opening chat.html directly in a browser or VS Code file preview. The launcher now serves the page over http://127.0.0.1, which avoids file:// origin restrictions.
Status stays "Connecting…" forever
- Confirm Streamer.bot is running on the Windows machine.
- Confirm the WebSocket server in Streamer.bot is enabled and bound to the LAN IP (not
127.0.0.1). - Test connectivity from the Linux machine:
nc -zv 10.0.0.95 8080
- Check that the Windows firewall allows inbound TCP on port 8080.
Messages appear but are blank
The payload structure from Streamer.bot changed. Open chat.html, add onData: (raw) => console.log(raw) to the StreamerbotClient constructor, relaunch, and inspect the browser console (right-click → Inspect) to see the raw payload shape. Then update handleChatMessage accordingly.
"Opening in existing browser session" and nothing loads
An existing browser window is running without --user-data-dir. The SingletonLock cleanup and --user-data-dir flag together prevent this. If it recurs, kill all Brave Nightly processes:
pkill brave-origin-nightlyThen relaunch with ./chat.