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

# Text-to-speech WebSocket examples

> Stream speech with the SLNG TTS WebSocket API. Python and Node.js code samples for sub-100ms latency, mid-sentence interrupt, and continuous text input.

You need a working knowledge of the [WebSocket protocol](/websockets). These examples use the Deepgram Aura model; swap the endpoint path to use a different provider.

WebSockets let you stream audio with sub-100ms latency and stop mid-sentence, which is what you need for voice agent conversations. If you only need to generate audio files, [HTTP is simpler](/examples/tts-http).

## Placeholders

The snippets below use these placeholders. Replace them before running the code.

| Placeholder    | Replace with                                                                                                                              |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `SLNG_API_KEY` | An SLNG key from [app.slng.ai/api-keys](https://app.slng.ai/api-keys). The snippets read it from the `SLNG_API_KEY` environment variable. |

## Message Flow

Every TTS WebSocket session follows this pattern:

```mermaid theme={null}
sequenceDiagram
    participant Client
    participant SLNG
    Client->>SLNG: Connect wss://api.slng.ai/v1/tts/slng/deepgram/aura:2-en
    SLNG-->>Client: Connection open
    Client->>SLNG: { type: "init", model, voice, config }
    SLNG-->>Client: { type: "ready", session_id: "..." }
    Client->>SLNG: { type: "text", text: "Hello!" }
    SLNG-->>Client: audio chunk
    SLNG-->>Client: audio chunk
    Client->>SLNG: { type: "flush" }
    SLNG-->>Client: audio chunk
    SLNG-->>Client: { type: "flushed" }
    Client->>SLNG: { type: "close" }
```

For the full list of message types and parameters, see the [WebSocket protocol reference](/websockets). To keep acronyms, names, and domain terms consistent during synthesis, set a session default or per-turn [pronunciation dictionary](/pronunciation-dictionaries).

***

## Quick Start

Connect, initialize a session, send text, and save the audio to a file.

Both examples write a `output.pcm` file containing raw 16-bit PCM audio at 24 kHz. You can play it with [ffplay](https://ffmpeg.org/ffplay.html):

```bash theme={null}
ffplay -f s16le -ar 24000 -ac 1 output.pcm
```

<CodeGroup>
  ```javascript JavaScript theme={null}
  // npm install ws
  const WebSocket = require("ws");
  const fs = require("fs");

  const API_KEY = process.env.SLNG_API_KEY;
  const ws = new WebSocket("wss://api.slng.ai/v1/tts/slng/deepgram/aura:2-en", {
    headers: { Authorization: `Bearer ${API_KEY}` },
  });

  const audioChunks = [];

  ws.on("open", () => {
    // 1. Initialize session
    ws.send(
      JSON.stringify({
        type: "init",
        model: "aura:2-en",
        voice: "aura-2-thalia-en",
        config: {
          encoding: "linear16",
          sample_rate: 24000,
        },
      }),
    );

    // 2. Send text to convert
    ws.send(
      JSON.stringify({
        type: "text",
        text: "Hello! This is a WebSocket TTS example.",
      }),
    );

    // 3. Flush to get remaining audio
    ws.send(JSON.stringify({ type: "flush" }));
  });

  ws.on("message", (data, isBinary) => {
    if (isBinary) {
      audioChunks.push(data);
    } else {
      const message = JSON.parse(data.toString());
      if (message.type === "ready") {
        console.log("Session ready:", message.session_id);
      } else if (message.type === "flushed") {
        console.log("All audio received, saving to output.pcm");
        fs.writeFileSync("output.pcm", Buffer.concat(audioChunks));
        ws.close();
      } else if (message.type === "error") {
        console.error("Error:", message.message);
        ws.close();
      }
    }
  });
  ```

  ```python Python theme={null}
  # pip install websockets
  import asyncio
  import json
  import os
  import websockets

  async def tts_quickstart():
      api_key = os.environ["SLNG_API_KEY"]
      uri = "wss://api.slng.ai/v1/tts/slng/deepgram/aura:2-en"
      headers = {"Authorization": f"Bearer {api_key}"}

      async with websockets.connect(uri, extra_headers=headers) as ws:
          # 1. Initialize session
          await ws.send(json.dumps({
              "type": "init",
              "model": "aura:2-en",
              "voice": "aura-2-thalia-en",
              "config": {
                  "encoding": "linear16",
                  "sample_rate": 24000,
              },
          }))

          # 2. Send text to convert
          await ws.send(json.dumps({
              "type": "text",
              "text": "Hello! This is a WebSocket TTS example.",
          }))

          # 3. Flush to get remaining audio
          await ws.send(json.dumps({"type": "flush"}))

          # 4. Receive audio chunks until flushed
          audio_chunks = []
          async for message in ws:
              if isinstance(message, bytes):
                  audio_chunks.append(message)
              else:
                  data = json.loads(message)
                  if data["type"] == "ready":
                      print(f"Session ready: {data['session_id']}")
                  elif data["type"] == "flushed":
                      print("All audio received, saving to output.pcm")
                      break
                  elif data["type"] == "error":
                      print(f"Error: {data['message']}")
                      break

          with open("output.pcm", "wb") as f:
              for chunk in audio_chunks:
                  f.write(chunk)

  asyncio.run(tts_quickstart())
  ```
</CodeGroup>

***

## More Examples

### Batch Text Streaming

Send multiple sentences for smoother speech instead of one large block. This is a complete example you can run independently.

<CodeGroup>
  ```javascript JavaScript theme={null}
  // npm install ws
  const WebSocket = require("ws");
  const fs = require("fs");

  const API_KEY = process.env.SLNG_API_KEY;
  const ws = new WebSocket("wss://api.slng.ai/v1/tts/slng/deepgram/aura:2-en", {
    headers: { Authorization: `Bearer ${API_KEY}` },
  });

  const text =
    "The sun rose over the mountains. Birds began to sing in the trees. A gentle breeze carried the scent of wildflowers across the valley.";
  const audioChunks = [];

  ws.on("open", () => {
    ws.send(
      JSON.stringify({
        type: "init",
        model: "aura:2-en",
        voice: "aura-2-thalia-en",
        config: { encoding: "linear16", sample_rate: 24000 },
      }),
    );

    // Stream sentences one at a time
    const sentences = text.split(". ");
    for (const sentence of sentences) {
      ws.send(
        JSON.stringify({
          type: "text",
          text: sentence.endsWith(".") ? sentence : sentence + ".",
        }),
      );
    }

    ws.send(JSON.stringify({ type: "flush" }));
  });

  ws.on("message", (data, isBinary) => {
    if (isBinary) {
      audioChunks.push(data);
    } else {
      const message = JSON.parse(data.toString());
      if (message.type === "flushed") {
        console.log("All audio received, saving to output.pcm");
        fs.writeFileSync("output.pcm", Buffer.concat(audioChunks));
        ws.close();
      }
    }
  });
  ```

  ```python Python theme={null}
  # pip install websockets
  import asyncio
  import json
  import os
  import websockets

  async def tts_batch_streaming():
      api_key = os.environ["SLNG_API_KEY"]
      uri = "wss://api.slng.ai/v1/tts/slng/deepgram/aura:2-en"
      headers = {"Authorization": f"Bearer {api_key}"}

      text = (
          "The sun rose over the mountains. "
          "Birds began to sing in the trees. "
          "A gentle breeze carried the scent of wildflowers across the valley."
      )

      async with websockets.connect(uri, extra_headers=headers) as ws:
          await ws.send(json.dumps({
              "type": "init",
              "model": "aura:2-en",
              "voice": "aura-2-thalia-en",
              "config": {"encoding": "linear16", "sample_rate": 24000},
          }))

          # Stream sentences one at a time
          sentences = text.split(". ")
          for sentence in sentences:
              if not sentence.endswith("."):
                  sentence += "."
              await ws.send(json.dumps({
                  "type": "text",
                  "text": sentence,
              }))

          await ws.send(json.dumps({"type": "flush"}))

          # Receive audio chunks until flushed
          audio_chunks = []
          async for message in ws:
              if isinstance(message, bytes):
                  audio_chunks.append(message)
              else:
                  data = json.loads(message)
                  if data["type"] == "flushed":
                      print("All audio received, saving to output.pcm")
                      break

          with open("output.pcm", "wb") as f:
              for chunk in audio_chunks:
                  f.write(chunk)

  asyncio.run(tts_batch_streaming())
  ```
</CodeGroup>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Live TTS demo" icon="play" href="https://examples-gbcy.onrender.com">
    Try real-time TTS in your browser, no setup needed
  </Card>

  <Card title="WebSocket protocol" icon="plug" href="/websockets">
    Full message types, parameters, and error codes
  </Card>

  <Card title="Pronunciation dictionaries" icon="book-open-text" href="/pronunciation-dictionaries">
    Reuse pronunciation rules across TTS requests
  </Card>

  <Card title="TTS HTTP examples" icon="file-audio" href="/examples/tts-http">
    Simpler integration for non-streaming use cases
  </Card>

  <Card title="TTS API reference" icon="audio-lines" href="/api-reference/tts/deepgram-aura-2/aura-2-english-ws">
    Endpoint-specific parameters
  </Card>
</CardGroup>
