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

# Hooks

> React hooks for accessing Pipecat client functionality

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 }`).
