# Custom vocabulary

**The problem.** Speech models write what is most likely in general. Your product, your customers' names and your
jargon are rare words: "Gladia" comes out as "Gladya", "Kubernetes" as "Cuban et ease", "Dr Okafor" as "doctor
oak a four". Custom vocabulary tells the model which words to expect, so they come out right the first time.

**Where it works.** Every model: `solaria-3`, `solaria-1`, `trantoria-1`.

> **Use the SDK.** The Gladia SDKs stream the audio, keep it until the API has transcribed it, and reconnect after a network drop
without losing a word. Most integration issues come from hand-written WebSocket clients: start from the SDK
examples below.

## Step by step

### 1. List your words

The option goes in `realtime_processing` of the session's configuration. Both fields are required:

```json
{
  "realtime_processing": {
    "custom_vocabulary": true,
    "custom_vocabulary_config": {
      "vocabulary": ["Gladia", "Kubernetes", "Dr Okafor"]
    }
  }
}
```

### 2. Start a session with it

Each program streams a 16-bit WAV file and prints the final transcripts. Put your API key in the `GLADIA_API_KEY` environment variable, then run `python custom_vocabulary.py meeting.wav`.

**Python SDK**

```python title="custom_vocabulary.py"
# pip install gladiaio-sdk
import os
import sys
import threading
import wave

from gladiaio_sdk import GladiaClient, LiveV2InitRequest

with wave.open(sys.argv[1]) as wav:  # a 16-bit PCM WAV file
    rate, channels = wav.getframerate(), wav.getnchannels()
    audio = wav.readframes(wav.getnframes())

config = {
    "encoding": "wav/pcm",
    "sample_rate": rate,
    "bit_depth": 16,
    "channels": channels,
    "model": "solaria-3",
    "language_config": {"languages": ["en"]},
    "realtime_processing": {
        "custom_vocabulary": True,
        "custom_vocabulary_config": {
            "vocabulary": [
                "Gladia",
                {"value": "Kubernetes", "pronunciations": ["cuban et ease", "kubernetis"]},
                {"value": "Dr Okafor", "intensity": 0.8},
            ],
            "default_intensity": 0.5,
        },
    },
}

client = GladiaClient(
    api_key=os.environ["GLADIA_API_KEY"],
    api_url=os.environ.get("GLADIA_API_URL", "https://eu1.api.gladia.io"),
)
session = client.live_v2().start_session(LiveV2InitRequest.from_dict(config))
ended, errors = threading.Event(), []

@session.on("message")
def on_message(message):
    if message.type == "transcript" and message.data.is_final:
        print(message.data.utterance.text)

session.on("error", errors.append)
session.once("ended", lambda _: ended.set())

step = rate * channels * 2 // 10  # 100 ms of audio per chunk
for start in range(0, len(audio), step):
    session.send_audio(audio[start : start + step])  # live audio: send each chunk as it is captured
session.stop_recording()

ended.wait(timeout=60)
sys.exit(1 if errors or not ended.is_set() else 0)
```

**JavaScript SDK**

```js title="custom_vocabulary.mjs"
// npm install @gladiaio/sdk
import { readFileSync } from "node:fs";
import { GladiaClient } from "@gladiaio/sdk";

const { sampleRate, channels, pcm } = readWav(process.argv[2]); // a 16-bit PCM WAV file

const config = {
  encoding: "wav/pcm",
  sample_rate: sampleRate,
  bit_depth: 16,
  channels,
  model: "solaria-3",
  language_config: { languages: ["en"] },
  realtime_processing: {
    custom_vocabulary: true,
    custom_vocabulary_config: {
      vocabulary: [
        "Gladia",
        { value: "Kubernetes", pronunciations: ["cuban et ease", "kubernetis"] },
        { value: "Dr Okafor", intensity: 0.8 },
      ],
      default_intensity: 0.5,
    },
  },
};

const client = new GladiaClient({
  apiKey: process.env.GLADIA_API_KEY,
  apiUrl: process.env.GLADIA_API_URL ?? "https://eu1.api.gladia.io",
});
const session = client.liveV2().startSession(config);

session.on("message", (message) => {
  if (message.type === "transcript" && message.data.is_final) console.log(message.data.utterance.text);
});
session.on("error", (error) => {
  console.error(error);
  process.exitCode = 1;
});
session.once("ended", () => process.exit());

const step = (sampleRate * channels * 2) / 10; // 100 ms of audio per chunk
for (let start = 0; start < pcm.length; start += step) {
  session.sendAudio(pcm.subarray(start, start + step)); // live audio: send each chunk as it is captured
}
session.stopRecording();

function readWav(path) {
  const file = readFileSync(path);
  let fmt, pcm;
  for (let pos = 12; pos < file.length; ) {
    const id = file.toString("ascii", pos, pos + 4);
    const size = file.readUInt32LE(pos + 4);
    if (id === "fmt ") fmt = { channels: file.readUInt16LE(pos + 10), sampleRate: file.readUInt32LE(pos + 12) };
    if (id === "data") pcm = file.subarray(pos + 8, pos + 8 + size);
    pos += 8 + size + (size % 2);
  }
  return { ...fmt, pcm };
}
```

