Connect to Kick.com live chat directly from the browser - no server, no Puppeteer, no headless browsers.
A lightweight browser SDK that resolves chatroom IDs and connects to Kick's Pusher WebSocket client-side. Works in any browser environment including OBS browser sources.
Built by Slipz for SlipzTools. Client-side rewrite by @bebiksior.
To read Kick chat, you need to subscribe to a Pusher WebSocket channel called chatrooms.{chatroom_id}.v2. Getting that chatroom_id is the hard part:
- Official Kick API (
api.kick.com) - does NOT returnchatroom_id. Only returnsbroadcaster_user_id, which is a different number. - Unofficial Kick API (
kick.com/api/v1/channels/{slug}) - returnschatroom.id, but Cloudflare blocks server-side requests. - Puppeteer approach - uses a headless browser to bypass Cloudflare. Works, but adds ~300MB of dependencies and is slow.
broadcaster_user_id != chatroom_id:
| Channel | broadcaster_user_id |
chatroom_id |
|---|---|---|
| xqc | 676 | 668 |
Subscribing to chatrooms.676.v2 gives you nothing. You need chatrooms.668.v2.
Skip the server entirely. The browser can fetch from kick.com directly (no CORS issues in browser context), resolve the chatroom ID, and connect to Pusher - all client-side.
Browser
|
|-- fetch kick.com/api/v1/channels/xqc --> { chatroom: { id: 668 } }
|
|-- connect wss://ws-us2.pusher.com/...
|-- subscribe chatrooms.668.v2
|
|<-- ChatMessageEvent { sender: "user", content: "hello" }
No server to maintain, no cache to poison, no proxy to DDoS.
git clone https://github.com/slipzdev/kick-chat-bypass.git
cd kick-chat-bypass
npm startOpen http://localhost:3000 in your browser. Type a channel name and hit Connect.
Include the SDK and create a connection:
<script src="kick-chat.js"></script>
<script>
const chat = new KickChat('xqc')
chat.on('connected', ({ chatroomId }) => {
console.log('connected to chatroom', chatroomId)
})
chat.on('message', ({ author, text, color, raw }) => {
console.log(`${author}: ${text}`)
})
chat.on('error', ({ message }) => {
console.error(message)
})
chat.on('status', ({ state }) => {
// 'resolving' | 'reconnecting'
console.log('status:', state)
})
chat.on('disconnected', () => {
console.log('disconnected')
})
chat.connect()
// later: chat.disconnect()
</script>| Event | Data | Description |
|---|---|---|
connected |
{ chatroomId } |
Successfully subscribed to the chat channel |
message |
{ author, text, color, raw } |
Chat message received. raw contains the full Kick payload |
error |
{ message } |
Connection or resolution error |
status |
{ state } |
Status changes: resolving, reconnecting |
disconnected |
{} |
Clean disconnect after calling disconnect() |
KickChatfetches the channel data fromkick.com/api/v1/channels/{slug}(falls back to v2)- Extracts
chatroom.idfrom the response - Opens a WebSocket to Kick's Pusher endpoint (
wss://ws-us2.pusher.com/app/...) - Subscribes to
chatrooms.{id}.v2 - Parses incoming
ChatMessageEventmessages and emits them asmessageevents - Sends keepalive pings every 30s to prevent Pusher from dropping the connection
- Auto-reconnects on disconnect (3s delay)
MIT