> ## Documentation Index
> Fetch the complete documentation index at: https://daily-docs-deploy-no-op-warm-pods-t3002.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Hooks

> React hooks from the Pipecat React SDK for client access, media device management, and bot event handling, like usePipecatClient.

The Pipecat React SDK provides hooks for accessing client functionality, managing media devices, and handling events.

## usePipecatClient

Provides access to the `PipecatClient` instance originally passed to `PipecatClientProvider`.

```jsx theme={null}
import { usePipecatClient } from "@pipecat-ai/client-react";

function MyComponent() {
  const pcClient = usePipecatClient();

  await pcClient.startBotAndConnect({
    endpoint: '/api/start',
    requestData: {
      // Any custom data your /start endpoint requires
    }
  });
}
```

## useRTVIClientEvent

Allows subscribing to RTVI client events. It is advised to wrap handlers with `useCallback`.

```jsx theme={null}
import { useCallback } from "react";
import { RTVIEvent, TransportState } from "@pipecat-ai/client-js";
import { useRTVIClientEvent } from "@pipecat-ai/client-react";

function EventListener() {
  useRTVIClientEvent(
    RTVIEvent.TransportStateChanged,
    useCallback((transportState: TransportState) => {
      console.log("Transport state changed to", transportState);
    }, [])
  );
}
```

**Arguments**

<ParamField path="event" type="RTVIEvent" required />

<ParamField path="handler" type="function" required />

## usePipecatClientMediaDevices

Manage and list available media devices.

```jsx theme={null}
import { usePipecatClientMediaDevices } from "@pipecat-ai/client-react";

function DeviceSelector() {
  const {
    availableCams,
    availableMics,
    selectedCam,
    selectedMic,
    updateCam,
    updateMic,
  } = usePipecatClientMediaDevices();

  return (
    <>
      <select
        name="cam"
        onChange={(ev) => updateCam(ev.target.value)}
        value={selectedCam?.deviceId}
      >
        {availableCams.map((cam) => (
          <option key={cam.deviceId} value={cam.deviceId}>
            {cam.label}
          </option>
        ))}
      </select>
      <select
        name="mic"
        onChange={(ev) => updateMic(ev.target.value)}
        value={selectedMic?.deviceId}
      >
        {availableMics.map((mic) => (
          <option key={mic.deviceId} value={mic.deviceId}>
            {mic.label}
          </option>
        ))}
      </select>
    </>
  );
}
```

## usePipecatClientMediaTrack

Access audio and video tracks.

```jsx theme={null}
import { usePipecatClientMediaTrack } from "@pipecat-ai/client-react";

function MyTracks() {
  const localAudioTrack = usePipecatClientMediaTrack("audio", "local");
  const botAudioTrack = usePipecatClientMediaTrack("audio", "bot");
}
```

**Arguments**

<ParamField path="trackType" type="'audio' | 'video'" required />

<ParamField path="participantType" type="'bot' | 'local'" required />

## usePipecatClientTransportState

Returns the current transport state.

```jsx theme={null}
import { usePipecatClientTransportState } from "@pipecat-ai/client-react";

function ConnectionStatus() {
  const transportState = usePipecatClientTransportState();
}
```

## usePipecatClientCamControl

Controls the local participant's camera state.

```jsx theme={null}
import { usePipecatClientCamControl } from "@pipecat-ai/client-react";
function CamToggle() {
  const { enableCam, isCamEnabled } = usePipecatClientCamControl();

  return (
    <button onClick={() => enableCam(!isCamEnabled)}>
      {isCamEnabled ? "Disable Camera" : "Enable Camera"}
    </button>
  );
}
```

## usePipecatClientMicControl

Controls the local participant's microphone state.

```jsx theme={null}
import { usePipecatClientMicControl } from "@pipecat-ai/client-react";
function MicToggle() {
  const { enableMic, isMicEnabled } = usePipecatClientMicControl();

  return (
    <button onClick={() => enableMic(!isMicEnabled)}>
      {isMicEnabled ? "Disable Microphone" : "Enable Microphone"}
    </button>
  );
}
```

## usePipecatConversation

The primary hook for accessing the conversation message stream. Returns the current list of messages (ordered for display) and a function to inject messages programmatically.

Each assistant message's text parts are split into `spoken` and `unspoken` segments based on real-time speech progress, so you can style them differently (e.g. dim unspoken text).

```tsx theme={null}
import { usePipecatConversation } from "@pipecat-ai/client-react";
import type { ConversationMessage } from "@pipecat-ai/client-react";

function Messages() {
  const { messages } = usePipecatConversation({
    onMessageCreated(message: ConversationMessage) {
      console.log("New message:", message);
    },
    onMessageUpdated(message: ConversationMessage) {
      if (message.final) {
        console.log("Message finalized:", message);
      }
    },
  });

  return (
    <ul>
      {messages.map((msg, i) => (
        <li key={`${msg.createdAt}-${i}`}>
          <strong>{msg.role}:</strong>{" "}
          {msg.parts?.map((part, j) => {
            if (typeof part.text === "string") {
              return <span key={j}>{part.text}</span>;
            }
            // BotOutputText: { spoken, unspoken }
            return (
              <span key={j}>
                <span>{part.text.spoken}</span>
                <span style={{ opacity: 0.5 }}>{part.text.unspoken}</span>
              </span>
            );
          })}
        </li>
      ))}
    </ul>
  );
}
```

