> ## Documentation Index
> Fetch the complete documentation index at: https://docs.modellix.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Gemini 3.5 Transcribe Live

> Stream PCM audio to google/gemini-3.5-transcribe-live over WebSocket and receive interim and final text transcripts.

Gemini 3.5 Transcribe Live converts streaming speech into text. Use it for live captions and dictation. For file transcription over HTTP, see the separate [Gemini 3.5 Transcribe API](https://docs.modellix.ai/google/gemini-3-5-transcribe.md).

> **WSS**
>
> `wss://api.modellix.ai/api/v1/live/google/gemini-3.5-transcribe-live`

| Item | Value |
| - | - |
| Model ID | `google/gemini-3.5-transcribe-live` |
| Input | Raw 16-bit, little-endian, mono PCM audio at 16 kHz |
| Output | Interim and final text transcripts |
| Response Modality | `TEXT` |
| Session Limit | Up to 10 minutes |
| Auth | `Authorization: Bearer <Modellix API Key>` on the handshake |

For shared authentication, handshake errors, and close codes, see the [Live Overview](https://docs.modellix.ai/live/overview.md).

## Quick Start

Prepare short mono, 16-bit PCM WAV files at 16 kHz and set `MODELLIX_API_KEY`. Save the following code as `transcribe_live.py` and run `python transcribe_live.py first.wav second.wav`. Each file is sent as a separate utterance on the same connection, using manual endpointing.

```python Python theme={null}
# pip install "websockets>=14"
import asyncio
import base64
import json
import os
import sys
import wave

import websockets

URL = "wss://api.modellix.ai/api/v1/live/google/gemini-3.5-transcribe-live"


async def send_audio(ws, path):
    with wave.open(path, "rb") as audio:
        if (audio.getnchannels(), audio.getsampwidth(), audio.getframerate()) != (1, 2, 16000):
            raise ValueError("Use mono, 16-bit PCM WAV audio at 16 kHz")
        await ws.send(json.dumps({"realtimeInput": {"activityStart": {}}}))
        while chunk := audio.readframes(1600):
            await ws.send(json.dumps({
                "realtimeInput": {
                    "audio": {
                        "mimeType": "audio/pcm;rate=16000",
                        "data": base64.b64encode(chunk).decode("ascii"),
                    }
                }
            }))
            await asyncio.sleep(len(chunk) / 32000)
        await ws.send(json.dumps({"realtimeInput": {"activityEnd": {}}}))


async def receive_utterance(ws):
    async for raw in ws:
        message = json.loads(raw)
        if message.get("error"):
            raise RuntimeError(message["error"])
        content = message.get("serverContent") or {}
        if content.get("interimInputTranscription"):
            print("Interim:", content["interimInputTranscription"]["text"])
        if content.get("inputTranscription"):
            print("Final:", content["inputTranscription"]["text"])
        if message.get("usageMetadata"):
            print("Usage:", message["usageMetadata"])
        if content.get("generationComplete"):
            return
    raise RuntimeError("Connection ended before utterance completion")


async def main():
    headers = {"Authorization": f"Bearer {os.environ['MODELLIX_API_KEY']}"}
    async with websockets.connect(URL, additional_headers=headers) as ws:
        await ws.send(json.dumps({
            "setup": {
                "generationConfig": {"responseModalities": ["TEXT"]},
                "inputAudioTranscription": {"languageCodes": []},
                "realtimeInputConfig": {
                    "automaticActivityDetection": {"disabled": True}
                },
            }
        }))
        reply = json.loads(await ws.recv())
        if "setupComplete" not in reply:
            raise RuntimeError(reply)
        for path in sys.argv[1:]:
            await asyncio.wait_for(
                asyncio.gather(send_audio(ws, path), receive_utterance(ws)),
                timeout=600,
            )


if len(sys.argv) < 2:
    raise SystemExit("Usage: python transcribe_live.py first.wav [second.wav]")

asyncio.run(main())
```

## Client Messages

### Setup

Send `setup` as the first message, then wait for `setupComplete`. The following fields belong inside `setup`.

**model** `string`

Optional. The URL selects the model, and Modellix replaces this field with the upstream model resource.

**generationConfig.responseModalities** `string[]` *required*

Set to `["TEXT"]` for this model.

**inputAudioTranscription** `object` *required*

Enables transcription. Use `{}` for automatic language detection and the default transcription mode, or configure the fields below.

**inputAudioTranscription.languageCodes** `string[]`

BCP-47 language hints, such as `["cmn-Hans-CN", "en-US"]`. Omit or use `[]` to detect languages automatically, including mixed-language speech.

**inputAudioTranscription.customVocabulary** `string[]`

Optional terms or phrases to help recognize names and specialist vocabulary. Supply up to 1,000 entries; Google recommends keeping the list to about 100 relevant entries for best results.

**inputAudioTranscription.mode** `string` (default: VERBATIM)

Allowed values: `VERBATIM`, `SMART`. `VERBATIM` preserves spoken words and fillers. `SMART` is experimental and cleans up disfluencies, corrections, and formatting. For `SMART`, use manual endpointing as in the quick start so natural pauses do not split a thought.

**realtimeInputConfig.automaticActivityDetection.disabled** `boolean` (default: false)

Allowed values: `true`, `false`. Set to `true` for manual endpointing with `activityStart` and `activityEnd`. Leave automatic voice activity detection (VAD) enabled to let the model detect speech boundaries.

### Realtime Input

After `setupComplete`, send audio and activity signals inside `realtimeInput`.

**audio** `object`

Audio chunk containing both fields below. Send chunks of about 100 ms at the audio's playback rate.

**Properties**

**mimeType** `string` *required*

Use `audio/pcm;rate=16000` for 16 kHz input.

**data** `string` *required*

Base64-encoded raw 16-bit, little-endian, mono PCM samples. Do not include a WAV header.

**activityStart** `object`

Send `{}` before an utterance when automatic VAD is disabled.

**activityEnd** `object`

Send `{}` after that utterance's audio when automatic VAD is disabled, then wait for `generationComplete` before starting the next utterance in the example.

**audioStreamEnd** `boolean`

With automatic VAD enabled, send `true` when the audio stream ends to flush buffered audio. Omit this signal during the manual endpointing flow above.

## Server Messages

Server messages are forwarded unchanged. A message may contain transcription content and `usageMetadata` together.

**setupComplete** `object`

The setup was accepted. You can now send audio.

**serverContent.interimInputTranscription.text** `string`

A provisional transcript that may change. Replace the current interim preview rather than appending every update.

**serverContent.inputTranscription.text** `string`

The finalized transcript for an utterance. Append it to your transcript and clear the interim preview.

**usageMetadata** `object`

Token counts for the utterance. Audio input is reported in `promptTokensDetails` with modality `AUDIO`; text output is reported in `candidatesTokensDetails` with modality `TEXT`. Use the latest report for each utterance. Do not sum multiple reports for the same utterance or treat them as session-wide totals.

**serverContent.generationComplete** `boolean`

`true` marks the utterance's completion. This model's settlement boundary is `generationComplete`; Gemini 3.8 Live continues to use `turnComplete`.

**voiceActivity** `object`

Speech activity metadata. A standalone activity notification does not start another billable utterance.

## Billing

Each completed utterance produces a request record. Charges use the upstream audio input and text output tokens; final transcript tokens are text output even though the transcript is returned under `inputTranscription`. Interim previews are not billed as additional text.

If the connection ends before `generationComplete`, Modellix settles any usage already received for the incomplete utterance. No usage means no token charge. You can inspect usage and the charged amount in the console's Live request records.

## Sessions and Limits

* Sessions support up to 10 minutes of continuous audio. The gateway's longer connection limit does not extend the model limit.
* Input is audio only; output is text only.
* Speaker diarization and word-level timestamps are not supported in Live transcription.

See the [Google Cloud model documentation](https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/gemini/3-5-transcribe) for supported languages and model capabilities.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.