Claude API WebSocket: Real-Time Chat App Guide
Does Claude have a WebSocket API?
No. Anthropic's Claude API is HTTP-based, not WebSocket-based. There is no wss:// endpoint you can connect to directly for Claude completions. If you're building a real-time chat app and searching for "Claude API websocket," what you actually need is a pattern that bridges Claude's HTTP streaming responses to a WebSocket (or similar persistent connection) between your server and your frontend. That's a very common architecture, and it's straightforward to build.
The short version: your browser or mobile client talks to your server over WebSocket (or Server-Sent Events, which is often simpler and sufficient). Your server talks to Claude over standard HTTPS with streaming enabled, and relays tokens to the client as they arrive. This gives users the "typing" effect of a real-time chat app without requiring Claude itself to support sockets.
Why you need a server in the middle
You can't call the Claude API directly from a browser with your API key — it would be exposed in client-side code, and Anthropic's CORS policy doesn't support unauthenticated browser calls anyway. So every "real-time Claude chat app" has the same three-tier shape:
- Client — browser/mobile app, holds a WebSocket connection to your backend
- Your backend — holds the API key, calls Claude with streaming, forwards chunks
- Claude API (or a gateway in front of it) — does the actual generation
This is also where a service like SubToAPI fits in: instead of managing raw API keys and billing plumbing yourself, you issue sub_live_... application keys from your SubToAPI dashboard, and your backend uses those to call a single stable endpoint with streaming, usage metadata, and team seat management already handled.
Building the WebSocket relay
Here's a minimal Node.js WebSocket server that proxies a streaming completion to connected clients.
import { WebSocketServer } from "ws";
import fetch from "node-fetch";
const wss = new WebSocketServer({ port: 8080 });
wss.on("connection", (socket) => {
socket.on("message", async (raw) => {
const { messages } = JSON.parse(raw.toString());
const response = await fetch("https://api.subtoapi.app/v1/messages", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "claude-3-5-sonnet",
max_tokens: 1024,
stream: true,
messages,
}),
});
for await (const chunk of response.body) {
const text = chunk.toString();
// forward each SSE line to the client as it arrives
for (const line of text.split("\n")) {
if (line.startsWith("data:")) {
socket.send(line.replace("data:", "").trim());
}
}
}
socket.send(JSON.stringify({ type: "done" }));
});
});
On the client side, you just listen for messages and append tokens to the UI:
const socket = new WebSocket("wss://your-server.example.com");
socket.onmessage = (event) => {
const payload = JSON.parse(event.data);
if (payload.type === "content_block_delta") {
appendToChatBubble(payload.delta.text);
}
};
socket.send(JSON.stringify({
messages: [{ role: "user", content: "Explain WebSockets in one paragraph." }],
}));
This pattern scales to multiple concurrent users as long as your server can hold many open sockets and fan out streamed chunks independently — which Node, Go, or any async-capable runtime handles fine.
WebSocket vs. Server-Sent Events
Before committing to WebSocket, consider whether you actually need bidirectional, low-latency sockets, or whether Server-Sent Events (SSE) would be simpler. SSE is unidirectional (server to client), works over plain HTTP, and is natively supported by EventSource in browsers with automatic reconnection. For a chat app where the main real-time requirement is "stream the assistant's reply token by token," SSE is often enough and removes a layer of complexity.
Use WebSocket instead when you need:
- Bidirectional signals mid-generation — e.g., the user can interrupt or redirect the model while it's still responding
- Multiplexed channels — multiple conversation threads or presence indicators over one connection
- Low-latency typing indicators or multi-user chat rooms where Claude is one participant among several
If you're unsure, start with SSE. It maps almost one-to-one onto how SubToAPI streams responses, and you can read more about chunk handling in the streaming docs.
Handling disconnects and reconnection
Real-time apps live or die on how they handle network interruptions. A few practical rules:
- Buffer partial responses server-side. If a client disconnects mid-stream, keep the Claude request running and cache the output so a reconnecting client can catch up instead of restarting the whole generation.
- Send heartbeats. WebSocket connections behind proxies and load balancers can silently die. A ping/pong every 20–30 seconds keeps the connection alive and detects drops quickly.
- Make streaming idempotent. Attach a request ID to each generation so your relay layer can deduplicate if the client retries while a previous stream is still in flight.
- Set sane timeouts. Long-running completions should still have an upper bound — don't let a single hung request hold a socket open indefinitely.
Authentication and tool use in a chat app
A chat app isn't just text in, text out — most real products eventually need function calling (looking up order status, searching a knowledge base, calling internal APIs). That works the same way over your WebSocket relay: Claude returns a tool-use block instead of plain text, your server executes the tool, and you send the result back in a follow-up request, streaming the final answer to the client exactly as before. See the tools docs for the request shape, and the Messages API reference for how streamed tool-use deltas are structured.
If you'd rather not build and maintain the key management, usage tracking, and billing plumbing behind all of this yourself, SubToAPI gives you a single API key per app, per-request usage metadata, and team seats, so your WebSocket relay only has to handle the socket logic — not the account layer underneath it. You can try it with a free trial at signup.
Questions
Does Claude natively support WebSocket connections? No. Claude's API is HTTP with optional response streaming (SSE-style chunks). You build your own WebSocket layer between your server and client, with your server calling Claude over HTTPS.
Should I use WebSocket or Server-Sent Events for a Claude-powered chat app? SSE is simpler and sufficient for one-directional token streaming. Use WebSocket only if you need bidirectional communication, like letting users interrupt a response or multiplexing several conversations on one connection.
How do I stream Claude's response token by token to the frontend? Call Claude with stream: true, read the SSE chunks on your server as they arrive, and forward each content_block_delta chunk over your WebSocket or SSE connection to the client in real time — see /docs/streaming for the full chunk format.