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

# Web (React) Guide

This guide walks you through building a voice calling application in the browser using React.

## Step 1: Create a React Project

```bash
npm create vite@latest my-jambonz-app -- --template react-ts
cd my-jambonz-app
```

## Step 2: Install the SDK

```bash
npm install @jambonz/client-sdk-web
```

## Step 3: Connect to the SBC

Create a component that connects to your jambonz SBC:

```tsx
// src/App.tsx
import { useState } from 'react';
import { createJambonzClient, ClientState } from '@jambonz/client-sdk-web';

function App() {
  const [client, setClient] = useState(null);
  const [state, setState] = useState(ClientState.Disconnected);

  const connect = async () => {
    const c = createJambonzClient({
      server: 'wss://sbc.example.com:8443',
      username: 'your-username',
      password: 'your-password',
    });

    c.on('stateChanged', (s) => setState(s));
    c.on('error', (err) => console.error('Error:', err.message));

    await c.connect();
    setClient(c);
  };

  return (
    <div>
      <p>Status: {state}</p>
      <button onClick={connect}>Connect</button>
    </div>
  );
}

export default App;
```

Run `npm run dev` and click **Connect**. You should see the status change to `registered`.

## Step 4: Make an Outbound Call

Add a call button to your component:

```tsx
const [call, setCall] = useState(null);
const [callState, setCallState] = useState(null);

const makeCall = () => {
  const newCall = client.call('+15551234567');

  newCall.on('stateChanged', (s) => setCallState(s));
  newCall.on('accepted', () => console.log('Call connected'));
  newCall.on('ended', (cause) => {
    console.log('Call ended:', cause.reason);
    setCall(null);
    setCallState(null);
  });

  setCall(newCall);
};

// In your JSX:
<button onClick={makeCall} disabled={!client}>Call</button>
<button onClick={() => call?.hangup()} disabled={!call}>Hang Up</button>
<p>Call: {callState || 'none'}</p>
```

## Step 5: Handle Incoming Calls

Listen for incoming calls and show an answer/decline UI:

```tsx
const [incomingCall, setIncomingCall] = useState(null);

// Add this after creating the client:
c.on('incoming', (call) => {
  setIncomingCall(call);
});

// In your JSX:
{incomingCall && (
  <div>
    <p>Incoming call from: {incomingCall.remoteIdentity}</p>
    <button onClick={() => {
      incomingCall.answer();
      setCall(incomingCall);
      setIncomingCall(null);
    }}>Answer</button>
    <button onClick={() => {
      incomingCall.hangup();
      setIncomingCall(null);
    }}>Decline</button>
  </div>
)}
```

## Step 6: Add Call Controls

Add mute, hold, and DTMF:

```tsx
const [isMuted, setIsMuted] = useState(false);
const [isHeld, setIsHeld] = useState(false);

// Listen for events:
newCall.on('mute', (muted) => setIsMuted(muted));
newCall.on('hold', (held) => setIsHeld(held));

// In your JSX:
<button onClick={() => call?.toggleMute()}>
  {isMuted ? 'Unmute' : 'Mute'}
</button>
<button onClick={() => isHeld ? call?.unhold() : call?.hold()}>
  {isHeld ? 'Resume' : 'Hold'}
</button>
<button onClick={() => call?.sendDTMF('1')}>Send 1</button>
```

## Step 7: Using React Hooks (Alternative)

Instead of managing state manually, use the built-in hooks:

```tsx
import { useJambonzClient, useCall } from '@jambonz/client-sdk-web';

function Phone() {
  const client = useJambonzClient({
    server: 'wss://sbc.example.com:8443',
    username: 'your-username',
    password: 'your-password',
  });

  const call = useCall(client.client);

  return (
    <div>
      <p>Status: {client.state}</p>
      {client.error && <p>Error: {client.error}</p>}

      {!client.isRegistered && (
        <button onClick={client.connect}>Connect</button>
      )}

      {client.isRegistered && !call.isActive && (
        <button onClick={() => call.makeCall('+15551234567')}>Call</button>
      )}

      {call.isActive && (
        <div>
          <p>Call: {call.state}</p>
          <button onClick={call.toggleMute}>
            {call.isMuted ? 'Unmute' : 'Mute'}
          </button>
          <button onClick={call.toggleHold}>
            {call.isHeld ? 'Resume' : 'Hold'}
          </button>
          <button onClick={call.hangup}>Hang Up</button>
        </div>
      )}

      {call.incomingCaller && (
        <div>
          <p>Incoming: {call.incomingCaller}</p>
          <button onClick={call.answerIncoming}>Answer</button>
          <button onClick={call.declineIncoming}>Decline</button>
        </div>
      )}
    </div>
  );
}
```

## Run the Full Example App

The repo includes a complete softphone example built with React + Vite + Tailwind CSS — with a polished dark theme UI, DTMF pad, incoming call handling, and console logs.

```bash
# 1. Clone the repo
git clone https://github.com/jambonz/webrtc-sdk.git
cd webrtc-sdk

# 2. Install and build the SDK
npm install
npm run build

# 3. Install and run the web example
cd examples/web
npm install
npm run dev
```

Open [http://localhost:5173](http://localhost:5173) in your browser.

#### What the example includes

The example app has clean separation between SDK logic and UI:

* **`src/useJambonz.ts`** — all SDK interactions (connect, call, mute, hold, transfer, incoming calls). **Read this file to learn the SDK.**
* **`src/App.tsx`** — wires SDK state to UI components
* **`src/components/`** — reusable UI: ConnectionForm, DialerView, ActiveCallView, IncomingCallView, DtmfPad, LogPanel

#### How to use it

1. Enter your jambonz SBC WebSocket URL (e.g. `wss://sbc.example.com:8443`)
2. Enter your SIP username and password
3. Click **Connect** — status dot turns green when registered
4. Enter a number or SIP URI and click **Call**
5. Use the in-call controls: mute, hold, DTMF pad, hang up
6. Incoming calls show an answer/decline screen
7. Expand **Console Logs** at the bottom to see SDK events

Source: [github.com/jambonz/webrtc-sdk/tree/main/examples/web](https://github.com/jambonz/webrtc-sdk/tree/main/examples/web)