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

# Integrate a Voice Agent with JavaScript

> Connect a Zero Runtime voice AI agent to a vanilla JavaScript app so users can talk to it in real time using the Google Gemini Live API.

Zero Runtime lets you integrate AI agents with real-time voice interaction into your JavaScript application within minutes.

In this quickstart, you'll create an AI agent that joins a meeting room and interacts with users through voice using the Google Gemini Live API.

## Prerequisites

Before proceeding, ensure that your development environment meets the following requirements:

* A Zero Runtime account (create one from the [Zero Runtime Dashboard](https://app.zeroruntime.ai/)).
* Node.js and Python 3.11+ installed on your device.
* A Google API key with Gemini Live API access.

<Note>
  You need a Zero Runtime account to generate a token and a Google API key for the Gemini Live API.
  Generate a token from the [Zero Runtime Dashboard](https://app.zeroruntime.ai/) and a Google API key from [Google AI Studio](https://aistudio.google.com/api-keys).
</Note>

## Project Structure

First, create an empty project using `mkdir folder_name` in your preferred location for the JavaScript frontend. Your final project structure should look like this:

<Tree>
  <Tree.Folder name="root" defaultOpen>
    <Tree.File name="index.html" />

    <Tree.File name="config.js" />

    <Tree.File name="index.js" />

    <Tree.File name="agent-js.py" />

    <Tree.File name=".env" />
  </Tree.Folder>
</Tree>

You will be working on the following files:

* `index.html`: Creates a basic UI for joining the meeting.
* `config.js`: Stores the token and room ID for the JavaScript frontend.
* `index.js`: Renders the meeting view and handles audio functionality.
* `agent-js.py`: The Python AI agent backend using the Google Gemini Live API.
* `.env`: Environment variables for the Python agent's API keys.

## Part 1: JavaScript Frontend

<Steps>
  <Step title="Install Zero Runtime" icon="download">
    Import Zero Runtime using the `<script>` tag or install it using npm/yarn.

    <Tabs>
      <Tab title="<script>">
        ```html theme={null}
        <html>
          <head>
            <!--.....-->
          </head>
          <body>
            <!--.....-->
            <script src="https://sdk.videosdk.live/js-sdk/0.3.6/videosdk.js"></script>
          </body>
        </html>
        ```
      </Tab>

      <Tab title="npm">
        ```bash theme={null}
        npm install @videosdk.live/js-sdk
        ```
      </Tab>

      <Tab title="yarn">
        ```bash theme={null}
        yarn add @videosdk.live/js-sdk
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Design the user interface" icon="window">
    Create an `index.html` file containing a `join-screen` and a `grid-screen` for audio-only interaction.

    ```html title="index.html" theme={null}
    <!DOCTYPE html>
    <html>
    <head> </head>
    <body>
        <div id="join-screen">
            <button id="createMeetingBtn">Join Agent Meeting</button>
        </div>
        <div id="textDiv"></div>
        <div id="grid-screen" style="display: none">
            <h3 id="meetingIdHeading"></h3>
            <button id="leaveBtn">Leave</button>
            <button id="toggleMicBtn">Toggle Mic</button>
            <div id="audioContainer"></div>
        </div>
        <script src="https://sdk.videosdk.live/js-sdk/0.3.6/videosdk.js"></script>
        <script src="config.js"></script>
        <script src="index.js"></script>
    </body>
    </html>
    ```
  </Step>

  <Step title="Configure environment and credentials" icon="key">
    Create a meeting room using the Zero Runtime API:

    ```bash theme={null}
    curl -X POST https://api.videosdk.live/v2/rooms \
      -H "Authorization: YOUR_JWT_TOKEN_HERE" \
      -H "Content-Type: application/json"
    ```

    Copy the `roomId` from the response and configure it in `config.js`:

    ```js title="config.js" theme={null}
    TOKEN = "YOUR_ZRT_AUTH_TOKEN";
    ROOM_ID = "YOUR_MEETING_ID"; // Static room ID shared between frontend and agent
    ```
  </Step>

  <Step title="Implement meeting logic" icon="code">
    In `index.js`, retrieve DOM elements, declare variables, and add the core meeting functionality.

    ```js title="index.js" theme={null}
    // getting Elements from Dom
    const leaveButton = document.getElementById("leaveBtn");
    const toggleMicButton = document.getElementById("toggleMicBtn");
    const createButton = document.getElementById("createMeetingBtn");
    const audioContainer = document.getElementById("audioContainer");
    const textDiv = document.getElementById("textDiv");

    // declare Variables
    let meeting = null;
    let meetingId = "";
    let isMicOn = false;

    // Join Agent Meeting Button Event Listener
    createButton.addEventListener("click", async () => {
      document.getElementById("join-screen").style.display = "none";
      textDiv.textContent = "Please wait, we are joining the meeting";
      meetingId = ROOM_ID;
      initializeMeeting();
    });

    // Initialize meeting
    function initializeMeeting() {
      window.VideoSDK.config(TOKEN);

      meeting = window.VideoSDK.initMeeting({
        meetingId: meetingId,
        name: "C.V.Raman",
        micEnabled: true,
        webcamEnabled: false,
      });

      meeting.join();

      meeting.localParticipant.on("stream-enabled", (stream) => {
        if (stream.kind === "audio") {
          setAudioTrack(stream, meeting.localParticipant, true);
        }
      });

      meeting.on("meeting-joined", () => {
        textDiv.textContent = null;
        document.getElementById("grid-screen").style.display = "block";
        document.getElementById("meetingIdHeading").textContent = `Meeting Id: ${meetingId}`;
      });

      meeting.on("meeting-left", () => {
        audioContainer.innerHTML = "";
      });

      meeting.on("participant-joined", (participant) => {
        let audioElement = createAudioElement(participant.id);
        participant.on("stream-enabled", (stream) => {
          if (stream.kind === "audio") {
            setAudioTrack(stream, participant, false);
            audioContainer.appendChild(audioElement);
          }
        });
      });

      meeting.on("participant-left", (participant) => {
        let aElement = document.getElementById(`a-${participant.id}`);
        if (aElement) aElement.remove();
      });
    }

    // Create audio elements for participants
    function createAudioElement(pId) {
      let audioElement = document.createElement("audio");
      audioElement.setAttribute("autoPlay", "false");
      audioElement.setAttribute("playsInline", "true");
      audioElement.setAttribute("controls", "false");
      audioElement.setAttribute("id", `a-${pId}`);
      audioElement.style.display = "none";
      return audioElement;
    }

    // Set audio track
    function setAudioTrack(stream, participant, isLocal) {
      if (stream.kind === "audio") {
        if (isLocal) {
          isMicOn = true;
        } else {
          const audioElement = document.getElementById(`a-${participant.id}`);
          if (audioElement) {
            const mediaStream = new MediaStream();
            mediaStream.addTrack(stream.track);
            audioElement.srcObject = mediaStream;
            audioElement.play().catch((err) => console.error("audioElem.play() failed", err));
          }
        }
      }
    }

    // Implement controls
    leaveButton.addEventListener("click", async () => {
      meeting?.leave();
      document.getElementById("grid-screen").style.display = "none";
      document.getElementById("join-screen").style.display = "block";
    });

    toggleMicButton.addEventListener("click", async () => {
      if (isMicOn) meeting?.muteMic();
      else meeting?.unmuteMic();
      isMicOn = !isMicOn;
    });
    ```
  </Step>
</Steps>

## Part 2: Python AI Agent

<Steps>
  <Step title="Setup the project" icon="download">
    Use Python 3.11 or higher, then install the Zero Runtime Agents SDK. Create and activate a virtual environment, then install `zrt` and `python-dotenv`. Every provider plugin ships with `zrt`.

    <CodeGroup>
      ```bash uv theme={null}
      uv venv --python 3.11
      source .venv/bin/activate     # macOS/Linux
      .\.venv\Scripts\activate      # Windows
      ```

      ```bash pip theme={null}
      python3.11 -m venv venv
      source venv/bin/activate      # macOS/Linux
      .\venv\Scripts\activate       # Windows
      ```
    </CodeGroup>

    <Tip>
      New to uv? See the [uv install guide](https://docs.astral.sh/uv/getting-started/installation/).
    </Tip>

    <CodeGroup>
      ```bash uv theme={null}
      uv pip install zrt python-dotenv
      ```

      ```bash pip theme={null}
      pip install zrt python-dotenv
      ```
    </CodeGroup>
  </Step>

  <Step title="Configure environment variables" icon="key">
    Create a `.env` file in your project root to store your keys and token securely for the Python agent:

    ```shell title=".env" theme={null}
    # Google API Key for the Gemini Live API
    GOOGLE_API_KEY=your_google_api_key_here

    # Option A: pre-generated ZRT auth token
    ZRT_AUTH_TOKEN=your_zrt_auth_token_here

    # Option B: SDK auto-generates the token (omit ZRT_AUTH_TOKEN)
    # ZRT_API_KEY=your_zrt_api_key
    # ZRT_SECRET_KEY=your_zrt_secret_key
    ```
  </Step>

  <Step title="Create the AI agent backend" icon="robot">
    Create the Python AI agent (`agent-js.py`) that joins the same meeting room and interacts with users through voice.

    ```python title="agent-js.py" theme={null}
    import os
    import zrt
    from zrt import Agent, Pipeline, Room
    from zrt.plugins import GeminiRealtime, GeminiLiveConfig
    from zrt.inference import AICousticsDenoise
    from dotenv import load_dotenv

    load_dotenv()

    AGENT_ID = "game-show-agent"

    pipeline = Pipeline(
        llm=GeminiRealtime(
            api_key=os.getenv("GOOGLE_API_KEY"),  # optional when GOOGLE_API_KEY is in .env
            config=GeminiLiveConfig(model="gemini-3.1-flash-live-preview", voice="Leda", response_modalities=["AUDIO"]),
        ),
        denoise=AICousticsDenoise(model_id="quail-vf-2.2-l-16khz"),
    )


    class MyVoiceAgent(Agent):
        def __init__(self) -> None:
            super().__init__(
                name="MyVoiceAgent",
                agent_id=AGENT_ID,
                instructions="You are a high-energy game-show host guiding the caller to guess a secret number from 1 to 100 to win 1,000,000$.",
                pipeline=pipeline,
            )

        async def on_enter(self) -> None:
            await self.session.say(
                "Welcome to the Zero Runtime AI Agent game show! I'm your host, and we're about to play for 1,000,000$. Are you ready to play?"
            )

        async def on_exit(self) -> None:
            await self.session.say("Goodbye!")


    def invoke_agent() -> None:
        # Join the same room the frontend created (its meeting ID).
        zrt.invoke(AGENT_ID, room=Room(room_id="YOUR_MEETING_ID"))


    if __name__ == "__main__":
        zrt.serve(MyVoiceAgent, on_ready=invoke_agent)
    ```
  </Step>
</Steps>

## Part 3: Run the Application

<Steps>
  <Step title="Start the frontend" icon="play">
    Once you have completed all the steps above, serve your frontend files:

    ```bash theme={null}
    # Using Python's built-in server
    python3 -m http.server 8000

    # Or using the Node.js http-server
    npx http-server -p 8000
    ```

    Open `http://localhost:8000` in your web browser.
  </Step>

  <Step title="Run the AI agent" icon="terminal">
    Open a new terminal, activate your virtual environment, and run the Python agent. It reads `GOOGLE_API_KEY` from the `.env` file.

    <CodeGroup>
      ```bash uv theme={null}
      uv run python agent-js.py
      ```

      ```bash pip theme={null}
      python agent-js.py
      ```
    </CodeGroup>
  </Step>

  <Step title="Connect and interact" icon="microphone">
    1. **Join the meeting from the frontend:**
       * Click the **Join Agent Meeting** button in your browser.
       * Allow microphone permissions when prompted.

    2. **Agent connection:**
       * Once you join, the Python agent detects your participation.
       * You should see "Participant joined" in the terminal.
       * The AI agent greets you and initiates the game.

    3. **Start playing:**
       * The agent guides you through a number guessing game (1–100).
       * Use your microphone to interact with the AI host.
  </Step>
</Steps>

## Troubleshooting

<AccordionGroup>
  <Accordion title="'Waiting for participant...' but no connection" icon="plug">
    * Ensure both the frontend and the agent are running.
    * Check that the `ROOM_ID` matches in `config.js` and `agent-js.py`.
    * Verify your Zero Runtime token is valid.
  </Accordion>

  <Accordion title="Audio not working" icon="volume-high">
    * Check browser permissions for microphone access.
    * Ensure your Google API key has Gemini Live API access enabled.
  </Accordion>

  <Accordion title="Agent not responding" icon="robot">
    * Verify your `GOOGLE_API_KEY` is set in the `.env` file.
    * Check that the Gemini Live API is enabled in your Google Cloud Console.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Quickstart Example" icon="github" href="https://github.com/ZeroRuntimeAI/zrt-python-sdk-examples">
    Complete working example with source code.
  </Card>

  <Card title="Build Your First Voice Agent" icon="microphone" href="/quickstarts/build-your-first-voice-agent">
    Learn the Cascade and Realtime pipelines in depth.
  </Card>
</CardGroup>
