React Chat SDK
Build your own user-facing conversation UI with headless React hooks.
- Last reviewed
React Chat SDK
Use the React Chat SDK when you want to show getuserfeedback.com conversations inside your own app. You own the UI; getuserfeedback.com keeps the conversation history.
This guide builds a React conversation view that lists conversations, opens a conversation, loads older messages, and sends a message.
How authentication works
Chat requests always use a JWT bearer token created by your app.
Before you add the SDK, configure your backend or auth provider to mint a JWT for the signed-in user. That token must be intended for your getuserfeedback.com app:
aud: https://getuserfeedback.com/v1/apps/{appId}sub: your user idIf your getuserfeedback.com app uses a custom JWT claim mapping, include
exactly one claim that maps to userId. The examples use sub, which is the
default.
Your React app should fetch that token from your own auth flow, then pass it to the provider. The SDK sends the token on each API request:
Authorization: Bearer <token>getuserfeedback.com verifies the token and uses the signed user id to decide which conversations to return. See User authentication for issuer, JWKS, audience, and claim setup.
1. Install
npm install @getuserfeedback/chat-reactRequires react >= 18.
The package is headless and isomorphic. It can run in React DOM, React Native,
and most non-browser React environments that provide fetch.
2. Add the provider
Wrap the part of your app that renders chat:
import { GetUserFeedbackChatProvider } from "@getuserfeedback/chat-react";import type { ReactNode } from "react";export function ChatProvider({children,token,}: {children: ReactNode;token: string;}) {return (<GetUserFeedbackChatProviderclientOptions={{auth: {jwt: {token,},},}}>{children}</GetUserFeedbackChatProvider>);}The provider creates the chat client and makes it available to all hooks below
it. When your auth provider refreshes the token, render the provider with the
new token.
The default API base URL is https://api.getuserfeedback.com/v1.
3. List conversations
import { useConversationList } from "@getuserfeedback/chat-react";export function ConversationList({onSelect,}: {onSelect: (conversationId: string) => void;}) {const { conversations, hasMore, loadMore, status } = useConversationList();if (status === "loading") {return <p>Loading conversations...</p>;}if (conversations.length === 0) {return <p>No conversations yet.</p>;}return (<div>{conversations.map((conversation) => (<buttonkey={conversation.id}onClick={() => onSelect(conversation.id)}type="button">{conversation.latestMessage?.content.type === "text"? conversation.latestMessage.content.text: "Conversation"}</button>))}{hasMore ? (<button onClick={() => void loadMore()} type="button">Load more</button>) : null}</div>);}4. Open a conversation and send a message
import type { FormEvent } from "react";import { useState } from "react";import { useConversation } from "@getuserfeedback/chat-react";export function ConversationThread({conversationId,}: {conversationId: string;}) {const [text, setText] = useState("");const conversation = useConversation({ conversationId });async function submitMessage(event: FormEvent) {event.preventDefault();const trimmed = text.trim();if (!trimmed) return;setText("");await conversation.send({text: trimmed,});}if (conversation.status === "loading") {return <p>Loading messages...</p>;}return (<section>{conversation.hasMore ? (<button onClick={() => void conversation.loadMore()} type="button">Load older messages</button>) : null}<ol>{conversation.messages.map((message) => (<li key={message.id}><strong>{message.author}</strong>{" "}{message.content.type === "text" ? message.content.text : "Message"}</li>))}</ol><form onSubmit={submitMessage}><inputonChange={(event) => setText(event.target.value)}value={text}/><button disabled={conversation.sendStatus === "sending"} type="submit">Send</button></form></section>);}Current limits
- Realtime updates are not supported yet. Call
refresh()after an app action where you expect new messages. - Sending currently supports plain text only.
Advanced: proxy through your backend
By default, the SDK calls https://api.getuserfeedback.com/v1 directly from
your app. You can route requests through your own backend instead.
Pass an absolute baseUrl; the SDK uses that URL exactly, including any path
prefix:
<GetUserFeedbackChatProviderclientOptions={{baseUrl: "https://app.example.com/api/chat/v1",auth: {jwt: {token: appSessionToken,},},}}><AppRoutes /></GetUserFeedbackChatProvider>Your backend should authenticate that app session token, then call getuserfeedback.com with a JWT minted for your getuserfeedback.com app and that user.
Next
- Chat SDK reference — full client and hook surface
- JavaScript Chat SDK — use the isomorphic client without React
- User authentication — JWT setup and expected token audience