Skip to main content
The useChat hook provides the logic to build a custom AI-powered chat component for conversational search experiences.

Import

import { useChat } from 'react-instantsearch';

Parameters

apiKey
string
required
Your Algolia API key with chat permissions.
const { messages, sendMessage } = useChat({
  apiKey: 'your-api-key',
});
chatModel
string
The chat model to use.
conversationId
string
ID for the conversation to maintain context.

Returns

messages
Message[]
The list of chat messages in the conversation.
const { messages } = useChat({ apiKey: 'key' });
sendMessage
(message: string) => void
Function to send a message to the chat.
const { sendMessage } = useChat({ apiKey: 'key' });
sendMessage('What are your best-selling products?');
isLoading
boolean
Whether a response is currently being generated.

Examples

Basic Chat Interface

import { useChat } from 'react-instantsearch';
import { useState } from 'react';

function ChatSearch() {
  const { messages, sendMessage, isLoading } = useChat({
    apiKey: process.env.ALGOLIA_CHAT_API_KEY,
  });
  const [input, setInput] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    if (input.trim()) {
      sendMessage(input);
      setInput('');
    }
  };

  return (
    <div className="chat-interface">
      <div className="messages">
        {messages.map((message, index) => (
          <div
            key={index}
            className={`message ${message.role}`}
          >
            <p>{message.content}</p>
          </div>
        ))}
        {isLoading && <div className="typing-indicator">...</div>}
      </div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={input}
          onChange={(e) => setInput(e.target.value)}
          placeholder="Ask me anything..."
          disabled={isLoading}
        />
        <button type="submit" disabled={isLoading || !input.trim()}>
          Send
        </button>
      </form>
    </div>
  );
}

Chat with Product Results

import { useChat, useHits } from 'react-instantsearch';
import { useState } from 'react';

function ConversationalSearch() {
  const { messages, sendMessage, isLoading } = useChat({
    apiKey: process.env.ALGOLIA_CHAT_API_KEY,
  });
  const { items } = useHits();
  const [input, setInput] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    if (input.trim()) {
      sendMessage(input);
      setInput('');
    }
  };

  return (
    <div className="conversational-search">
      <div className="chat-panel">
        <div className="messages">
          {messages.map((message, index) => (
            <div key={index} className={`message ${message.role}`}>
              {message.content}
            </div>
          ))}
        </div>
        <form onSubmit={handleSubmit}>
          <input
            value={input}
            onChange={(e) => setInput(e.target.value)}
            placeholder="Ask about products..."
          />
          <button type="submit">Send</button>
        </form>
      </div>
      <div className="results-panel">
        <h3>Recommended Products</h3>
        <div className="products">
          {items.map((item) => (
            <div key={item.objectID} className="product">
              <img src={item.image} alt={item.name} />
              <h4>{item.name}</h4>
              <p>${item.price}</p>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

TypeScript

import { useChat } from 'react-instantsearch';
import type { UseChatProps } from 'react-instantsearch';

function ChatInterface(props: UseChatProps) {
  const { messages, sendMessage } = useChat(props);

  return (
    <div>
      {messages.map((message, index) => (
        <div key={index}>{message.content}</div>
      ))}
    </div>
  );
}