**HTTP**

Create the session, then stream its audio to the returned `url` ([Live WebSocket](/api-reference/v2/live/websocket/)):

```bash
curl -X POST https://eu1.api.gladia.io/v2/live \
  -H "x-gladia-key: $GLADIA_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "encoding": "wav/pcm",
    "sample_rate": 16000,
    "bit_depth": 16,
    "channels": 1,
    "model": "solaria-3",
    "language_config": { "languages": ["en"] },
    "realtime_processing": {
      "custom_vocabulary": true,
      "custom_vocabulary_config": {
        "vocabulary": [
          "Gladia",
          { "value": "Kubernetes", "pronunciations": ["cuban et ease", "kubernetis"] },
          { "value": "Dr Okafor", "intensity": 0.8 }
        ],
        "default_intensity": 0.5
      }
    }
  }'
```

### 3. Check the result

Nothing new arrives: the words simply come out spelled as you listed them, in partial and final transcripts.

```json
{ "type": "transcript", "data": { "is_final": true, "utterance": { "text": "Dr Okafor deployed Gladia on Kubernetes." } } }
```

## Options

| field | what it does |
|---|---|
| `vocabulary` | The words or phrases: strings, or objects with their own options. |
| `value` | The word or phrase, written exactly as it must appear. |
| `pronunciations` | How it may be heard, written as it sounds. Whatever the model writes for one of them is rewritten to `value`. |
| `intensity` | How strongly the entry is favoured, from 0 to 1 (`trantoria-1` only, see below). |
| `default_intensity` | The intensity of entries that set none. |

## Limits and gotchas

- **Fewer, precise entries work better.** List what is specific to your audio. Hundreds of common words, or a
  whole dictionary, make the model see your words where they were not said.
- **Intensity applies to `trantoria-1` only.** `solaria-3` and `solaria-1` read the list as context: every entry
  counts the same and `intensity` is ignored. On `trantoria-1`, a high intensity replaces similar-sounding words
  with yours: raise it word by word, and only for the words still missed.
- **Size limit.** At most 1,000 entries. The whole session configuration (vocabulary, custom spelling and
  `custom_metadata` together) must also fit in its WebSocket URL: a few hundred average entries. Beyond, `POST
  /v2/live` answers `400` with "the session configuration is too large for its WebSocket URL".
- **Numbers stay as listed.** With [numbers as digits](/features/numerals/), a vocabulary phrase made of number
  words ("Seven Eleven") is kept as you wrote it.
- **Not a spelling rule.** Vocabulary helps the model *hear* a word. To change how a word is *written* (casing, an
  abbreviation), use [custom spelling](/features/custom-spelling/).
- **One list per session.** The vocabulary cannot be changed while the session runs: create a new session.
- **`language` of an entry is not applied**: it is accepted for compatibility with Gladia's cloud API.

## Troubleshooting

| symptom | cause | fix |
|---|---|---|
| `400` "custom_vocabulary_config is required when custom_vocabulary is true" | the flag without the list | send both fields |
| `400` "the session configuration is too large…" | the list, the spelling and the metadata do not fit in the URL | shorten the list, keep the words that are actually missed |
| your word now appears where it was not said | the list is too long or the intensity too high | remove generic entries, lower `intensity` |
| a word is still missed on `solaria-3` | the model hears it differently | add `pronunciations` as it is heard, or fix it with [custom spelling](/features/custom-spelling/) |
