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

# Hooks

> See what hooks Tavus supports for managing video calls, media controls, participant management, and conversation events.

Hooks are generated source files copied into your app by `npx @tavus/cvi-ui@latest add ...`. Import them from your generated hooks directory and render them under `CVIProvider` unless the hook explicitly only creates request helpers.

| Hook                      | Add command                      | Import path pattern                                  | Parameters        | Return values                                                      | Required context              | Generated location pattern                             |
| ------------------------- | -------------------------------- | ---------------------------------------------------- | ----------------- | ------------------------------------------------------------------ | ----------------------------- | ------------------------------------------------------ |
| `useCVICall`              | `add use-cvi-call`               | `<components-path>/hooks/use-cvi-call`               | None              | `joinCall`, `leaveCall`                                            | `CVIProvider`                 | `<components-path>/hooks/use-cvi-call.*`               |
| `useStartHaircheck`       | `add use-start-haircheck`        | `<components-path>/hooks/use-start-haircheck`        | None              | Permission booleans, `requestPermissions`                          | `CVIProvider`                 | `<components-path>/hooks/use-start-haircheck.*`        |
| `useLocalCamera`          | `add use-local-camera`           | `<components-path>/hooks/use-local-camera`           | None              | `onToggleCamera`, `isCamReady`, `isCamMuted`, `localSessionId`     | `CVIProvider` and active call | `<components-path>/hooks/use-local-camera.*`           |
| `useLocalMicrophone`      | `add use-local-microphone`       | `<components-path>/hooks/use-local-microphone`       | None              | `onToggleMicrophone`, `isMicReady`, `isMicMuted`, `localSessionId` | `CVIProvider` and active call | `<components-path>/hooks/use-local-microphone.*`       |
| `useLocalScreenshare`     | `add use-local-screenshare`      | `<components-path>/hooks/use-local-screenshare`      | None              | `onToggleScreenshare`, `isScreenSharing`, `localSessionId`         | `CVIProvider` and active call | `<components-path>/hooks/use-local-screenshare.*`      |
| `useRequestPermissions`   | `add use-request-permissions`    | `<components-path>/hooks/use-request-permissions`    | None              | `requestPermissions`                                               | `CVIProvider`                 | `<components-path>/hooks/use-request-permissions.*`    |
| `useReplicaIDs`           | `add use-replica-ids`            | `<components-path>/hooks/use-replica-ids`            | None              | `string[]`                                                         | `CVIProvider` and active call | `<components-path>/hooks/use-replica-ids.*`            |
| `useRemoteParticipantIDs` | `add use-remote-participant-ids` | `<components-path>/hooks/use-remote-participant-ids` | None              | `string[]`                                                         | `CVIProvider` and active call | `<components-path>/hooks/use-remote-participant-ids.*` |
| `useObservableEvent`      | `add cvi-events-hooks`           | `<components-path>/hooks/cvi-events-hooks`           | `callback(event)` | None                                                               | `CVIProvider` and active call | `<components-path>/hooks/cvi-events-hooks.*`           |
| `useClosedCaption`        | `add use-closed-caption`         | `<components-path>/hooks/use-closed-caption`         | None              | `ClosedCaption` or `null`                                          | `CVIProvider` and active call | `<components-path>/hooks/use-closed-caption.*`         |
| `useSendAppMessage`       | `add cvi-events-hooks`           | `<components-path>/hooks/cvi-events-hooks`           | None              | `sendMessage(message)`                                             | `CVIProvider` and active call | `<components-path>/hooks/cvi-events-hooks.*`           |
| `useChat`                 | `add use-chat`                   | `<components-path>/hooks/use-chat`                   | None              | `messages`, `sendMessage(text)`                                    | `CVIProvider` and active call | `<components-path>/hooks/use-chat.*`                   |

## 🔧 Core Call Management

### useCVICall

Essential hook for joining and leaving video calls.

```bash theme={null}
npx @tavus/cvi-ui@latest add use-cvi-call
```

