> This page is for Voice APIs.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://dev.hume.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://dev.hume.ai/_mcp/server.

# EVI TypeScript Quickstart

In this guide, you’ll learn how to integrate EVI into your TypeScript applications using Hume’s TypeScript SDK.

1. [**Installation**](#installation): Install the [hume](https://www.npmjs.com/package/hume) package.
2. [**Authentication**](#authentication): Instantiate the Hume client using your API credentials.
3. [**Connection**](#connection): Initialize a WebSocket connection to interact with EVI.
4. [**Audio capture**](#audio-capture): Capture and stream audio input.
5. [**Audio playback**](#audio-playback): Play back EVI's streamed audio output.
6. [**Interruption**](#interruption): Handle user interruptions client-side.

#### [Looking for sample code?](https://github.com/HumeAI/hume-api-examples/tree/main/evi/evi-typescript-quickstart)

See the complete implementation of this guide on GitHub

#### [TypeScript SDK](https://github.com/HumeAI/hume-typescript-sdk)

Explore or contribute to Hume's TypeScript SDK on GitHub

> **Tip**
>
> **This guide primarily targets web browser implementations**. For non-browser environments (e.g., Node.js), audio
> capture and playback implementation will vary based on your runtime context.

## Installation \[#installation]

Install the [Hume TypeScript SDK package](https://www.npmjs.com/package/hume).

#### pnpm

```sh
pnpm i hume
```

#### npm

```sh
npm i hume
```

#### yarn

```sh
yarn add hume
```

#### bun

```sh
bun add hume
```

## Authentication \[#authentication]

**Instantiate the Hume client with your API credentials** to authenticate. Visit our [Getting your API keys page](/docs/introduction/api-key) for details on how to obtain your credentials.

> **Warning**
>
> This example uses direct [API key authentication](/docs/introduction/api-key#api-key-authentication) for
> simplicity. For production browser environments, implement the [Token authentication](/docs/introduction/api-key#token-authentication) strategy instead to prevent exposing your API
> key to the client.
>
> **Load API keys from environment variables.** Avoid hardcoding them in your code to prevent credential leaks and
> unauthorized access.

#### Initialize Hume client with credentials

```typescript maxLines=0
import { Hume, HumeClient } from 'hume';

const client = new HumeClient({
  apiKey: HUME_API_KEY, // Load from environment variables
});
```

## Connection \[#connection]

With the Hume client instantiated, **establish an authenticated WebSocket connection using the client's `empathicVoice.chat.connect`
method**, and assign WebSocket event handlers.

#### Establish a connection with EVI

```typescript maxLines=0
import type { SubscribeEvent } from "hume/api/resources/empathicVoice/resources/chat";
import type { CloseEvent } from "hume/core/websocket/events";

const socket = await client.empathicVoice.chat.connect({
  configId: HUME_CONFIG_ID, // optional
});

// Placeholder event handlers to be updated in later steps
function handleOpen() {}
function handleMessage(msg: SubscribeEvent) {}
function handleError(err: Event | Error) {}
function handleClose(e: CloseEvent) {}

socket.on('open', handleOpen);
socket.on('message', handleMessage);
socket.on('error', handleError);
socket.on('close', handleClose);
```

## Audio capture \[#audio-capture]

**Capture audio input from the user's microphone and stream it to EVI** over the WebSocket:

1. Request microphone access from the user.
2. Obtain the audio stream using the [MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream) API.
3. Record audio chunks using the [MediaRecorder](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder) API.
4. Encode each audio chunk in base64.
5. Stream encoded audio to EVI by sending [audio_input](/reference/speech-to-speech-evi/chat#send.AudioInput)
   messages to Hume over WebSocket using the SDK’s `sendAudioInput` method.

#### Audio capture logic

```typescript maxLines=0
import {
  convertBlobToBase64,
  ensureSingleValidAudioTrack,
  getAudioStream,
  getBrowserSupportedMimeType,
} from 'hume';

let recorder: MediaRecorder | null = null;

async function startAudioCapture(
  socket: ChatSocket,
  timeSliceMs = 80
): Promise<MediaRecorder> {
  const mimeTypeResult = getBrowserSupportedMimeType();
  const mimeType = mimeTypeResult.success
    ? mimeTypeResult.mimeType
    : MimeType.WEBM;

  const micAudioStream = await getAudioStream();
  ensureSingleValidAudioTrack(micAudioStream);

  const recorder = new MediaRecorder(micAudioStream, { mimeType });
  recorder.ondataavailable = async (e: BlobEvent) => {
    if (e.data.size > 0 && socket.readyState === WebSocket.OPEN) {
      const data = await convertBlobToBase64(e.data);
      socket.sendAudioInput({ data });
    }
  };
  recorder.onerror = (e) => console.error("MediaRecorder error:", e);
  recorder.start(timeSliceMs);

  return recorder;
}
```

> **Info**
>
> Accepted audio formats include: `mp3`, `wav`, `aac`, `ogg`, `flac`, `webm`, `avr`, `cdda`,
> `cvs/vms`, `aiff`, `au`, `amr`, `mp2`, `mp4`, `ac3`, `avi`, `wmv`, `mpeg`, `ircam`.

Invoke the `startAudioCapture` function within `handleOpen` to start streaming audio once a
connection is established:

#### Start audio capture on open

```typescript maxLines=0
async function handleOpen() {
  console.log("Socket opened");
  recorder = await startAudioCapture(socket!);
}
```

Update your `handleClose` function to ensure audio capture stops appropriately on disconnect:

#### Stop audio capture on close

```typescript maxLines=0
function handleClose(e: CloseEvent) {
  console.log("Socket closed:", e);
  recorder?.stream.getTracks().forEach((t) => t.stop());
  recorder = null;
}
```

## Audio playback \[#audio-playback]

**Handle playback of audio responses from EVI using the Hume TypeScript SDK's
[EVIWebAudioPlayer](https://github.com/HumeAI/hume-typescript-sdk/blob/main/src/wrapper/EVIWebAudioPlayer.ts)**.

1. Initialize the audio player when the WebSocket connection opens.
2. Queue audio responses received from EVI for playback.
3. Dispose of the audio player when the WebSocket connection closes to release resources.

After starting audio capture, initialize the player within `handleOpen`.

#### Initialize player on open

```typescript maxLines=0
import { EVIWebAudioPlayer } from "hume";

let player = new EVIWebAudioPlayer();

async function handleOpen() {
  console.log("Socket opened");
  recorder = await startAudioCapture(socket!);
  await player.init();
}
```

Update `handleMessage` to enqueue received audio responses for playback:

#### Enqueue EVI response audio for playback

```typescript maxLines=0
import type { SubscribeEvent } from "hume/api/resources/empathicVoice/resources/chat";

// Define a WebSocket message event handler to play audio output
async function handleMessage(msg: SubscribeEvent) {
  switch (msg.type) {
    case 'audio_output':
      await player.enqueue(msg);
      break;
  }
}
```

Update `handleClose` to dispose of the audio player when the WebSocket disconnects:

#### Dispose player on close

```typescript maxLines=0
function handleClose(e: CloseEvent) {
  console.log("Socket closed:", e);
  recorder?.stream.getTracks().forEach((t) => t.stop());
  recorder = null;
  player?.dispose();
}
```

## Interruption \[#interruption]

When an interruption is detected, EVI will immediately stop sending further response messages and wait for the
user's new input.

The client must then explicitly handle the interruption by stopping ongoing audio playback.

To stop audio playback on user interruption, **update `handleMessage` to invoke `EVIWebAudioPlayer.stop` when you
receive a [user_interruption](/reference/speech-to-speech-evi/chat#receive.UserInterruption)
message**:

#### Stop playback on interruption

```typescript maxLines=0
function handleMessage(msg: SubscribeEvent) {
  switch (message.type) {
    case 'audio_output':
      await player.enqueue(msg);
      break;
    case 'user_interruption':
      player.stop();
      break;
  }
}
```

## Next steps

**Congratulations!** You’ve successfully implemented a real-time conversational application using Hume’s Empathic Voice
Interface (EVI). In this quickstart, you've learned the core aspects of authentication, WebSocket communication, audio
streaming, playback handling, and interruption management.

Next, consider exploring these areas to enhance your EVI application:

#### [Configure EVI](/docs/speech-to-speech-evi/configuration/build-a-configuration)

See detailed instructions on how you can customize EVI for your application needs.

#### [Chat History](/docs/speech-to-speech-evi/features/chat-history)

Learn how you can access and manage conversation transcripts and expression measures.

> **Info**
>
> For further details and practical examples, explore the [API Reference](/reference/speech-to-speech-evi/chat) and our [Hume API Examples](https://github.com/HumeAI/hume-api-examples/tree/main/evi) on GitHub.

---