Create a custom AI chatbot with TalkJS and Claude

AI chatbots like Anthropic's Claude can provide automated, context-aware responses to all kinds of queries. With TalkJS, you can create a customizable chat application that integrates chatbot responses seamlessly into your user chat.

In this tutorial we'll show you how to use Anthropic's API to generate replies to user messages using the Claude family of language models. We'll then use TalkJS's REST API and webhooks to add Claude's responses directly to your chat:

Chatbot demo. The user asks questions about TalkJS and gets replies generated by the Anthropic API.

To follow along with this tutorial, you will need:

We’ll build up the feature step by step in the following sections. If you would rather see the complete example code, see the Github repo for this tutorial.

First, we'll set up a TalkJS chat in our frontend code. The details will depend on exactly how you integrate TalkJS into your current application, but for our example we'll use TalkJS's JavaScript SDK to create a conversation between a user and a bot, and display it with our prebuilt chatbox UI:

Talk.ready.then(function () {
  const me = new Talk.User({
    id: "claudeExampleUser",
    name: "Alice",
    email: "alice@example.com",
    role: "default",
    photoUrl: "https://talkjs.com/images/avatar-1.jpg",
  });
  const talkSession = new Talk.Session({
    appId: "<APP_ID>", // replace with your TalkJS app ID
    me: me,
  });

  const bot = new Talk.User({
    id: "claudeExampleBot",
    name: "Bot 🤖",
    email: "bot@example.com",
    role: "default",
    photoUrl: "https://talkjs.com/new-web/talkjs-logo.svg",
    welcomeMessage:
      "Hi, I'm a friendly chatbot! I'll use Anthropic's chat API to assist with your queries. How can I help?",
  });

  var conversation = talkSession.getOrCreateConversation(
    "claudeExampleConversation"
  );
  conversation.setParticipant(me);
  conversation.setParticipant(bot);

  const chatbox = talkSession.createChatbox();
  chatbox.select(conversation);
  chatbox.mount(document.getElementById("talkjs-container"));
});

We've included a welcomeMessage for the bot to start the conversation off.

Get notified about new messages

We'll eventually want the bot to reply to any messages that the user sends in the conversation. To do this, we'll first enable TalkJS webhooks, which allow the TalkJS server to notify your server when a message is sent.

Webhooks let you use an event-driven architecture, where you get told about events when they happen rather than having to constantly check for new messages. There are lots of events you can listen for, but we’re only interested in new messages being sent.

Webhooks are server-side only, so you’ll need a web server. We’ll be using Express in this tutorial, but feel free to use your favorite web server library instead. The following code sets up an Express server with a POST endpoint at /onMessageSent that logs incoming events from the TalkJS server to the terminal:

import express from "express";
const app = express().use(express.json()); // creates http server

app.listen(3000, () => console.log("Server is up"));

app.post("/onMessageSent", (req, res) => {
  console.log(req.body);
  res.status(200).end();
});

For TalkJS to communicate with your server, you must expose it to the internet. This can be very difficult when developing locally, with endless firewalls and port forwarding to set up. Instead, we’ll use ngrok to create a secure tunnel to your local server. See our tutorial on How to integrate ngrok with TalkJS for instructions on how to install ngrok.

Once you have installed ngrok, run the following command:

ngrok http 3000

This command starts a secure tunnel to your local port 3000. The output should include the URL that ngrok exposes:

Forwarding                    https://<YOUR_SITE>.ngrok-free.app -> http://localhost:3000

You’re now ready to enable webhooks. You can do this in the Settings section of the TalkJS dashboard, under Webhooks. Paste the ngrok URL into the Webhook URL field, including the /onMessageSent path: https://<YOUR_SITE>.ngrok-free.app/talkjs.

Select the message.sent option:

The list of webhook options in the TalkJS dashboard.

TalkJS will now send a web request to your server when a message is sent. To test this, write a message in your chat UI. You should see the event in your server’s console.

Call the Anthropic API

Next, we'll call the Anthropic create message API to generate replies to the user's messages.

The API call uses a secret key, so you'll need to call it from your backend server to avoid exposing the key.

First, install the @anthropic-ai/sdk package:

npm install @anthropic-ai/sdk

Then, as a first test of the API, add the following to your server code:

import Anthropic from "@anthropic-ai/sdk";

const anthropicSecretKey = "<ANTHROPIC_SECRET_KEY>";

const anthropic = new Anthropic({
  apiKey: anthropicSecretKey,
});

