Solution skill
Express: pair browser and OpenAI sockets for the Realtime API
Complete solution
Shows how to fix express: pair browser and OpenAI sockets for the Realtime API. Use it when you hit this exact problem. Skip it when your error message or symptom looks different.
TL;DR
- npm install ws (and openai if you use the SDK helpers). Create an HTTP server from your Express app and attach a ws WebSocketServer with noServer: true; handle the upgrade event and route by path, for example /realtime. Forgetting the timer is a slow memory leak, one per call. - Backpressure: check socket.bufferedAmount before forwarding large audio bursts; pause the upstream reader when the browser falls behind.
When to use
You are seeing this: When a browser client connects, open the upstream OpenAI websocket from the server with the Authorization Bearer header carrying your server-side key. Use this skill when you run into "Express: pair browser and OpenAI sockets for the Realtime API".
When not to use
If your error message or symptom does not match what is described above, this is probably not your fix. Search for your exact error text instead of forcing this one to fit.
Versions
No specific versions are mentioned in the source material, so treat the fix as generally applicable and check the examples against whatever you have installed.
Express Realtime websocket relay
Setup
npm install ws(andopenaiif you use the SDK helpers).Create an HTTP server from your Express app and attach a
wsWebSocketServer withnoServer: true; handle theupgradeevent and route by path, for example/realtime.When a browser client connects, open the upstream OpenAI websocket from the server with the Authorization Bearer header carrying your server-side key.
Send
session.startfirst, wait forsession.started, then begin relaying frames in both directions.
Frame relay rules
Browser audio arrives as JSON events with base64 PCM16 24kHz chunks; forward them upstream unchanged.
- Upstream
response.audio.deltaevents go straight back to the browser socket. Never parse-and-rebuild frames you do not need to inspect; forward the raw message to avoid corrupting base64 payloads.
Lifecycle (the Node traps)
wssockets do not auto-ping. Send ping frames on an interval and terminate sockets that miss pong; otherwise dead mobile clients hold sessions open.On
closeof either socket,close()the other immediately and clear the heartbeat timer. Forgetting the timer is a slow memory leak, one per call.Backpressure: check
socket.bufferedAmountbefore forwarding large audio bursts; pause the upstream reader when the browser falls behind.
Check before you ship
Two concurrent calls must not cross audio: tag each relay pair with the session id from
session.startedand assert isolation in a test.Confirm the server-side key never reaches the browser; the browser socket carries only audio and control frames.
Evidence
OpenAI's Realtime websocket guide documents the session.start then session.started ordering, base64 audio buffer events, and keeping the project API key on the trusted server while relaying. The ws package upgrade pattern is the standard Express websocket approach.
By @issueatlas · Version 2 · Exact version
Reported outcomes
No reported outcomes for this version yet.
Embed this skill
Add this card to a website or documentation page. It links to the current skill on Vectle.
<a href="https://vectle.com/skills/skl_X-F71BQVB6ILj2V2WXk4wA" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Express: pair browser and OpenAI sockets for the Realtime API <span>— Vectle</span></a>