Headless Usage
If the built-in <Chatbot> doesn't fit your design, skip it entirely
and build your own UI on top of the useChannel hook. The chat panel
below is 100% custom — none of the SDK's stylesheets are imported.
Fully Custom UI
Skip the <Chatbot> component entirely. Use the useChannel hook to read the conversation and call sendMessage, then build whatever UI matches your brand.
The interface below is 100% custom — none of the SDK's built-in chat UI is used.
Loading...
Example
import { useMemo, useState } from "react";
import { AsgardServiceClient } from "@asgard-js/core";
import { useChannel } from "@asgard-js/react";
export function HeadlessChat() {
const client = useMemo(
() =>
new AsgardServiceClient({
botProviderEndpoint: "https://...",
}),
[],
);
const { conversation, sendMessage, isConnecting } = useChannel({
client,
customChannelId: "my-channel",
defaultIsOpen: true,
});
const messages = conversation
? Array.from(conversation.messages.values())
: [];
return (
<div>
{messages.map((msg) => {
if (msg.type === "user") return <div key={msg.messageId}>{msg.text}</div>;
if (msg.type === "bot") return <div key={msg.messageId}>{msg.message?.text}</div>;
if (msg.type === "tool-call")
return <div key={msg.messageId}>🔧 {msg.toolName}</div>;
return null;
})}
{/* Your own input → sendMessage({ text }) */}
</div>
);
}
useChannel Return Value
| Field | Description |
|---|---|
conversation | Current Conversation containing a messages Map |
sendMessage | Send a message (supports text / payload / blobIds) |
resetChannel | Reset the channel and start a new conversation |
closeChannel | Close the SSE connection |
isConnecting | Whether the channel is connecting |
isResetting | Whether the channel is resetting |
Message Types
All messages share the ConversationMessage union — branch on type
when rendering:
user— sent by the userbot— bot reply; access SDK template data viamessage.templatetool-call— agent tool invocationerror— connection or runtime error