<Tabs>
  <Tab title="Description">
    A React hook that provides comprehensive call management functionality for video conversations. This hook handles the core lifecycle of video calls, including connection establishment, room joining, and proper cleanup when leaving calls.

    **Purpose:**

    * Manages call join/leave operations with proper state management
    * Handles connection lifecycle and cleanup
    * Provides simple interface for call control

    **Return Values:**

    * `joinCall` (function): Function to join a call by URL - handles Daily.co room connection
    * `leaveCall` (function): Function to leave the current call - properly disconnects and cleans up resources
  </Tab>

  <Tab title="Code">
    ```tsx theme={null}
    import { useCVICall } from './hooks/use-cvi-call';
    ```

    ```tsx theme={null}
    const CallManager = () => {
      const { joinCall, leaveCall } = useCVICall();

      const handleJoin = () => {
        joinCall({ url: 'https://your-daily-room-url' });
      };

      return (
        <div>
          <button onClick={handleJoin}>Join Call</button>
          <button onClick={leaveCall}>Leave Call</button>
        </div>
      );
    };
    ```
  </Tab>
</Tabs>

### useStartHaircheck

A React hook that manages device permissions and camera initialization for the hair-check component.

```bash theme={null}
npx @tavus/cvi-ui@latest add use-start-haircheck
```

<Tabs>
  <Tab title="Description">
    A React hook that manages device permissions and camera initialization for the hair-check component.

    **Purpose:**

    * Monitors device permission states
    * Starts camera and microphone when appropriate
    * Provides permission state for UI conditional rendering
    * Handles permission request flow

    **Return Values:**

    * `isPermissionsPrompt` (boolean): Browser is prompting for device permission
    * `isPermissionsLoading` (boolean): Permissions are being processed or camera is initializing
    * `isPermissionsGranted` (boolean): Device permission granted
    * `isPermissionsDenied` (boolean): Device permission denied
    * `requestPermissions` (function): Function to request camera and microphone permissions
  </Tab>

  <Tab title="Code">
    ```tsx theme={null}
    import { useStartHaircheck } from './hooks/use-start-haircheck';
    ```

    ```tsx theme={null}
    const HairCheckComponent = () => {
      const {
        isPermissionsPrompt,
        isPermissionsLoading,
        isPermissionsGranted,
        isPermissionsDenied,
        requestPermissions
      } = useStartHaircheck();

      useEffect(() => {
        requestPermissions();
      }, []);

      return (
        <div>
          {isPermissionsLoading && <InitializingSpinner />}
          {isPermissionsPrompt && <PermissionPrompt />}
          {isPermissionsDenied && <PermissionDeniedMessage />}
          {isPermissionsGranted && <VideoPreview />}
        </div>
      );
    };
    ```
  </Tab>
</Tabs>

***

## 🎥 Media Controls

### useLocalCamera

A React hook that provides local camera state and toggle functionality.

```bash theme={null}
npx @tavus/cvi-ui@latest add use-local-camera
```

<Tabs>
  <Tab title="Description">
    A React hook that provides local camera state and toggle functionality.

    **Purpose:**

    * Manages local camera state (on/off)
    * Tracks camera permission and ready state

    **Return Values:**

    * `onToggleCamera` (function): Function to toggle camera on/off
    * `isCamReady` (boolean): Camera permission is granted and ready
    * `isCamMuted` (boolean): Camera is currently turned off
    * `localSessionId` (string): Local session ID
  </Tab>

  <Tab title="Code">
    ```tsx theme={null}
    import { useLocalCamera } from './hooks/use-local-camera';
    ```

    ```tsx theme={null}
    const CameraControls = () => {
      const { onToggleCamera, isCamReady, isCamMuted } = useLocalCamera();

      return (
        <button
          onClick={onToggleCamera}
          disabled={!isCamReady}
        >
          {isCamMuted ? 'Turn Camera On' : 'Turn Camera Off'}
        </button>
      );
    };
    ```
  </Tab>
</Tabs>

### useLocalMicrophone

A React hook that provides local microphone state and toggle functionality.

```bash theme={null}
npx @tavus/cvi-ui@latest add use-local-microphone
```