**Options**

<ParamField path="onMessageCreated" type="(message: ConversationMessage) => void">
  Called once when a new message first enters the conversation. The message may
  or may not be complete at this point — check `message.final`.
</ParamField>

<ParamField path="onMessageUpdated" type="(message: ConversationMessage) => void">
  Called whenever an existing message's content changes (e.g. streaming text
  appended, function call status changed, message finalized). Check
  `message.final` to detect finalization.
</ParamField>

<ParamField path="aggregationMetadata" type="Record<string, AggregationMetadata>">
  Metadata for aggregation types to control rendering and speech progress
  behavior. Used to determine which aggregations should be excluded from
  position-based speech splitting.
</ParamField>

**Returns**

<ParamField path="messages" type="ConversationMessage[]">
  The current list of conversation messages, ordered for display. Assistant messages have their text parts split into `{ spoken, unspoken }` based on real-time speech progress.
</ParamField>

<ParamField path="injectMessage" type="(message: { role: string; parts: ConversationMessagePart[] }) => void">
  Programmatically inject a message into the conversation (e.g. a system prompt or user-typed input).
</ParamField>

## useConversationContext

Lower-level hook that provides direct access to the conversation context. Use this when you only need `injectMessage` without subscribing to the message stream, or to check whether the connected bot supports BotOutput events.

```tsx theme={null}
import { useConversationContext } from "@pipecat-ai/client-react";

function TextInput() {
  const { injectMessage, botOutputSupported } = useConversationContext();

  const send = (text: string) => {
    injectMessage({
      role: "user",
      parts: [{ type: "text", text }],
    });
  };

  return (
    <input
      onKeyDown={(e) => e.key === "Enter" && send(e.currentTarget.value)}
    />
  );
}
```

**Returns**

<ParamField path="injectMessage" type="(message: { role: string; parts: ConversationMessagePart[] }) => void">
  Programmatically inject a message into the conversation.
</ParamField>

<ParamField path="botOutputSupported" type="boolean | null">
  Whether the connected bot supports BotOutput events (RTVI 1.1.0+). `null`
  means detection hasn't completed yet.
</ParamField>

## User interface

These hooks voice-enable a UI: stream the screen to a server-side [`UIWorker`](/api-reference/server/workers/ui-worker), send UI events, handle the bot's UI commands, and track background work. They must be used within a [`PipecatClientProvider`](/api-reference/client/react/components#pipecatclientprovider). See [the RTVI standard](/client/rtvi-standard#user-interface) for wire payloads and [Controlling the UI](/pipecat/learn/ui-worker) for the patterns.

### useUISnapshot

Streams accessibility snapshots of the page to the bot. Call once near the root of your app.

```jsx theme={null}
useUISnapshot({ enabled: true, debounceMs: 300, trackViewport: true });
```

**Arguments** — `options?: UseUISnapshotOptions` with `enabled` (default `true`), `debounceMs` (default `300`), `trackViewport` (default `true`), and `logSnapshots` (default `false`).

### useUIEventSender

Returns `(event: string, payload?) => void` to send app-defined UI events to the bot (routed to the worker's `@ui_event` handlers).

```jsx theme={null}
const sendUIEvent = useUIEventSender();
sendUIEvent("note_click", { ref: "e8" });
```

### useUICommandHandler

Registers a handler for a named UI command, active while the component is mounted.

```jsx theme={null}
useUICommandHandler("add_note", (payload) => addNoteToPage(payload));
```

**Arguments**

<ParamField path="command" type="string" required />

<ParamField path="handler" type="(payload: T) => void | Promise<void>" required />

### Default command handlers

`useDefaultUICommandHandlers(options?)` installs DOM handlers for all the standard commands at once (`scroll_to`, `focus`, `highlight`, `select_text`, `set_input_value`, `click`). Each resolves the target by snapshot `ref`, then `target_id`, and refuses unsafe targets. Install them individually with `useDefaultScrollToHandler`, `useDefaultFocusHandler`, `useDefaultHighlightHandler`, `useDefaultSelectTextHandler`, `useDefaultSetInputValueHandler`, and `useDefaultClickHandler`. For the non-DOM commands, `useToastHandler(handler)` and `useNavigateHandler(handler)` are typed convenience wrappers.

```jsx theme={null}
useUISnapshot();
useDefaultUICommandHandlers();
```

### useUIJobGroups

Reads accumulated job groups (oldest first) and controls from the nearest `UIJobGroupsProvider`. Wrap your app in the provider to collect them:

```jsx theme={null}
<UIJobGroupsProvider maxGroups={20}>
  <App />
</UIJobGroupsProvider>
```

```jsx theme={null}
const { groups, cancelJobGroup, dismissJobGroup, clearCompleted } =
  useUIJobGroups();
```

**Returns** — `UIJobGroupsAPI`: `groups: JobGroup[]`, `cancelJobGroup(jobId, reason?)`, `dismissJobGroup(jobId)`, and `clearCompleted()`. Each `JobGroup` has `jobId`, `label`, `cancellable`, `status`, and `jobs` (per-worker `{ workerName, status, updates, response }`).
