La OpenAI Realtime API conecta clientes por WebSocket o WebRTC. Para conexiones del lado del servidor, puedes llegar a OpenAI directamente desde cualquier máquina con internet. Para conexiones del lado del cliente —que es la mayor parte de lo que querrías construir con esto— el navegador necesita un origen seguro y tu backend debe emitir tokens efímeros. Ambas funcionan a través de un túnel. Hay algunos detalles que conviene saber.
Dos formas de conectar, dos razones para tunelizar
La Realtime API admite conexiones del lado del servidor (tu backend abre un WebSocket hacia OpenAI) y conexiones del lado del cliente (un navegador abre una conexión peer WebRTC o un WebSocket usando un token efímero que tu backend emite). El camino del servidor no necesita túnel. El del cliente casi siempre sí.
Por qué el lado del cliente necesita HTTPS:
- Los permisos de micrófono del navegador requieren un origen seguro.
- El
getUserMediade WebRTC y el manejo de ICE funcionan mejor con HTTPS. - Los service workers (si tienes alguno) lo necesitan.
- Si llamas al endpoint
/sessionde tu backend para obtener un token efímero, ese backend también tiene que ser HTTPS si tu frontend lo es.
Puedes saltarte el primero con flags del navegador. No lo hagas. Usa un túnel y vive en el mundo real.
La forma de una app Realtime en desarrollo
Una app realtime mínima tiene tres partes:
- Un frontend que captura la entrada de micrófono y reproduce la salida de audio.
- Una ruta de backend que emite un token efímero llamando al endpoint
/v1/realtime/sessionsde OpenAI con tu API key real. - Una conexión WebRTC o WebSocket directa del navegador a OpenAI, usando el token efímero.
Tu túnel expone el frontend + backend (la misma dominio en la mayoría de configuraciones). El tráfico realtime real va del navegador a OpenAI, no a través de tu túnel: esa conexión es directa por HTTPS/WSS.
Configuración rápida con PortPreview
- Inicia tu servidor de desarrollo (Next.js, Vite, lo que sea) en el puerto 3000 o 5173.
- Ejecuta
npx portpreview 3000. - Abre la URL HTTPS en un navegador. Los avisos de permiso de micrófono funcionan con normalidad.
- Llama a tu endpoint emisor de tokens, obtén un token efímero, abre la conexión realtime.
- Habla, recibe una respuesta en streaming.
Si usas Vite, necesitarás la config de allowedHosts y HMR de Vite + túnel. Si estás en Next.js con edge runtime en algún sitio, cuidado con la config de runtime en rutas que necesitan crypto de Node.
Upgrades de WebSocket a través de túneles
Las conexiones realtime son WebSocket (o WebRTC, que en su mayoría evita el túnel). Cualquier túnel que uses debe reenviar correctamente la petición HTTP Upgrade. La mayoría lo hace: PortPreview, los quick tunnels de Cloudflare y ngrok manejan los upgrades de WebSocket. Si el tuyo no, la conexión falla en silencio en el navegador con un genérico WebSocket closed before connected y sin detalle útil.
Prueba el upgrade con wscat si no estás seguro. Conéctate a wss://your-tunnel.portpreview.dev/anything y observa el handshake.
Los trucos de desarrollo que ayudan
Inspeccionar la petición de emisión de token
Tu frontend llama a una ruta de backend que llama a OpenAI. El bug de desarrollo más común aquí es una petición mal configurada a /v1/realtime/sessions: nombre de modelo equivocado, voz equivocada, modalities equivocadas. Tu túnel captura la petición del frontend al backend, pero no el salto del backend a OpenAI. Registra esa petición en el servidor, o haz proxy a través de tu túnel ejecutando ambas capas en local.
Desajustes de formato de audio
La Realtime API usa PCM16 por defecto con una sample rate configurable. Si metes audio de otro formato, el modelo lo rechazará o alucinará. El MediaRecorder del navegador suele darte Opus o WebM: tendrás que manejar la conversión o usar el camino WebRTC que lo hace por ti.
Expiración de token en sesiones largas
Los tokens efímeros son de corta duración. Si pruebas una sesión más larga que el TTL del token, renueva según un calendario. El SDK de Realtime tiene ayudantes para esto; hacerlo a mano significa vigilar el evento session.expired y emitir un token nuevo antes de que muera el viejo.
Cómo se ve esto en producción
El único cambio real de desarrollo a producción es la URL: reemplaza el hostname del túnel por tu dominio real. El endpoint emisor de tokens se queda en tu backend. La conexión WebRTC/WebSocket del navegador a OpenAI es el mismo camino de código. Hemos visto equipos darle demasiadas vueltas e intentar hacer proxy del tráfico realtime por su backend: no lo hagas, añade latencia y rompe el modelo que asume el SDK de OpenAI.
Para la oferta paralela de Anthropic (que se parece más a un bucle de tool use que a un WebSocket en streaming), mira Anthropic tool use y webhooks en local. Únete a la lista de espera de PortPreview para un túnel que maneja los upgrades de WebSocket por defecto.