<Tabs>
  <Tab title="Description">
    A React hook that provides local microphone state and toggle functionality.

    **Purpose:**

    * Manages local microphone state (on/off)
    * Tracks microphone permission and ready state

    **Return Values:**

    * `onToggleMicrophone` (function): Function to toggle microphone on/off
    * `isMicReady` (boolean): Microphone permission is granted and ready
    * `isMicMuted` (boolean): Microphone is currently turned off
    * `localSessionId` (string): Local session ID
  </Tab>

  <Tab title="Code">
    ```tsx theme={null}
    import { useLocalMicrophone } from './hooks/use-local-microphone';
    ```

    ```tsx theme={null}
    const MicrophoneControls = () => {
      const { onToggleMicrophone, isMicReady, isMicMuted } = useLocalMicrophone();

      return (
        <button
          onClick={onToggleMicrophone}
          disabled={!isMicReady}
        >
          {isMicMuted ? 'Unmute' : 'Mute'}
        </button>
      );
    };
    ```
  </Tab>
</Tabs>

### useLocalScreenshare

A React hook that provides local screen sharing state and toggle functionality.

```bash theme={null}
npx @tavus/cvi-ui@latest add use-local-screenshare
```

<Tabs>
  <Tab title="Description">
    A React hook that provides local screen sharing state and toggle functionality.

    **Purpose:**

    * Manages screen sharing state (on/off)
    * Provides screen sharing toggle function
    * Handles screen share start/stop with optimized display media options

    **Return Values:**

    * `onToggleScreenshare` (function): Function to toggle screen sharing on/off
    * `isScreenSharing` (boolean): Whether screen sharing is currently active
    * `localSessionId` (string): Local session ID

    **Display Media Options:**
    When starting screen share, the hook uses the following optimized settings:

    * **Audio**: Disabled (false)
    * **Self Browser Surface**: Excluded
    * **Surface Switching**: Included
    * **Video Resolution**: 1920x1080
  </Tab>

  <Tab title="Code">
    ```tsx theme={null}
    import { useLocalScreenshare } from './hooks/use-local-screenshare';
    ```

    ```tsx theme={null}
    const ScreenShareControls = () => {
      const { onToggleScreenshare, isScreenSharing } = useLocalScreenshare();

      return (
        <button
          onClick={onToggleScreenshare}
          className={isScreenSharing ? 'active' : ''}
        >
          {isScreenSharing ? 'Stop Sharing' : 'Share Screen'}
        </button>
      );
    };
    ```
  </Tab>
</Tabs>

### useRequestPermissions

A React hook that requests camera and microphone permissions with optimized audio processing settings.

```bash theme={null}
npx @tavus/cvi-ui@latest add use-request-permissions
```

<Tabs>
  <Tab title="Description">
    A React hook that requests camera and microphone permissions with optimized audio processing settings.

    **Purpose:**

    * Requests camera and microphone permissions from the user
    * Starts camera and audio with specific configuration
    * Applies noise cancellation audio processing
    * Provides a clean interface for permission requests

    **Return Values:**

    * `requestPermissions` (function): Function to request camera and microphone permissions

    **Configuration:**
    When requesting permissions, the hook uses the following settings:

    * **Video**: Started on (startVideoOff: false)
    * **Audio**: Started on (startAudioOff: false)
    * **Audio Source**: Default system audio input
    * **Audio Processing**: Noise cancellation enabled
  </Tab>

  <Tab title="Code">
    ```tsx theme={null}
    import { useRequestPermissions } from './hooks/use-request-permissions';
    ```

    ```tsx theme={null}
    const PermissionRequest = () => {
      const requestPermissions = useRequestPermissions();

      const handleRequestPermissions = async () => {
        try {
          await requestPermissions();
          console.log('Permissions granted successfully');
        } catch (error) {
          console.error('Failed to get permissions:', error);
        }
      };

      return (
        <button onClick={handleRequestPermissions}>
          Request Camera & Microphone Permissions
        </button>
      );
    };
    ```
  </Tab>
</Tabs>

***

## 👥 Participant Management

### useReplicaIDs

A React hook that returns the IDs of all Tavus replica participants in a call.

```bash theme={null}
npx @tavus/cvi-ui@latest add use-replica-ids
```

