useChat

Your interface, your customers, your support crew. This hook connects a customer to chat and keeps authentication state available to your React components.

Give chat a home.

Wrap the chat interface in CStarChatProvider. Hooks inside it share that customer's client.

Support.tsx
import { CStarChatProvider } from '@cstar.help/react';
import { ChatHeader } from './ChatHeader';

export function Support({ accountKey }: { accountKey: string }) {
  return (
    <CStarChatProvider key={accountKey} teamSlug="your-team-slug">
      <ChatHeader />
    </CStarChatProvider>
  );
}

Mount this tree only for the signed-in app session. Make accountKey change when the customer, team or sign-in session changes, including signing back in as the same person. Remove the tree on app sign-out. The provider creates one client from its initial configuration and disconnects when unmounted; changing its props alone does not replace that client.

Connect the customer.

This example uses your app's existing sign-in. The button asks your server for a signed identity, then connects to cStar. A failed request leaves the customer with a useful next step.

ChatHeader.tsx
import { useEffect, useRef, useState } from 'react';
import { useChat } from '@cstar.help/react';

export function ChatHeader() {
  const { isAuthenticated, identify, disconnect } = useChat();
  const [busy, setBusy] = useState(false);
  const [feedback, setFeedback] = useState('');
  const activeRequest = useRef<AbortController | null>(null);

  useEffect(() => () => {
    activeRequest.current?.abort();
    activeRequest.current = null;
  }, []);

  async function connect() {
    if (activeRequest.current) return;
    const request = new AbortController();
    activeRequest.current = request;
    setBusy(true);
    setFeedback('');
    try {
      // Your authenticated server signs this customer's identity.
      const response = await fetch('/api/cstar-auth', {
        signal: request.signal,
        cache: 'no-store'
      });
      if (!response.ok) throw new Error('Identity unavailable');
      const { customer, signature } = await response.json();
      if (request.signal.aborted) return;
      await identify(customer, signature);
    } catch {
      if (!request.signal.aborted) {
        setFeedback("Couldn't connect. Please try again.");
      }
    } finally {
      if (activeRequest.current === request) {
        activeRequest.current = null;
        setBusy(false);
      }
    }
  }

  return (
    <section aria-label="Customer support">
      {isAuthenticated ? (
        <>
          <p>You're connected. Your crew is here to help.</p>
          <button type="button" onClick={disconnect}>Disconnect chat</button>
        </>
      ) : (
        <button type="button" disabled={busy} onClick={connect}>
          {busy ? 'Connecting…' : 'Connect to support'}
        </button>
      )}
      <p role="status">{feedback}</p>
    </section>
  );
}

/api/cstar-auth is a route you build on your server. It must use your verified app session to sign only that customer's identity and return { customer, signature } with Cache-Control: no-store. Keep the identity secret out of browser code. Follow the HMAC signing example for the exact fields and timestamp.

What the hook returns

  • isAuthenticated and authMode describe the client authentication state. authMode is null before authentication or after disconnect.
  • identify(customer, signature) returns a promise with the verified customer and session response.
  • loginWithCredentials({ email, password }) uses an existing cStar customer account. loginWithSession({ accessToken }) uses a customer token issued by cStar's auth service, not an unrelated auth provider.
  • disconnect() clears this chat client and its subscriptions. It does not sign the customer out of your app or revoke their identity-provider session.
  • error holds the latest authentication error. Authentication methods also reject, so catch them in event handlers.
  • isRealtimeReady is the hook's realtime readiness flag. Messages can use polling when realtime is unavailable; don't block chat solely on this flag.
  • isIdentified is a deprecated alias for isAuthenticated. Prefer the newer name.

The hook does not return a customer profile or a client field. Keep display details from your own authenticated session or the authentication result. To access the underlying client, call the separate useChatClient() hook inside the provider.

Keep the conversation going.

Use useTickets for conversations and useMessages for a selected thread. The customer chat guide explains authentication choices, preserving a draft after a failed response and cleaning up subscriptions.