Documentation

Events and hooks

Subscribe to messages, presence, typing, and connection events from your own code.

The widget keeps its state in a Zustand store inside the bundle. There is no published hook export today — useAppmintChat and useChatStore are not pulled out of the chat-client repo because there is no npm package. To drive your own UI off the same data, you have two practical options:

  1. Custom events. Listen for events the bundle dispatches on window. Lightweight, works from any framework.
  2. Reach into the bundle. After AppmintChat.init runs, the bundle's store is available on window. Read it directly. More fragile — internal shapes can change.

Both patterns are sketches; for production usage, prefer option 1 plus your own state management.

No published hook

Earlier docs showed import { useAppmintChat } from '@appmint/chat'. That import does not work — there is no @appmint/chat package, and the bundle does not export hooks. The patterns below are the actual ways to integrate today.

Window event listeners

The simplest cross-framework integration. Listen for the events the bundle dispatches:

window.addEventListener('appmint-chat:message-sent', (e: any) => {
  analytics.track('chat.sent', { content: e.detail.content });
});

window.addEventListener('appmint-chat:message-received', (e: any) => {
  analytics.track('chat.received', { from: e.detail.from });
});

Confirm the exact event names against chat-client/src/ — the bundle dispatches a small set of appmint-chat:* events on visitor activity.

Reading the store directly

After init runs, the bundle attaches its store factory under window. From there you can subscribe to changes the same way Zustand stores normally work — but treat this as an internal API: shape changes on every release.

// After init has run:
const store = (window as any).__appmintChatStore;
if (store) {
  const unsubscribe = store.subscribe((state: any) => {
    if (state.messages.length !== lastSeen) { /* react */ }
  });
}

The exact key the bundle attaches to window is not documented as public surface — confirm in chat-client/src/index.tsx for the build you've deployed before relying on it.

What's in the store

The store is defined in src/chat-store.ts (ChatStoreState). The most useful fields:

FieldTypeDescription
messagesChatMessage[]

Every message in the active conversation. Each entry has chatId, messageId, content, from, to, type (user / agent / system / ai-assistant), sentTime, and optional deliveredTime, readTime, status, files.

sendMessage(message: string, files?: any[]) => void

Send a message as the current visitor. Files are an array of File objects or already-uploaded references.

isTypingboolean

True while a remote participant (agent or AI) is composing a reply.

aiStreamingMessagesRecord<string, AiStreamingState>

Partial AI replies as they stream in. Keyed by message id. Each value has content, isStreaming, tools (active tool calls), and optional error.

aiWaitingForResponseboolean

True between the moment the visitor sends a message and the first AI streaming chunk.

presenceMapRecord<string, PresenceEntry>

{ status, role, name, timestamp } per participant email. Driven by the onPresenceChange socket handler.

conversationStatusRecord<string, ConvoStatus>

Per-conversation status updates pushed by the server (assigned, transferred, closed, archived).

assignedAgentAgentAssignment | null

Set when a queue request resolves to a specific agent. Includes agent.email, agent.name, assignedAt.

queueStatusQueueStatus | null

While waiting in the agent queue: position, ahead, estimatedWaitSeconds. Polled until assignment.

userobject | null

The current visitor's customer record (after registration / signin).

tokenstring | null

The visitor's chat-scoped JWT.

myEmailstring | null

Convenience copy of user.data.email — used everywhere in the widget for "is this message from me?" checks.

isChatOpenboolean

Whether the floating panel is expanded. Toggle via setStateItem({ isChatOpen: !isChatOpen }).

cleanup() => void

Tear down the socket and reset state. Call before unmounting if you're remounting the widget with new props.

Socket events the bundle handles

The widget subscribes to these on the AppEngine ChatGateway socket (defined in src/components/chat-socket.tsx and the on* actions in chat-store.ts):

  • message — new chat message
  • typing / stop-typing — typing indicator from the other side
  • presence — participant online/away/offline
  • status — conversation status (assigned / closed / transferred)
  • chat-assigned / chat-transferred / agent-changed — agent routing
  • message-status-update — read receipts and delivery confirmations
  • ai-stream-start / ai-stream-chunk / ai-stream-tool-use / ai-stream-tool-result / ai-stream-end / ai-stream-error — AI streaming events
  • engage — proactive notices (toast outside the panel)
  • broadcast-start / broadcast-end — agent screen/camera broadcasts

Driving the widget from outside

To open the panel or pre-fill a message from outside the bundle, dispatch a custom event the bundle listens for, or reach into the store as described above. The recommended path (works without depending on internal store shape):

<button onclick="window.AppmintChat?.openPanel?.()">Help</button>

Confirm the helper names against chat-client/src/index.tsx — the bundle exposes a small set of imperative methods on window.AppmintChat for outside-the-panel control. Anything not exposed there requires forking the bundle.

Lifecycle

The widget mounts a single socket per page. Be careful with React Strict Mode in development — re-mounting the wrapper component will tear down and reconnect the socket during the double-mount cycle. Production builds aren't affected.

If you re-init the widget with a different orgId / configId, the existing socket is cleaned up automatically when the bundle observes the change.

When to use which integration path

  • Window events / store reads — building UI outside the floating panel (a sidebar, a notification bell, a custom dashboard).
  • chat-config record edits — branding, welcome copy, AI assistants, availability windows. No code change needed.
  • Forking the bundle — replacing parts of the panel UI (no slot API today; see Slots).