<Tabs>
  <Tab title="Description">
    A React hook that returns the IDs of all Tavus replica participants in a call.

    **Purpose:**

    * Filters and returns participant IDs where `user_id` includes 'tavus-replica'

    **Return Value:**

    * `string[]` — Array of replica participant IDs
  </Tab>

  <Tab title="Code">
    ```tsx theme={null}
    import { useReplicaIDs } from './hooks/use-replica-ids';
    ```

    ```tsx theme={null}
    const ids = useReplicaIDs();
    // ids is an array of participant IDs for Tavus replicas
    ```
  </Tab>
</Tabs>

### useRemoteParticipantIDs

A React hook that returns the IDs of all remote participants in a call.

```bash theme={null}
npx @tavus/cvi-ui@latest add use-remote-participant-ids
```

<Tabs>
  <Tab title="Description">
    A React hook that returns the IDs of all remote participants in a call.

    **Purpose:**

    * Returns participant IDs for all remote participants (excluding local user)

    **Return Value:**

    * `string[]` — Array of remote participant IDs
  </Tab>

  <Tab title="Code">
    ```tsx theme={null}
    import { useRemoteParticipantIDs } from './hooks/use-remote-participant-ids';
    ```

    ```tsx theme={null}
    const remoteIds = useRemoteParticipantIDs();
    // remoteIds is an array of remote participant IDs
    ```
  </Tab>
</Tabs>

***

## 💬 Conversation & Events

### useObservableEvent

A React hook that listens for CVI app messages and provides a callback mechanism for handling various conversation events.

```bash theme={null}
npx @tavus/cvi-ui@latest add cvi-events-hooks
```

<Tabs>
  <Tab title="Description">
    A React hook that listens for CVI app messages and provides a callback mechanism for handling various conversation events.

    **Purpose:**

    * Listens for app messages from the Daily.co call mapped to CVI events
    * Handles various conversation event types (utterances, tool calls, speaking events, etc.)
    * Provides type-safe event handling for CVI interactions

    **Parameters:**

    * `callback` (function): Function called when app messages are received

    **Event Types:**
    This hook handles all CVI conversation events. For detailed information about each event type, see the [Interaction Events overview](/sections/conversational-video-interface/interactions-protocols/overview).
  </Tab>

  <Tab title="Code">
    ```tsx theme={null}
    import { useObservableEvent } from './hooks/cvi-events-hooks';
    ```

    ```tsx theme={null}
    const ConversationHandler = () => {
      useObservableEvent((event) => {
        switch (event.event_type) {
          case 'conversation.utterance':
            console.log('Speech:', event.properties.speech);
            break;
          case 'conversation.replica.started_speaking':
            console.log('Replica started speaking');
            break;
          case 'conversation.user.stopped_speaking':
            console.log('User stopped speaking');
            break;
        }
      });

      return <div>Listening for conversation events...</div>;
    };
    ```
  </Tab>
</Tabs>

### useClosedCaption

A React hook that returns the latest closed caption with the speaker's role and text.

```bash theme={null}
npx @tavus/cvi-ui@latest add use-closed-caption
```

<Tabs>
  <Tab title="Description">
    A React hook that returns the latest closed caption with the speaker's role and text. Subscribes to `conversation.utterance.streaming` events for both `user` and `replica` roles and exposes the latest caption to your UI.

    **Purpose:**

    * Streams captions for both the user and the replica from `conversation.utterance.streaming`
    * Updates progressively as either party speaks
    * Auto-clears the caption 2 seconds after a `final` utterance
    * Returns `null` when no caption is currently being shown

    **Return Value:**

    * `ClosedCaption | null` where `ClosedCaption` is `{ role: "user" | "replica"; text: string }`
  </Tab>

  <Tab title="Code">
    ```tsx theme={null}
    import { useClosedCaption } from './hooks/use-closed-caption';
    ```

    ```tsx theme={null}
    const Captions = () => {
      const caption = useClosedCaption();

      if (!caption) return null;

      return (
        <div role="status" aria-live="polite">
          <span>{caption.role === 'replica' ? 'Replica' : 'You'}</span>
          <span>{caption.text}</span>
        </div>
      );
    };
    ```
  </Tab>
</Tabs>

### useSendAppMessage

A React hook that provides a function to send CVI app messages to other participants in the call.

