OpenAI Realtime API Voice 9 min read

OpenAI Realtime API Guide 2025: Low-Latency Voice & Audio

The OpenAI Realtime API is a WebSocket-based interface for building real-time voice applications powered by GPT-4o. Instead of a fragile TTS+STT pipeline, a single natively multimodal model handles audio input and output with sub-300ms latency — enabling natural interruption, emotion-aware responses, and function calling mid-conversation.

What Is the OpenAI Realtime API?

Traditional voice AI pipelines chain three separate models: a speech-to-text model (like Whisper) transcribes audio to text, an LLM generates a text response, and a TTS model converts that text back to speech. Each hop adds latency and loses information — the LLM never hears your tone, and the TTS voice sounds robotic.

The Realtime API eliminates the middlemen. GPT-4o natively processes audio in and audio out over a persistent WebSocket connection. It hears your actual voice, preserves emotional context, responds with a natural-sounding voice, and can be interrupted mid-sentence — all with end-to-end latency in the 300–500ms range.

Key capabilities:

  • Bidirectional audio streaming — send audio chunks as PCM16 or base64, receive audio delta events in real time
  • Server-side VAD — automatic voice activity detection; the server triggers responses when the user stops speaking
  • Natural interruption handling — the model stops mid-response when the user speaks over it
  • Function calling — tools work during voice conversations, enabling live data lookups
  • Text + audio input/output — mix text and audio in the same session

Models & Pricing

Two models are available for the Realtime API, both accessed via the wss://api.openai.com/v1/realtime endpoint:

Model Audio input (per 1M tokens) Audio output (per 1M tokens) Best for
gpt-4o-realtime-preview $100 $200 Production voice assistants, high quality
gpt-4o-mini-realtime-preview $10 $20 Cost-sensitive apps, prototyping

Audio tokens are measured by the audio duration: roughly 1,500 tokens per minute of audio input. A typical 5-minute voice conversation uses ~7,500 audio input tokens and ~10,000 audio output tokens.

WebSocket Connection

Connect to the Realtime API via a WebSocket with the model as a query parameter and your API key in the Authorization header. Once connected, send and receive JSON events over the socket.

Raw WebSocket connection

import websocket
import json
import os

url = "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview"

headers = [
    f"Authorization: Bearer {os.environ['OPENAI_API_KEY']}",
    "OpenAI-Beta: realtime=v1",
]

ws = websocket.WebSocketApp(
    url,
    header=headers,
    on_open=on_open,
    on_message=on_message,
    on_error=on_error,
    on_close=on_close,
)
ws.run_forever()

After the connection opens, the server sends a session.created event. You can then configure the session, send audio, and receive responses.

Python Quickstart with the OpenAI SDK

The official OpenAI Python SDK (v1.50+) provides a high-level RealtimeConnection context manager that handles the WebSocket lifecycle, event routing, and audio chunking for you:

pip install openai

pip install "openai>=1.50.0"

realtime_quickstart.py

import asyncio
from openai import AsyncOpenAI

client = AsyncOpenAI()

async def main():
    async with client.beta.realtime.connect(
        model="gpt-4o-realtime-preview"
    ) as conn:
        # Configure the session
        await conn.session.update(session={
            "voice": "alloy",
            "instructions": "You are a helpful assistant. Respond concisely.",
            "turn_detection": {"type": "server_vad"},
        })

        # Send a text message (audio works the same way)
        await conn.conversation.item.create(item={
            "type": "message",
            "role": "user",
            "content": [{"type": "input_text", "text": "Say hello!"}],
        })
        await conn.response.create()

        # Stream the response events
        async for event in conn:
            if event.type == "response.audio.delta":
                # event.delta is base64-encoded PCM16 audio
                audio_bytes = event.delta
                # write to speaker or buffer here
                print(f"Audio chunk received: {len(audio_bytes)} bytes")
            elif event.type == "response.done":
                print("Response complete")
                break

asyncio.run(main())

JavaScript / Browser Quickstart

In the browser, use a native WebSocket combined with the MediaRecorder API to capture microphone input and stream it to the Realtime API. Note: for browser clients, use an ephemeral session token from your backend rather than exposing your API key.

Browser WebSocket + MediaRecorder pattern

// 1. Fetch ephemeral token from your backend
const tokenRes = await fetch("/api/realtime-token");
const { client_secret } = await tokenRes.json();

// 2. Connect via WebSocket using the ephemeral token
const ws = new WebSocket(
  "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview",
  ["realtime", `openai-insecure-api-key.${client_secret.value}`]
);

ws.onopen = () => {
  // Configure session
  ws.send(JSON.stringify({
    type: "session.update",
    session: {
      voice: "shimmer",
      instructions: "You are a helpful assistant.",
      turn_detection: { type: "server_vad" },
    }
  }));
};

