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

# Step 3: Start the avatar session

> Connect the browser to your Anam session token, stream the ElevenLabs avatar, and handle transcripts and session lifecycle in React.

This is the final step of the quickstart. With the [server route from step two](/docs/integrations/elevenlabs/server-side-setup) in place, connect the browser and start a conversation with your avatar.

## Install the JavaScript SDK

In your Next.js project, install the SDK with your package manager:

```bash theme={"system"}
npm install @anam-ai/js-sdk
```

## Connect the browser

Request the session token, create an Anam client, and attach its stream to your video element:

```typescript theme={"system"}
import { createClient } from "@anam-ai/js-sdk";

const res = await fetch("/api/anam-session", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ avatarId, agentId }),
});
const { sessionToken } = await res.json();

const client = createClient(sessionToken);
await client.streamToVideoElement("avatar-video");
```

`streamToVideoElement()` starts microphone capture and renders the avatar's video and audio in the element with the matching ID.

## Working component example

Below is a React component with connection lifecycle and a streaming transcript.

The `MESSAGE_STREAM_EVENT_RECEIVED` event fires for each chunk of text from both the user and the agent. Accumulate chunks by message ID to build the full transcript.

```typescript theme={"system"}
"use client";

import { useRef, useState, useCallback } from "react";
import { AnamEvent, createClient, type AnamClient } from "@anam-ai/js-sdk";

type Message = {
  id: string;
  role: "user" | "persona";
  content: string;
  interrupted?: boolean;
};

export default function AvatarChat({
  avatarId,
  agentId,
}: {
  avatarId: string;
  agentId: string;
}) {
  const clientRef = useRef<AnamClient | null>(null);
  const [status, setStatus] = useState<"idle" | "connecting" | "connected">("idle");
  const [messages, setMessages] = useState<Message[]>([]);

  const start = useCallback(async () => {
    setStatus("connecting");
    setMessages([]);

    try {
      const res = await fetch("/api/anam-session", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ avatarId, agentId }),
      });
      const body = await res.json();
      if (!res.ok) {
        throw new Error(body.error ?? "Failed to create a session token");
      }

      const anamClient = createClient(body.sessionToken);
      clientRef.current = anamClient;

      // Accumulate transcript chunks by message ID
      anamClient.addListener(
        AnamEvent.MESSAGE_STREAM_EVENT_RECEIVED,
        (evt: {
          id: string;
          content: string;
          role: string;
          interrupted: boolean;
        }) => {
          setMessages((prev) => {
            const idx = prev.findIndex((m) => m.id === evt.id);
            if (idx >= 0) {
              const next = [...prev];
              next[idx] = {
                ...next[idx],
                content: next[idx].content + evt.content,
                interrupted: evt.interrupted,
              };
              return next;
            }
            return [
              ...prev,
              {
                id: evt.id,
                role: evt.role as "user" | "persona",
                content: evt.content,
                interrupted: evt.interrupted,
              },
            ];
          });
        }
      );

      anamClient.addListener(AnamEvent.CONNECTION_CLOSED, () => {
        setStatus("idle");
      });

      await anamClient.streamToVideoElement("avatar-video");
      setStatus("connected");
    } catch (error) {
      console.error("Failed to start the avatar session:", error);
      clientRef.current = null;
      setStatus("idle");
    }
  }, [avatarId, agentId]);

  const stop = useCallback(async () => {
    await clientRef.current?.stopStreaming();
    clientRef.current = null;
    setStatus("idle");
  }, []);

  return (
    <div>
      <video id="avatar-video" autoPlay playsInline />
      <button
        disabled={status === "connecting"}
        onClick={status === "connected" ? stop : start}
      >
        {status === "connected" ? "Stop" : "Start"}
      </button>
      <ul>
        {messages.map((message) => (
          <li key={message.id}>
            <strong>{message.role === "user" ? "You" : "Agent"}:</strong>{" "}
            {message.content}
            {message.interrupted && " (interrupted)"}
          </li>
        ))}
      </ul>
    </div>
  );
}
```

## Run your first conversation

1. Save the component above as `AvatarChat.tsx` and render it on a page in your Next.js app. Pass your Cara 4 avatar ID as `avatarId` and the ElevenLabs agent ID from step one as `agentId`.
2. Start your development server with your project's dev command, such as `npm run dev`. Open the page on localhost.
3. Click **Start** and allow microphone access. The avatar video should appear and the button should change to **Stop**.
4. Speak to the agent. Confirm that you hear its reply, see the avatar speaking in sync, and see both sides of the conversation in the transcript.
5. Click **Stop** to end the session. Click **Start** again to check that you can reconnect, then stop the session when you finish testing.

<Check>
  **Quickstart complete.** You now have a working ElevenLabs agent with an Anam avatar.
</Check>

If the video or conversation does not start, follow [Troubleshooting](/docs/integrations/elevenlabs/troubleshooting).

## Upgrade your avatar

Your avatar session is running. Build on it with expressive performance, personalised conversations, and actions in your app:

* [Director Notes](/docs/integrations/elevenlabs/director-notes): add expressions that follow ElevenLabs audio tags.
* [Session customisation](/docs/integrations/elevenlabs/session-customisation): pass user-specific variables, override settings, or attach a user ID.
* [Client tools](/docs/integrations/elevenlabs/client-tools): let the agent trigger actions in your browser and receive the results.

For more on event handling, message history, and connection lifecycle, see the [basic Next.js app recipe](https://anam.ai/cookbook/basic-nextjs-app).

<Card title="Next: Add Director Notes" icon="arrow-right" href="/docs/integrations/elevenlabs/director-notes">
  Connect ElevenLabs audio tags to the avatar's performance.
</Card>


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