```bash theme={null}
npx @tavus/cvi-ui@latest add cvi-events-hooks
```

<Tabs>
  <Tab title="Description">
    A React hook that provides a function to send CVI app messages to other participants in the call.

    **Purpose:**

    * Sends various types of conversation messages to the CVI system
    * Supports echo, respond, interrupt, and context management messages
    * Provides type-safe message sending with proper validation
    * Enables real-time communication with Tavus replicas and conversation management

    **Return Value:**

    * `(message: SendAppMessageProps) => void` - Function that sends the message when called

    **Message Types:**
    This hook supports all CVI interaction types. For detailed information about each interaction type and their properties, see the [Interaction Events overview](/sections/conversational-video-interface/interactions-protocols/overview).
  </Tab>

  <Tab title="Code">
    ```tsx theme={null}
    import { useSendAppMessage } from './hooks/cvi-events-hooks';
    ```

    ```tsx theme={null}
    const MessageSender = () => {
      const sendMessage = useSendAppMessage();

      // Send a text echo
      const sendTextEcho = () => {
        sendMessage({
          message_type: "conversation",
          event_type: "conversation.echo",
          conversation_id: "conv-123",
          properties: {
            modality: "text",
            text: "Hello, world!",
            audio: "",
            sample_rate: 16000,
            inference_id: "inf-456",
            done: true
          }
        });
      };

      // Send a text response
      const sendResponse = () => {
        sendMessage({
          message_type: "conversation",
          event_type: "conversation.respond",
          conversation_id: "conv-123",
          properties: {
            text: "This is my response to the conversation."
          }
        });
      };

      return (
        <div>
          <button onClick={sendTextEcho}>Send Text Echo</button>
          <button onClick={sendResponse}>Send Response</button>
        </div>
      );
    };
    ```
  </Tab>
</Tabs>

### useChat

A React hook that powers a chat experience on top of the live conversation. It tracks the running transcript and provides a function to send a user turn back to the replica.

```bash theme={null}
npx @tavus/cvi-ui@latest add use-chat
```

<Tabs>
  <Tab title="Description">
    A React hook that powers a chat experience on top of the live conversation. Subscribes to Daily app messages and tracks `conversation.utterance` events from both `user` and `replica` roles, and exposes a `sendMessage` function that dispatches `conversation.respond`.

    **Purpose:**

    * Builds a chronological transcript of `user` and `replica` messages from `conversation.utterance` events
    * Optimistically appends locally sent messages so the UI updates immediately, then reconciles each pending message with the matching server-side utterance using `inference_id`
    * Dispatches `conversation.respond` when the user sends a chat message
    * Designed to back the [`Chat`](/sections/conversational-video-interface/component-library/components#chat) components (`ChatProvider`, `ChatPanel`, `ChatButton`)

    **Return Values:**

    * `messages` (`ChatMessage[]`): Ordered transcript where `ChatMessage` is `{ id: string; role: "user" | "replica"; text: string; inference_id?: string; pending?: boolean }`
    * `sendMessage` (`(text: string) => void`): Sends a user turn — appends a pending local echo to `messages` and dispatches `conversation.respond`. The pending entry is reconciled (and `pending` cleared) when the matching utterance arrives by `inference_id`.
  </Tab>

  <Tab title="Code">
    ```tsx theme={null}
    import { useChat } from './hooks/use-chat';
    ```

    ```tsx theme={null}
    const Chat = () => {
      const { messages, sendMessage } = useChat();
      const [draft, setDraft] = useState('');

      const onSubmit = () => {
        const text = draft.trim();
        if (!text) return;
        sendMessage(text);
        setDraft('');
      };

      return (
        <div>
          <ul>
            {messages.map((m) => (
              <li key={m.id} aria-busy={m.pending || undefined}>
                <strong>{m.role === 'replica' ? 'Replica' : 'You'}:</strong> {m.text}
              </li>
            ))}
          </ul>
          <textarea
            value={draft}
            onChange={(e) => setDraft(e.target.value)}
          />
          <button onClick={onSubmit}>Send</button>
        </div>
      );
    };
    ```
  </Tab>
</Tabs>
