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

# Browser Calls (WebRTC)

> Make voice calls to your AI agent directly from the browser using WebRTC.

Voicebip supports browser-based voice calls via WebRTC using [pion/webrtc](https://github.com/pion/webrtc). This enables two use cases:

1. **Dashboard test calls** - Test your agent from the dashboard without a phone
2. **Shareable links** - Let anyone call your agent from a browser (see [Shareable Links](/guides/shareable-links))

## WebRTC Signaling (Public Endpoint)

The public endpoint handles WebRTC signaling for shareable agent links. No authentication required.

```bash
curl -X POST "https://api.voicebip.com/v1/public/try/{agent_id}/offer" \
  -H "Content-Type: application/json" \
  -d '{
    "sdp": "v=0\r\no=- 1234567890 2 IN IP4 127.0.0.1\r\n...",
    "agent_id": "agt_PAEZ_njcfm2kycpjs"
  }'
```

Response:

```json
{
  "sdp": "v=0\r\no=- 9876543210 2 IN IP4 ...\r\n...",
  "type": "answer",
  "call_id": "call_webrtc_abc123"
}
```

## Browser Implementation

Here is a minimal JavaScript example for establishing a WebRTC call:

```javascript
async function callAgent(agentId) {
  // 1. Get microphone access
  const stream = await navigator.mediaDevices.getUserMedia({ audio: true });

  // 2. Create peer connection
  const pc = new RTCPeerConnection({
    iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
  });

  // 3. Add audio track
  stream.getTracks().forEach((track) => pc.addTrack(track, stream));

  // 4. Handle remote audio
  const remoteAudio = new Audio();
  remoteAudio.autoplay = true;
  pc.ontrack = (event) => {
    remoteAudio.srcObject = event.streams[0];
  };

  // 5. Create and send offer
  const offer = await pc.createOffer();
  await pc.setLocalDescription(offer);

  const response = await fetch(
    `https://api.voicebip.com/v1/public/try/${agentId}/offer`,
    {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ sdp: offer.sdp, agent_id: agentId }),
    }
  );
  const { sdp, call_id } = await response.json();

  // 6. Set remote description
  await pc.setRemoteDescription({ type: "answer", sdp });

  // Call is now active. The agent will greet the caller via TTS.
  console.log("Call started:", call_id);

  // 7. Hang up
  return {
    hangup: () => {
      pc.close();
      stream.getTracks().forEach((track) => track.stop());
    },
    callId: call_id,
  };
}
```

## Audio Visualization

The dashboard includes real-time audio level visualization during calls. To implement this in your own UI:

```javascript
const audioContext = new AudioContext();
const analyser = audioContext.createAnalyser();
const source = audioContext.createMediaStreamSource(stream);
source.connect(analyser);

analyser.fftSize = 256;
const dataArray = new Uint8Array(analyser.frequencyBinCount);

function draw() {
  analyser.getByteFrequencyData(dataArray);
  const average = dataArray.reduce((a, b) => a + b) / dataArray.length;
  // Use `average` to drive a visual indicator (0-255)
  requestAnimationFrame(draw);
}
draw();
```

## Live Transcript

During a WebRTC call, you can stream the live transcript via Server-Sent Events (SSE). Pass your API key as a `?token=` query parameter since browsers cannot set `Authorization` headers on `EventSource` connections.

```javascript
const es = new EventSource(
  `https://api.voicebip.com/v1/calls/${callId}/transcript/stream?token=${apiKey}`
);

es.onmessage = (event) => {
  const data = JSON.parse(event.data);
  // Each frame: { role, text, is_final, turn_id, ts }
  // role is "user" (caller) or "agent"
  console.log(`[${data.role}] ${data.text}`);
};

// Close when done
es.close();
```

## Requirements

* Modern browser with WebRTC support (Chrome, Firefox, Safari, Edge)
* Microphone access permission
* Agent must have `shareable: true` for public endpoint access

## Current Limitations

**Barge-in is not yet supported on WebRTC calls.** When the agent is speaking and the user interrupts, the WebRTC path lets the current TTS audio finish before processing the next turn. Barge-in (interrupting mid-response) works on regular phone calls placed and received via the API (ESL and SIP transports), but is not yet wired into the WebRTC peer connection path.

## Error Handling

| HTTP Status | Meaning                                                                                      |
| ----------- | -------------------------------------------------------------------------------------------- |
| 200         | SDP answer returned, call established                                                        |
| 404         | Agent not found or `shareable` is false                                                      |
| 503         | Agent busy — concurrent limit (10 simultaneous calls) or daily limit (50 calls/day) exceeded |
| 400         | Invalid SDP offer                                                                            |