// 3. Capture microphone audio with MediaRecorder
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const recorder = new MediaRecorder(stream, { mimeType: "audio/webm" });

recorder.ondataavailable = async (e) => {
  const buffer = await e.data.arrayBuffer();
  const base64 = btoa(String.fromCharCode(...new Uint8Array(buffer)));
  ws.send(JSON.stringify({
    type: "input_audio_buffer.append",
    audio: base64,
  }));
};

recorder.start(100); // send chunks every 100ms

// 4. Handle incoming audio deltas
ws.onmessage = (e) => {
  const event = JSON.parse(e.data);
  if (event.type === "response.audio.delta") {
    // Decode base64 PCM16 and play via AudioContext
    playAudioChunk(event.delta);
  }
};

Always generate ephemeral tokens server-side using POST /v1/realtime/sessions with your API key — never expose your API key in client-side code.

Session Configuration

Send a session.update event to configure voice, instructions, VAD settings, and tools. You can update the session at any time during the conversation.

session.update event — full config

{
  "type": "session.update",
  "session": {
    // Voice options: alloy, echo, shimmer, verse, ash, ballad, coral, sage
    "voice": "alloy",

    // System prompt for the voice model
    "instructions": "You are a friendly customer support agent for Acme Corp.",

    // Input audio format: pcm16, g711_ulaw, g711_alaw
    "input_audio_format": "pcm16",

    // Output audio format: pcm16, g711_ulaw, g711_alaw
    "output_audio_format": "pcm16",

    // server_vad: automatic turn detection
    // null: manual push-to-talk (use input_audio_buffer.commit)
    "turn_detection": {
      "type": "server_vad",
      "threshold": 0.5,        // VAD sensitivity (0.0-1.0)
      "prefix_padding_ms": 300, // audio before speech start to include
      "silence_duration_ms": 500 // silence before triggering response
    },

    // Modalities: ["text", "audio"] or ["text"] for text-only
    "modalities": ["text", "audio"],

    // Temperature for response generation
    "temperature": 0.8,

    // Max output tokens (audio + text combined)
    "max_response_output_tokens": 4096
  }
}

Function Calling in Voice

Tools work in the Realtime API exactly like in Chat Completions — the model decides when to call a function and includes the call in its response stream. Add tools to the session config, then listen for response.function_call_arguments.done events:

Add tools to session

{
  "type": "session.update",
  "session": {
    "tools": [
      {
        "type": "function",
        "name": "get_weather",
        "description": "Get current weather for a city",
        "parameters": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "City name, e.g. San Francisco"
            }
          },
          "required": ["location"]
        }
      }
    ],
    "tool_choice": "auto"
  }
}

Handle function call and return result

ws.onmessage = async (e) => {
  const event = JSON.parse(e.data);

  if (event.type === "response.function_call_arguments.done") {
    const args = JSON.parse(event.arguments);
    const callId = event.call_id;

    // Execute your function
    const result = await getWeather(args.location);

    // Return the result to the model
    ws.send(JSON.stringify({
      type: "conversation.item.create",
      item: {
        type: "function_call_output",
        call_id: callId,
        output: JSON.stringify(result),
      }
    }));

    // Ask the model to continue the conversation
    ws.send(JSON.stringify({ type: "response.create" }));
  }
};

Realtime API vs Traditional TTS + STT Pipeline

Attribute Realtime API Whisper + GPT-4o + TTS
Latency 300–500ms end-to-end 1.5–4s (3 sequential API calls)
Voice quality Natural, context-aware emotion Robotic TTS, no emotion
Interruption handling Built-in (VAD) Manual, complex to implement
Cost Higher per minute Lower, more predictable
Complexity Single WebSocket connection 3 APIs, transcription step, error handling
Best for Real-time voice UX, live agents Transcription pipelines, async processing

Use Cases

  • Voice assistants — build a hands-free assistant with natural back-and-forth conversation, interruption support, and personality via the instructions field
  • Customer service bots — automate inbound calls with function calling to query order status, CRM records, or ticketing systems in real time
  • Real-time transcription + response — transcribe speech while simultaneously generating an AI response; use response.audio_transcript.delta events for live captions
  • Language tutoring — have learners practice conversation with a patient, low-latency AI tutor that corrects pronunciation and grammar on the fly
  • Accessibility tools — voice-controlled interfaces for users who cannot use a keyboard, with function calling to execute actions in your app
  • Live interpretation — pair with translation instructions to create real-time speech-to-speech translation between languages

OpenAI's Realtime API Has Had Notable Outages

OpenAI's Realtime API has had notable outages. Prismix tracks OpenAI's status in real time — get alerted before your voice app breaks.

Monitor OpenAI Status →