Skip to main content

Initial Messages (initMessages)

initMessages lets you seed the chatbot with a set of conversation history at initialization, so the user already sees content when they open the chatbot. Common uses:

  • Showing a sample conversation
  • Loading history messages from your backend
  • A guided opening message
Pair with autoResetChannel={false}, and only for a not-yet-existing channel

To keep your initMessages, pair them with autoResetChannel={false}:

<Chatbot
initMessages={messages}
autoResetChannel={false}
...
/>

Since 0.3.x, mount first checks the channel metadata: if the customChannelId already exists on the backend, it is always restored and the server history is replayed, overriding initMessages (regardless of autoResetChannel). So initMessages is best paired with a customChannelId the backend has not created yet (pure client-side seeding). See Auto Reset Channel.

Types

initMessages accepts ConversationMessage[], where each message is one of the following union members:

import type { ConversationMessage } from "@asgard-js/core";
// ConversationMessage = ConversationUserMessage | ConversationBotMessage | ...

User message

import type { ConversationUserMessage } from "@asgard-js/core";

const userMsg: ConversationUserMessage = {
type: "user",
messageId: "msg-1", // unique id for each message
text: "Hi!",
blobIds: [],
time: new Date("2026-01-01T10:00:00"),
};

Bot message

A bot message requires a complete message object (matching the message shape returned over SSE):

import { EventType, MessageTemplateType } from "@asgard-js/core";
import type { ConversationBotMessage } from "@asgard-js/core";

const botMsg: ConversationBotMessage = {
type: "bot",
messageId: "msg-2",
eventType: EventType.MESSAGE_COMPLETE, // marks the message as completed
isTyping: false,
typingText: null,
message: {
messageId: "msg-2",
replyToCustomMessageId: "",
text: "Hello! How can I help you?",
payload: null,
isDebug: false,
idx: 0,
template: {
type: MessageTemplateType.TEXT,
text: "Hello! How can I help you?",
quickReplies: [],
},
},
time: new Date("2026-01-01T10:00:05"),
raw: "",
};

Full Example (Next.js App Router)

"use client";

import dynamic from "next/dynamic";
import "@asgard-js/react/style";
import { useMemo } from "react";
import { EventType, MessageTemplateType } from "@asgard-js/core";
import type { ConversationMessage } from "@asgard-js/core";

const Chatbot = dynamic(
() => import("@asgard-js/react").then((m) => m.Chatbot),
{ ssr: false },
);

function makeBotMessage(
id: string,
text: string,
time: Date,
): ConversationMessage {
return {
type: "bot",
messageId: id,
eventType: EventType.MESSAGE_COMPLETE,
isTyping: false,
typingText: null,
message: {
messageId: id,
replyToCustomMessageId: "",
text,
payload: null,
isDebug: false,
idx: 0,
template: {
type: MessageTemplateType.TEXT,
text,
quickReplies: [],
},
},
time,
raw: "",
};
}

export default function ChatPage() {
const initMessages = useMemo<ConversationMessage[]>(
() => [
{
type: "user",
messageId: "pre-1",
text: "Hi!",
blobIds: [],
time: new Date("2026-01-01T10:00:00"),
},
makeBotMessage(
"pre-2",
"Hello! How can I help you?",
new Date("2026-01-01T10:00:05"),
),
],
[],
);

return (
<div style={{ height: "100vh" }}>
<Chatbot
title="My Chatbot"
customChannelId="user-123"
config={{
botProviderEndpoint:
"https://api.asgard-ai.com/ns/{namespace}/bot-provider/{botProviderId}",
}}
initMessages={initMessages}
autoResetChannel={false}
/>
</div>
);
}
note

useMemo keeps the initMessages array referentially stable across re-renders, avoiding unnecessary channel resets.

Further Reading