Skip to main content
Build a working chat in React: a message list, a typing indicator, and a composer, connected to your Typewise AI Agent. You’ll have it running in a few minutes and can style it however you like afterwards.
Not using React? Follow Plain HTML and JavaScript or see Other frameworks. The concepts are the same.

Prerequisites

  • A React 18 or later app
  • Your client ID, from Behavior → Channels → Chat → Installation
  • If your chat has a Domain allowlist, localhost added to it. While the list is empty, every origin is allowed.

Using an AI coding tool? Copy this prompt, or open it in Cursor.

Open in Cursor

Build the chat

You’ll add three files:
src
chat.ts
useChat.ts
Chat.tsx
1

Install the SDK

2

Create the client

Create one client at module scope and import it wherever you need it. Each client holds one visitor session and one real-time connection.
src/chat.ts
3

Connect it to React

The client is an external store, so useSyncExternalStore is all you need. resume() restores the visitor’s open conversation and loads the greetings.
src/useChat.ts
4

Render the conversation

src/Chat.tsx
Render <Chat /> anywhere in your app.
5

Send a test message

Start your dev server, open the page, and ask a question. The greeting appears first, then your message, a “Thinking…” indicator, and the AI Agent’s reply. Reload the page: the conversation is restored.

What’s happening

  • messages holds greetings, history, and live messages in order. Your own message appears at once with status: "sending", then switches to "sent".
  • Message keys. A message’s id changes when the server confirms it. Its dedupeKey stays the same, so it makes a stable React key.
  • activity tells you what to show as a typing indicator: the AI Agent working, a Human Agent typing, or the conversation waiting for one.
  • conversation is null until the first message. Once a conversation closes, isClosed is true and the visitor can start a new one.
For every field, see Render messages and activity.

Use it with Next.js

createClient doesn’t touch window or storage at import time, so the module is safe to import on the server. Add "use client" at the top of Chat.tsx, because it uses hooks.

Before you go live

  • One client per app. Create it at module scope, not inside a component, so re-renders don’t open new connections.
  • Catch errors. Methods reject with a TypewiseError. Listen to chat.on("error", …) for background failures.
  • Don’t retry sends automatically. Sending isn’t idempotent, so the SDK never retries. Show failed messages and let the visitor send again.
  • Send page context. Tell the AI Agent what the visitor is looking at with context variables.
  • Verify identity. If actions or lookups use the Trusted only check, pass signed variables.
  • Forget the visitor on logout. Call chat.resetSession() so the next person on the device doesn’t see the conversation.
  • Allow your domains. Add production origins to the Domain allowlist, and to your Content Security Policy if you have one.

Next steps

Share page context

Tell the AI Agent what the visitor is doing

Render messages and activity

Quick actions, Human Agent handoff, and closed conversations

Attachments, surveys, and verification

Files, satisfaction ratings, and email codes

Examples

Complete apps you can copy