const messageHistory = [
  {
    role: "user",
    content:
      "You are a helpful assistant. Please provide short, concise answers.",
  },
];

async function getReply(messageHistory) {
  const response = await anthropic.messages.create({
    model: "claude-3-haiku-20240307",
    messages: messageHistory,
    max_tokens: 1024,
  });

  return response.content[0].text;
}

The getReply function calls the Anthropic API to create a message in response, given a messageHistory list that represents the conversation so far.

In this first test example, we send a messageHistory list that has a single message with a role of user. This initial user message gives some basic instructions on the type of replies we'd like to receive.

We also need to select one of Anthropic's language models to generate the reply. In this example, we use the Haiku 3 model, claude-3-haiku-20240307, which is faster and cheaper but less capable than the Sonnet models. You can switch this out for a different model if you like. See Anthropic's list of models for more choices.

Next, update your app.post call to call the getReply function:

const botId = "chatbotExampleBot";

app.post("/onMessageSent", async (req, res) => {
  if (senderId != botId) {
    const reply = await getReply(messageHistory);
    console.log(reply);
  }
  res.status(200).end();
});

We do not call the Anthropic API for messages from the bot, or it will get stuck in a loop of responding to itself!

Restart your server, and send another message. You should see a response logged to your terminal. At the moment, the response is very generic (something like "Okay, I'll provide short, concise answers."),because it only has the instructions in the initial user message to work with. We want to instead give it the full conversation so far, so that it can reply with something relevant. To do this, replace your app.post call with the following code, which creates a message history for each conversation:

const allMessageHistory = {};

app.post("/onMessageSent", async (req, res) => {
  const convId = req.body.data.conversation.id;
  const messageText = req.body.data.message.text;
  const senderId = req.body.data.sender.id;

  if (!(convId in allMessageHistory)) {
    allMessageHistory[convId] = [
      {
        role: "user",
        content:
          "You are a helpful assistant. Please provide short, concise answers.",
      },
    ];
  }
  const messageHistory = allMessageHistory[convId];

  if (senderId == botId) {
    // Bot message
    messageHistory.push({ role: "assistant", content: messageText });
  } else {
    // User message
    messageHistory.push({ role: "user", content: messageText });
    getReply(messageHistory);
  }

  res.status(200).end();
});

You should now see a relevant reply logged to the terminal when you restart the server and send a message.

Call the TalkJS API

The final step is to display the bot's replies as messages in the chatbox. To do this, create a function to call the TalkJS REST API to send messages from the bot:

const appId = "<APP_ID>";
const talkJSSecretKey = "<TALKJS_SECRET_KEY>";
const basePath = "https://api.talkjs.com";
const conversationId = "claudeExampleConversation";

async function sendMessage(text) {
  return fetch(
    `${basePath}/v1/${appId}/conversations/${conversationId}/messages`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${talkJSSecretKey}`,
      },
      body: JSON.stringify([
        {
          text: text,
          sender: botId,
          type: "UserMessage",
        },
      ]),
    }
  );
}

As with the Anthropic API, you should call the TalkJS API from your backend server to avoid exposing your secret key. You can find your secret key along with your app ID in the TalkJS dashboard under Settings.

Now you can call the sendMessage function after getReply:

app.post("/getMessages", async (req, res) => {
  // ...

  if (senderId == botId) {
    // Bot message
    messageHistory.push({ role: "assistant", content: messageText });
  } else {
    // User message
    messageHistory.push({ role: "user", content: messageText });
    const reply = await getReply(messageHistory);
    await sendMessage(convId, reply);
  }
  res.status(200).end();
});

The responses from the Claude now appear in the chatbox as messages from the bot:

Chatbox with an example question and reply.

Customize your chat

You now have a working demonstration of how to integrate a Claude-powered chatbot into your TalkJS chat!

You may want to customize your chat further. For example, you could include an indicator in your chat that the bot is generating a response. See our blog post on How to add a custom typing indicator for a chatbot for information on ways to do this.

You can also use all our other features, such as custom themes, action buttons and HTML Panels, to control exactly how you want the chat to look and behave.

Summary

To recap, in this tutorial we have:

  • Created a chat between a user and a bot
  • Set up a web server to receive webhook events from the TalkJS server when new messages are sent
  • Called the Anthropic API to generate replies to new user messages
  • Called the TalkJS API to send the replies as messages in the chat

For the full example code for this tutorial, see our Github repo.

If you want to learn more about TalkJS, here are some good places to start: