shadimage
pipecat
componentclient-statussource: ok · hit

Client Status

Client and agent connection status rows, live-updated from transport state and bot lifecycle events.

npx shadcn add "https://ui.pipecat.ai/r/client-status.json"
free

Where it goes

stats

Interaction

animated-counter

Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.

Dependencies

Bundle weight · light
@pipecat-ai/client-js@^1.13.1@pipecat-ai/client-react@^1.8.2lucide-react@^1.41.0

Files1 · source cached 10/11/2026, 1:03:34 AM

src/components/client-status.tsx
"use client";

import { RTVIEvent } from "@pipecat-ai/client-js";
import {
  usePipecatClientTransportState,
  useRTVIClientEvent,
} from "@pipecat-ai/client-react";
import { Loader2Icon } from "lucide-react";
import { useEffect, useState } from "react";

import { cn } from "@/lib/utils";

const CONNECTING_STATES = [
  "initializing",
  "authenticating",
  "authenticated",
  "connecting",
];

export interface ClientStatusValueProps {
  /** Transport-like state string to display. */
  state?: string | null;
  className?: string;
}

/** One status value, colored and animated by connection state. */
export function ClientStatusValue({
  state,
  className,
}: ClientStatusValueProps) {
  return (
    <span
      className={cn(
        "text-muted-foreground flex items-center justify-end gap-1.5 font-mono text-xs leading-none font-medium tracking-wide uppercase",
        {
          "text-active": state === "connected" || state === "ready",
          "text-destructive": state === "error",
          "text-muted-foreground/60": state === "disconnected" || !state,
          "animate-pulse": CONNECTING_STATES.includes(state || ""),
        },
        className,
      )}
    >
      {state || "—"}
      {state &&
        ["authenticating", "authenticated", "connecting"].includes(state) && (
          <Loader2Icon className="size-3 animate-spin" />
        )}
    </span>
  );
}

export interface ClientStatusProps {
  /** Hide the agent (bot) status row. */
  noAgentState?: boolean;
  /** Hide the client (transport) status row. */
  noClientState?: boolean;
  className?: string;
}

/**
 * Client and agent connection status rows, live-updated from transport
 * state and bot lifecycle events.
 * Must be rendered inside a PipecatClientProvider.
 */
export function ClientStatus({
  noAgentState = false,
  noClientState = false,
  className,
}: ClientStatusProps) {
  const transportState = usePipecatClientTransportState();

  const [botStatus, setBotStatus] = useState<
    "disconnected" | "connecting" | "connected" | "ready" | null
  >(null);

  useEffect(() => {
    if (transportState === "connecting") {
      setBotStatus("connecting");
    }
  }, [transportState]);

  useRTVIClientEvent(RTVIEvent.BotReady, () => setBotStatus("ready"));
  useRTVIClientEvent(RTVIEvent.BotConnected, () => setBotStatus("connected"));
  useRTVIClientEvent(RTVIEvent.Disconnected, () =>
    setBotStatus("disconnected"),
  );
  useRTVIClientEvent(RTVIEvent.BotDisconnected, () =>
    setBotStatus("disconnected"),
  );

  if (noAgentState && noClientState) return null;

  return (
    <dl
      data-slot="client-status"
      className={cn(
        "grid grid-cols-[auto_minmax(0,1fr)] items-center gap-2 text-sm",
        className,
      )}
    >
      {!noClientState && (
        <>
          <dt className="text-muted-foreground">Client</dt>
          <dd className="min-w-0">
            <ClientStatusValue state={transportState} />
          </dd>
        </>
      )}
      {!noAgentState && (
        <>
          <dt className="text-muted-foreground">Agent</dt>
          <dd className="min-w-0">
            <ClientStatusValue state={botStatus} />
          </dd>
        </>
      )}
    </dl>
  );
}

More from pipecat

Browse all components in this library →