Embed Chat to Website
Embed the Qlar chat widget on your website so visitors can talk to your agent without leaving your page. By the end of this tutorial you will have a working chat widget — either embedded inline inside a container or as a floating button fixed to a corner of the viewport — in a plain HTML file or a React/TypeScript application.
How It Works
The Qlar widget is a standard Web Component (<pusaka-container>). You load one script tag from Qlar's CDN and then place the <pusaka-container> element anywhere in your HTML or JSX. No build step, no npm package, and no changes to your backend are required.
When the element renders it connects to your agent and handles the entire conversation UI. You control its appearance and behaviour through HTML attributes.
Prerequisites
- A Qlar account with at least one agent created and published.
- A website or application where you can add a
<script>tag to the page<head>.
Step 1 — Open the Widget Page
In the Qlar CMS, click the hamburger menu (☰) in the top-left corner to open the sidebar, then click Widget.
The Widget page opens and shows the embed documentation for the currently active agent, including its Agent ID — you will need this value in the next step.
Step 2 — Copy Your Agent ID
Your Agent ID is a unique identifier that tells the widget which agent to connect to.
On the Widget page, locate the code snippets shown. The data-agent-id attribute in every snippet already contains your active agent's ID. Copy that value — it looks like a UUID, for example a1b2c3d4-e5f6-7890-abcd-ef1234567890.
Alternative: You can also find the Agent ID on the agent's Settings page.
Step 3 — Add the Script Tag
Add the Qlar Container script to the <head> of your HTML page. This registers the <pusaka-container> custom element in the browser.
<script
type="module"
crossorigin
src="https://app-container-prod.pusaka.ai/pusaka-container.mjs"
></script>
Load the script once per page — you can then place as many <pusaka-container> elements as you need in the <body>.
Step 4 — Embed as an Inline Widget
The inline mode renders the widget inside a container you control. The element fills the width and height of its parent element, so wrap it in a <div> with explicit dimensions.
Here is a complete working HTML page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My Website</title>
<script
type="module"
crossorigin
src="https://app-container-prod.pusaka.ai/pusaka-container.mjs"
></script>
</head>
<body>
<!-- Give the parent a size so the widget has space to render -->
<div style="width: 400px; height: 600px;">
<pusaka-container
data-agent-id="YOUR_AGENT_ID"
data-theme="system"
data-app-mode="chat"
></pusaka-container>
</div>
</body>
</html>
Replace YOUR_AGENT_ID with the value you copied in Step 2.
Open the page in a browser — you should see the chat interface appear inside the <div>.
Step 5 — Embed as a Floating Widget
The floating mode renders a FAB (Floating Action Button) fixed to a corner of the viewport. The button is always visible while scrolling; clicking it opens or closes an animated chat panel. The <pusaka-container> element itself takes up no space in the document flow, so you can drop it anywhere in <body> without a wrapper.
Minimal example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My Website</title>
<script
type="module"
crossorigin
src="https://app-container-prod.pusaka.ai/pusaka-container.mjs"
></script>
</head>
<body>
<!-- Your page content here -->
<pusaka-container
data-agent-id="YOUR_AGENT_ID"
data-mode="floating"
data-position="bottom-right"
data-chat-title="Your Agent Name"
></pusaka-container>
</body>
</html>
Fully customized example
<pusaka-container
data-agent-id="YOUR_AGENT_ID"
data-theme="dark"
data-app-mode="chat"
data-mode="floating"
data-position="bottom-right"
data-offset-x="24px"
data-offset-y="24px"
data-chat-width="400px"
data-chat-height="600px"
data-chat-title="Your Agent Name"
></pusaka-container>
Tip: On viewports narrower than 480 px the floating panel automatically fills the entire screen regardless of
data-chat-widthanddata-chat-height, so it works on mobile without extra configuration.
Step 6 — Customize Appearance
All <pusaka-container> attributes are listed below.
| Attribute | Default | Options / Notes |
|---|---|---|
data-agent-id | (required) | The Agent ID copied in Step 2. |
data-theme | system | system · light · dark |
data-app-mode | full-app | full-app (chat + top bar) · chat (chat only) |
data-enable-autofocus | true | true · false — whether the chat input receives focus automatically on load and after each agent reply. Set to false to prevent the page from scrolling to the widget. |
data-mode | (inline) | floating — renders a fixed FAB. Omit for inline mode. |
data-position | bottom-right | bottom-right · bottom-left · top-right · top-left — floating only. |
data-offset-x | 20px | Any CSS length — horizontal gap between FAB and viewport edge. Floating only. |
data-offset-y | 20px | Any CSS length — vertical gap between FAB and viewport edge. Floating only. |
data-chat-width | 380px | Any CSS length — width of the floating chat panel. Floating only. |
data-chat-height | 580px | Any CSS length — height of the floating chat panel. Floating only. |
data-chat-title | Chat | Text shown in the floating panel header. Floating only. |
Note:
data-modecontrols the container layout (inline vs floating).data-app-modecontrols the chat interface display (full app vs chat-only). They are independent of each other.
Step 7 — Embed in a React App (Vite / CRA — TypeScript)
React does not recognise custom HTML elements by default. Follow the four sub-steps below.
7A — Add the script to public/index.html
In your React project, open public/index.html and add the script inside <head>:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>React App</title>
<script
type="module"
crossorigin
src="https://app-container-prod.pusaka.ai/pusaka-container.mjs"
></script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
7B — Declare the custom element type
Create (or edit) src/custom-elements.d.ts to tell TypeScript about the <pusaka-container> element:
/// <reference types="vite/client" />
import React from "react";
declare global {
namespace JSX {
interface IntrinsicElements {
"pusaka-container": React.DetailedHTMLProps<
React.HTMLAttributes<HTMLElement>,
HTMLElement
> & {
"data-agent-id"?: string;
"data-theme"?: string;
"data-app-mode"?: string;
"data-enable-autofocus"?: string;
"data-mode"?: string;
"data-position"?: string;
"data-offset-x"?: string;
"data-offset-y"?: string;
"data-chat-width"?: string;
"data-chat-height"?: string;
"data-chat-title"?: string;
};
}
}
}
export {};
7C — Use <pusaka-container> in a component
Here is a complete example of a chat panel with manual open/expand/close controls:
import { useState } from "react";
import { MessageCircle, X, Maximize2, Minimize2 } from "lucide-react";
export default function ChatAgent() {
const [isOpen, setIsOpen] = useState(false);
const [isExpanded, setIsExpanded] = useState(false);
return (
<div className="fixed bottom-4 right-4 z-50">
<button
onClick={() => setIsOpen((prev) => !prev)}
className="bg-purple-600 text-white p-3 rounded-full shadow-lg hover:bg-purple-700 transition-colors"
>
{isOpen ? <X size={24} /> : <MessageCircle size={24} />}
</button>
<div
className={`${
isExpanded
? "fixed inset-0 w-full h-full bg-white"
: "fixed bottom-20 right-4 w-full max-w-xs sm:max-w-sm md:max-w-md h-[500px]"
} rounded-lg shadow-xl flex flex-col transition-all duration-300 ${
isOpen ? "block" : "hidden"
}`}
>
{/* Header */}
<div className="flex items-center justify-between p-4 bg-purple-600 text-white">
<h3 className="font-semibold">Chat with Your Agent</h3>
<div className="flex items-center space-x-2">
<button
onClick={() => setIsExpanded((prev) => !prev)}
className="hover:text-purple-300"
>
{isExpanded ? <Minimize2 size={20} /> : <Maximize2 size={20} />}
</button>
<button
onClick={() => setIsOpen(false)}
className="hover:text-purple-300"
>
<X size={20} />
</button>
</div>
</div>
<div className="flex-1 overflow-hidden">
<pusaka-container
data-agent-id="YOUR_AGENT_ID"
data-app-mode="chat"
data-theme="dark"
></pusaka-container>
</div>
</div>
</div>
);
}
7D — Or use the built-in floating mode
If you do not need a custom wrapper, use data-mode="floating" as a simple drop-in. Place the tag anywhere in your JSX — the widget handles everything:
export default function App() {
return (
<>
{/* Your app content */}
<pusaka-container
data-agent-id="YOUR_AGENT_ID"
data-mode="floating"
data-position="bottom-right"
data-chat-title="Your Agent Name"
></pusaka-container>
</>
);
}
Next Steps
- Test the widget — use the Simulation section in Qlar CMS to verify your agent's responses before going live.
- Refine your agent's personality — adjust the tone, mission, and interaction style in the Persona & Behavior section.
- Connect more channels — add your agent to WhatsApp or Instagram via the Channel section in the CMS sidebar.