// docs / websocket-obs
WebSocket & OBS
LiveAudio runs a local WebSocket server that broadcasts subtitle JSON in real time. OBS is the built-in target via the included subtitulos_obs.html overlay, but any HTML or WebSocket client on localhost can connect and receive the same broadcast.
Server details
| Parameter | Value |
|---|---|
| Protocol | WebSocket (ws://) |
| Host | 127.0.0.1 (localhost only) |
| Port | 8765 by default, configurable via ws_port |
| Format | JSON |
| Auth | None — bound to localhost only |
JSON payload schema
{
"id": "1760000000000-12",
"text": "Hello everyone, welcome to the stream",
"style": "default",
"created_at": 1760000000.0,
"processed_at": 1760000001.3,
"queue_delay": 0.2,
"total_delay": 1.3,
"latency": 1.1,
"is_replay": false,
"catchup_interval_sec": 0.0
} | Field | Type | Description |
|---|---|---|
id | string | Stable identifier for the phrase within the session. |
text | string | Transcribed text, after blacklist filtering. |
style | string | Visual style: default, karaoke, neon, minimal, bold, rgb, typewriter. |
created_at | number | Timestamp when the audio segment was created. |
processed_at | number | Timestamp when transcription completed. |
queue_delay | number | Seconds the audio waited before entering the ASR engine. |
total_delay | number | Total delay from audio capture to a ready subtitle (sub-second to ~1 s on a typical setup). |
latency | number | Seconds Whisper spent transcribing the segment. |
is_replay | boolean | Whether this is a backlog / catch-up subtitle. |
catchup_interval_sec | number | Recommended pacing between backlog items in auto mode. |
The built-in OBS overlay only consumes text and style. The remaining fields are metadata for diagnostics and backlog control — useful if you build your own client, ignorable if you do not.
Subtitle styles
The style field selects one of seven built-in looks, switchable from the Subtitles tab:
| Style | Look |
|---|---|
default | White text on a semi-transparent black background, soft fade in/out. |
karaoke | Words appear staggered with a popIn animation; bright yellow with a black outline. |
neon | Cyan glow, uppercase, wide letter-spacing. |
minimal | No background, subtle fade — for streams with their own design. |
bold | High-contrast thick text, fast animation, strong on-screen presence. |
rgb | Each word takes a different rainbow color. |
typewriter | Words type in one at a time with a blinking cursor; monospaced. |
OBS backlog policy
The backlog policy controls only what shows live in OBS. Everything valid is always saved to disk regardless of policy.
| Mode | Config value | Behavior |
|---|---|---|
| Auto | auto | Sends fresh subtitles plus a short, paced backlog. Drops anything past the max delay. |
| Live only | live_only | Saves everything; shows only what is within subtitle_max_live_delay_sec. |
| Send all | send_all | Sends everything to OBS even when it arrives late. |
Security
- Localhost only — the server rejects any connection that is not from
127.0.0.1,::1orlocalhost. - No authentication required, because it is bound to localhost.
- Broadcast — multiple clients receive the same messages simultaneously.
OBS Browser Source setup
- In OBS, Sources → + → Browser.
- Choose Local file and select
subtitulos_obs.html(inliveaudio/assets/). Set size 1920×200. - Set FPS to
30or60, and place the source bottom-center in your scene. - Disable "Shut down source when not visible" and "Refresh browser when scene becomes active" — both can drop the WebSocket connection.
- For a custom port, set
ws_portinconfig.json; the OBS HTML reads?port=XXXXfrom its URL (default8765).
Connection behavior
- Reconnect. A client that loses the connection retries about every 3 seconds until the server is back — the bundled overlay does this for you.
- Broadcast. Every connected client receives every message. Multiple clients (OBS plus a debug browser tab) all see the same stream, and a slow client does not block the others.
- No backpressure. On
websockets ≥ 16the server usesbroadcast(), which fans out without waiting on any single client.
Build your own client
Any localhost WebSocket client can subscribe to the same broadcast OBS reads. A minimal browser client — open the file directly, or load it as an OBS Browser Source:
<!-- open this file in a browser, or load it as an OBS Browser Source -->
<div id="caption"></div>
<script>
// ?port=XXXX overrides the default; matches ws_port in config.json
const port = new URLSearchParams(location.search).get("port") || "8765";
let ws;
function connect() {
ws = new WebSocket("ws://127.0.0.1:" + port);
ws.onmessage = (e) => {
const msg = JSON.parse(e.data); // the subtitle payload
document.getElementById("caption").textContent = msg.text;
};
// the server only broadcasts — reconnect every 3 s if it drops
ws.onclose = () => setTimeout(connect, 3000);
}
connect();
</script> Or a minimal Python client, to print every payload as it arrives (requires the websockets package):
import asyncio, websockets
async def test():
async with websockets.connect("ws://127.0.0.1:8765") as ws:
async for msg in ws:
print(msg)
asyncio.run(test()) Debug signals
Open the overlay in a browser and press F12 → Console. These messages tell you where a stalled overlay is stuck:
| Console message | Meaning |
|---|---|
Conectado al motor ASR | Connected successfully — the WebSocket is live. |
Desconectado. Reintentando… | Cannot connect: LiveAudio is not started, the port is busy, or the ?port= in the URL does not match ws_port. |
Error parseando WebSocket | A non-JSON / non-dict message reached the overlay — the payload was not a valid subtitle object. |