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
autoResetChannel={false}, and only for a not-yet-existing channelTo 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>
);
}
useMemo keeps the initMessages array referentially stable across re-renders,
avoiding unnecessary channel resets.
Further Reading
- Auto Reset Channel — details on
autoResetChannel - Headless mode — achieve the same with the
initMessagesargument ofuseChannel