> 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 Next.js Quickstart

With Hume’s [React SDK](https://www.npmjs.com/package/@humeai/voice-react), WebSocket connection management is handled
for you and the complexities of audio capture, playback, and streaming are abstracted away. You can integrate EVI into
your React app with just a few hooks and components, without writing any low-level WebSocket or audio code.

In this guide, you’ll learn how to integrate EVI into your Next.js applications using Hume’s React SDK, with
step-by-step instructions for both the **App Router** and the **Pages Router**.

#### [EVI Next.js Starter](https://vercel.com/templates/next.js/empathic-voice-interface-starter)

Kickstart your project with our pre-configured Vercel template

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

See the complete implementation of this guide on GitHub

#### [React SDK](https://github.com/HumeAI/empathic-voice-api-js/tree/main/packages/react)

Explore or contribute to Hume's React SDK on GitHub

**This guide is broken up into five sections:**

1. [**Installation**](#installation): Install Hume SDK packages.
2. [**Authentication**](#authenticate): Generate and use an access token to authenticate with EVI.
3. [**Context provider**](#context-provider): Set up the `<VoiceProvider/>`.
4. [**Connection**](#connection): Open a WebSocket connection and start a chat with EVI.
5. [**Display chat**](#display-chat): Display chat messages in the UI.

> **Info**
>
> Before you begin, you'll need an existing [Next.js project](https://nextjs.org/docs/getting-started/installation).

## Installation \[#installation]

Install Hume's [React SDK](https://www.npmjs.com/package/@humeai/voice-react) and [TypeScript SDK](https://www.npmjs.com/package/hume) packages.

#### pnpm

```sh
pnpm i @humeai/voice-react hume
```

#### npm

```sh
npm i @humeai/voice-react hume
```

#### yarn

```sh
yarn add @humeai/voice-react hume 
```

#### bun

```sh
bun add @humeai/voice-react hume
```

## Authentication \[#authenticate]

Generate an access token for authentication. Doing so will require your **API key** and **Secret key**. These keys can
be obtained by logging into the portal and visiting the [API keys page](https://app.hume.ai/keys).

> **Warning**
>
> **Load your API key and secret from environment variables.** Avoid hardcoding them in your code to prevent
> credential leaks and unauthorized access.

#### App Router

In your root component, use the TypeScript SDK's `fetchAccessToken` method to fetch your access token.

#### ./app/page.tsx

```tsx maxLines=0
import dynamic from "next/dynamic";
import { fetchAccessToken } from "hume";

const Chat = dynamic(() => import("@/components/Chat"), {
  ssr: false,
});

export default async function Page() {
  const accessToken = await fetchAccessToken({
    apiKey: String(process.env.HUME_API_KEY),
    secretKey: String(process.env.HUME_SECRET_KEY),
  });

  return (
    <div className={"grow flex flex-col"}>
      <Chat accessToken={accessToken} />
    </div>
  );
}
```

#### Pages Router

In `index.tsx` define a function called `getServerSideProps` within `index.tsx` for fetching your access token.

#### ./pages/index.tsx

```tsx maxLines=0
import StartCall from "@/components/StartCall";
import Messages from "@/components/Messages";
import { fetchAccessToken } from "hume";
import { VoiceProvider } from "@humeai/voice-react";
import { InferGetServerSidePropsType } from "next";

export const getServerSideProps = async () => {
  try {
    const accessToken = await fetchAccessToken({
      apiKey: String(process.env.HUME_API_KEY),
      secretKey: String(process.env.HUME_SECRET_KEY),
    });

    return {
      props: {
        accessToken,
      },
    };
  } catch (error) {
    console.error("Failed to fetch access token:", error);
    throw error;
  }
};

type PageProps = InferGetServerSidePropsType<
  typeof getServerSideProps
>;

export default function Page({ accessToken }: PageProps) {
  return (
    <div className={"grow flex flex-col"}>
    </div>
  );
}
```

## Context Provider \[#context-provider]

After fetching our access token we can pass it to our `Chat` component. First we set up the `<VoiceProvider/>` so that
our `Messages` and `StartCall` components can access the context.

We also pass the access token to the `accessToken` prop of the `StartCall` component for setting up the WebSocket
connection.

#### App Router

#### ./app/page.tsx

```tsx maxLines=0
import { VoiceProvider } from "@humeai/voice-react";
import Messages from "./Messages";
import StartCall from "./StartCall";

export default function Chat({
  accessToken,
}: {
  accessToken: string;
}) {
  return (
    <VoiceProvider>
      <Messages />
      <StartCall accessToken={accessToken}/>
    </VoiceProvider>
  );
}
```

#### Pages Router

#### ./pages/index.tsx

```tsx maxLines=0
import StartCall from "@/components/StartCall";
import Messages from "@/components/Messages";
import { fetchAccessToken } from "hume";
import { VoiceProvider } from "@humeai/voice-react";
import { InferGetServerSidePropsType } from "next";

export const getServerSideProps = async () => {
  try {
    const accessToken = await fetchAccessToken({
      apiKey: String(process.env.HUME_API_KEY),
      secretKey: String(process.env.HUME_SECRET_KEY),
    });

    return {
      props: {
        accessToken,
      },
    };
  } catch (error) {
    console.error("Failed to fetch access token:", error);
    throw error;
  }
};

type PageProps = InferGetServerSidePropsType<
  typeof getServerSideProps
>;

export default function Page({ accessToken }: PageProps) {
  return (
    <div className={"grow flex flex-col"}>
      <VoiceProvider>
        <Messages />
        <StartCall accessToken={accessToken}/>
      </VoiceProvider>
    </div>
  );
}
```

## Connection \[#connection]

Use the `useVoice` hook's `connect` method for starting a Chat session. It is important that this event is
attached to a user interaction event (like a click) so that the browser is capable of recording and playing
back audio.

> **Info**
>
> Implementing this step is the same whether you are using the **App Router** or **Pages Router**.

#### ./components/StartCall.tsx

```tsx maxLines=0
"use client";
import {
  useVoice,
  ConnectOptions,
  VoiceReadyState
} from "@humeai/voice-react";

export default function StartCall({
  accessToken,
}: {
  accessToken: string;
}) {
  const { connect, disconnect, readyState } = useVoice();

  if (readyState === VoiceReadyState.OPEN) {
    return (
      <button
        onClick={() => {
          disconnect();
        }}
      >
        End Session
      </button>
    );
  }

  return (
    <button
      onClick={() => {
        connect({
          auth: { type: "accessToken", value: accessToken }
        })
          .then(() => {
            /* handle success */
          })
          .catch(() => {
            /* handle error */
          });
      }}
    >
      Start Session
    </button>
  );
}
```

## Display chat \[#display-chat]

Use the `useVoice` hook to access the `messages` array. We can then map over the `messages` array to display the
role (`Assistant` or `User`) and content of each message.

> **Info**
>
> Implementing this step is the same whether you are using the **App Router** or **Pages Router**.

#### ./components/Messages.tsx

```tsx maxLines=0
import { useVoice } from "@humeai/voice-react";

export default function Messages() {
  const { messages } = useVoice();

  return (
    <div>
      {messages.map((msg, index) => {
        if (msg.type === "user_message" || msg.type === "assistant_message") {
          return null;
        }

        return (
          <div key={msg.type + index}>
            <div>{msg.message.role}</div>
            <div>{msg.message.content}</div>
          </div>
        );
      })}
    </div>
  );
}
```

## Next steps

**Congratulations!** You’ve successfully integrated EVI using Hume’s React SDK.

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.

---