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

# Receiving WebRTC Calls on Guava Agents

> Let callers talk to your agent straight from the browser

export const TLDR = ({children}) => <Card title="At a Glance">
    {children}
  </Card>;

<Tip>
  Looking for a drop-in widget? Check out our [widgets guide](/guides/webrtc-widgets).
</Tip>

Callers can talk to your agent straight from the browser over WebRTC, with no phone number needed.

<TLDR>
  <Tabs>
    <Tab title="Python">
      1. Create a WebRTC code (`grtc-...`).
      2. Attach your agent to that code using `agent.listen_webrtc("grtc-...")`.
      3. Start a call from the browser using `new Call({ webrtcCode: "grtc-..." }).start()`.
    </Tab>

    <Tab title="TypeScript">
      1. Create a WebRTC code (`grtc-...`).
      2. Attach your agent to that code using `agent.listenWebrtc("grtc-...")`.
      3. Start a call from the browser using `new Call({ webrtcCode: "grtc-..." }).start()`.
    </Tab>
  </Tabs>
</TLDR>

## Create a WebRTC code

A WebRTC code (`grtc-...`) is like a phone number, but for WebRTC calls. It's used to route calls from a browser client to your agent. Create one with the Guava CLI.

```bash theme={null}
guava webrtc create-code
```

Alternatively, open the [WebRTC page in the Guava dashboard](https://app.goguava.ai/dashboard/webrtc) and click **Create Code**.

## Attach your agent to the code

<Tabs>
  <Tab title="Python">
    Call `listen_webrtc` with your code. Like `listen_phone`, it blocks and handles incoming calls until the process exits.

    ```python agent.py theme={null}
    import guava

    from guava import logging_utils

    agent = guava.Agent(
        purpose="You are a helpful voice agent.",
        name="Hannah",
    )

    @agent.on_call_start
    def on_call_start(call: guava.Call):
        # Set your first task here using call.set_task(...)
        pass

    if __name__ == "__main__":
        logging_utils.configure_logging()
        agent.listen_webrtc("grtc-...") # Replace with your WebRTC code.
    ```
  </Tab>

  <Tab title="TypeScript">
    Call `listenWebrtc` with your code. Like `listenPhone`, it handles incoming calls until the process exits.

    ```typescript agent.ts theme={null}
    import * as guava from "@guava-ai/guava-sdk";

    const agent = new guava.Agent({
      purpose: "You are a helpful voice agent.",
      name: "Hannah",
    });

    agent.onCallStart(async (call) => {
      // Set your first task here using call.setTask(...)
    });

    agent.listenWebrtc("grtc-..."); // Replace with your WebRTC code.
    ```
  </Tab>
</Tabs>

## Install the WebRTC SDK

The WebRTC client is included in the TypeScript SDK and runs in the browser.

<Tabs>
  <Tab title="Using a Bundler (Recommended)">
    Install the SDK with your preferred package manager.

    ```bash theme={null}
    npm install @guava-ai/guava-sdk
    yarn add @guava-ai/guava-sdk
    pnpm add @guava-ai/guava-sdk
    ```

    Then import from `@guava-ai/guava-sdk/webrtc`.

    ```typescript theme={null}
    import * as Guava from "@guava-ai/guava-sdk/webrtc";
    ```
  </Tab>

  <Tab title="Using a CDN">
    Load a prebuilt bundle from a CDN. This exposes a global `Guava` object.

    ```html theme={null}
    <script
      src="https://cdn.jsdelivr.net/npm/@guava-ai/guava-sdk@0.38.0/dist/guava-webrtc.min.js"
      integrity="sha384-6MN0aBFnGuNmEmoeTtbYR4z0Irx2sJ26LYWjUOUyrKlAnAugcZRQOIpnpNz3zAo5"
      crossorigin="anonymous"
    ></script>
    ```

    Or load it as an ES module:

    ```html theme={null}
    <script type="importmap">
      {
        "integrity": {
          "https://cdn.jsdelivr.net/npm/@guava-ai/guava-sdk@0.38.0/dist/guava-webrtc.esm.min.js": "sha384-qnseWbldkzYVfnszRGXZuEDW2mg62vnYWLJpAk8wjfFdt+g0qBhvU4b1wnYVvkMJ"
        }
      }
    </script>
    <script type="module">
      import * as Guava from "https://cdn.jsdelivr.net/npm/@guava-ai/guava-sdk@0.38.0/dist/guava-webrtc.esm.min.js";
    </script>
    ```
  </Tab>
</Tabs>

## Start a call

Create a `Call` with your WebRTC code and call `start()`. The browser asks for microphone permission, then connects to your agent.

```typescript theme={null}
const call = new Guava.Call({ webrtcCode: "grtc-..." });
await call.start();
```

Browsers only allow microphone access after a user gesture, so start the call from something like a click handler. Use `onStateChange` to update your UI, and `hangup()` to end the call.

```typescript theme={null}
call.onStateChange((state) => {
  // "not-started" | "starting" | "waiting-for-permission" | "connecting" | "connected" | "ended"
  console.log("Call state:", state);
});

await call.hangup();
```

## Passing Through Metadata to the Agent

Use `customPayload` to send metadata from the browser to your agent, such as the signed-in user or the current page.

```typescript theme={null}
const call = new Guava.Call({
  webrtcCode: "grtc-...",
  customPayload: { userId: "123", page: "/pricing" },
});
await call.start();
```

Your agent receives the payload as `custom_payload` on the incoming call's info.

<Tabs>
  <Tab title="Python">
    ```python agent.py theme={null}
    from guava.types.call_info import WebRTCCallInfo

    @agent.on_call_received
    def on_call_received(call_info: guava.CallInfo) -> guava.IncomingCallAction:
        if isinstance(call_info, WebRTCCallInfo):
            user_id = call_info.custom_payload.get("userId")
        return guava.AcceptCall()
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript agent.ts theme={null}
    agent.onCallReceived(async (callInfo: guava.CallInfo) => {
      if (callInfo.call_type === "webrtc") {
        const userId = callInfo.custom_payload.userId;
      }
      return { action: "accept" };
    });
    ```
  </Tab>
</Tabs>

## Sending and Receiving Messages

During a call, the browser and your agent can exchange JSON messages, for example to react to what the user does on the page or to update your UI from the agent.

In the browser, use `sendMessage` to send a message to the agent, and `onMessage` to receive messages from it.

```typescript theme={null}
call.sendMessage({ action: "added-to-cart", sku: "abc-123" });

call.onMessage((payload) => {
  if (payload.action === "show-checkout") {
    showCheckout();
  }
});
```

<Tabs>
  <Tab title="Python">
    Your agent receives browser messages in `on_webrtc_message`, and sends messages to the browser with `call.send_webrtc_message`.

    ```python agent.py theme={null}
    from guava.events import WebRTCMessageEvent

    @agent.on_webrtc_message
    def on_webrtc_message(call: guava.Call, event: WebRTCMessageEvent):
        if event.payload.get("action") == "added-to-cart":
            call.send_webrtc_message({"action": "show-checkout"})
    ```
  </Tab>

  <Tab title="TypeScript">
    <Note>
      Agent-side WebRTC messaging (`on_webrtc_message` / `send_webrtc_message`) is currently available in the Python SDK only.
    </Note>
  </Tab>
</Tabs>


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