FindableChat

A complete AI chat widget with streaming responses, citations, and follow-up suggestions.

Live Chat Demo
Try: “What ventilation system is installed?Try: “Tell me about fire safety measuresTry: “Show the electrical distribution

Building Assistant

Ask a question to get started

Basic Usage

<FindableChat buildingId="bld-789" />

Full Example

<FindableChat
  buildingId="bld-789"
  placeholder="Ask about your building..."
  title="Ask Findable"
  language="en"
  reasoningEffort="medium"
  showCitations={true}
  showFollowUps={true}
  className="my-chat"
  onError={(err) => console.error(err)}
  onThreadCreated={(threadId) => saveThreadId(threadId)}
  onCitationClick={(citation) => openDocument(citation.documentId)}
  renderMessage={(msg) => <CustomMessage {...msg} />}
/>

Props

PropTypeDefaultDescription
buildingId*stringThe building to ask questions about
placeholderstring'Ask about your building...'Input placeholder text
titlestring'Ask Findable'Header title. Set to empty string to hide the header.
language'en' | 'no' | 'nb' | 'nn'Language for AI responses
reasoningEffort'low' | 'medium' | 'high''medium'AI reasoning effort level
showCitationsbooleantrueShow inline citation badges
showFollowUpsbooleantrueShow follow-up suggestion chips
classNamestringAdditional CSS class
onError(error: Error) => voidError callback
onThreadCreated(threadId: string) => voidCalled when a new conversation thread starts
onCitationClick(citation: AskCitation) => voidCalled when a citation badge is clicked
renderMessage(msg: ChatMessage) => JSX.ElementCustom message renderer for full UI control

Headless Hook: useChat

For full control over the UI, use the useChat hook directly:

import { useChat } from '@findable-ai/react';

function CustomChat() {
  const {
    messages,
    status,
    followUpSuggestions,
    threadId,
    sendMessage,
    cancelStream,
    clearChat,
  } = useChat({ buildingId: 'bld-789' });

  return (
    <div>
      {messages.map((msg) => (
        <div key={msg.id} className={msg.role}>
          {msg.content}
          {msg.isStreaming && <span>...</span>}
        </div>
      ))}
      <input
        onKeyDown={(e) => {
          if (e.key === 'Enter') {
            sendMessage(e.currentTarget.value);
            e.currentTarget.value = '';
          }
        }}
      />
      {status === 'streaming' && (
        <button onClick={cancelStream}>Stop</button>
      )}
    </div>
  );
}

useChat Return Value

PropTypeDefaultDescription
messagesChatMessage[]All messages in the conversation
statusChatStatus'idle' | 'starting' | 'streaming' | 'finished' | 'failed'
followUpSuggestionsstring[]Suggested follow-up questions
threadIdstring | nullCurrent conversation thread ID
sendMessage(query, docIds?) => voidSend a message
cancelStream() => voidCancel an in-flight stream
clearChat() => voidClear all messages and start a new thread