Overview
The Weav Chatbot Widget is a lightweight, embeddable chat interface that lets you add AI-powered customer support to any website.
It renders a customizable launcher button that opens a chat interface in an iframe, and it can be controlled through a simple JavaScript API.
The configuration options below are to provide developers with more flexibility of the Weav chatbot experience. Most of these features can be controlled within the Weav application for non developers.
Features
- Fully customizable appearance, including colors, icons, text, position, and theme
- Mobile responsive with optimized layouts
- Accessible, including ARIA labels and keyboard support with the
Esc key
- Lightweight with minimal performance impact
- Secure iframe isolation
- JavaScript API for initialization, teardown, and event handling
Installation
Basic usage
- Include the widget script near the end of your
<body> tag.
- Call
window.WeavWidget.init() once the script has loaded.
<script src="https://app.weav.com/widget.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
if (!window.WeavWidget) {
console.error('Weav Chat Widget failed to load')
return
}
window.WeavWidget.init({
agentSlug: '{agent slug}',
})
})
</script>
The widget automatically injects its mount node and lazy-loads the iframe the first time it opens.
Quick start example
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
</head>
<body>
<!-- Your page content -->
<script src="https://app.weav.com/widget.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
window.WeavWidget?.init({
agentSlug: '{agent slug}',
branding: {
accent_color: '#007bff',
},
})
})
</script>
</body>
</html>
JavaScript API
Once loaded, the script registers a single global object: window.WeavWidget.
| Method | Description |
|---|
init(options?: InitializeOptions) | Mounts the widget with the provided configuration. Calling init() again tears down the current instance and mounts a fresh one with the new options. |
destroy() | Unmounts the widget, clears queued actions, and removes any DOM nodes created by the widget. |
open() | Programmatically opens the widget. Throws if called before init(). |
close() | Programmatically closes the widget. Throws if called before init(). |
sendMessage(message: string) | Sends a message to the chat on behalf of the visitor. Call open() first if the widget is not already visible. Throws if called before init() or with an empty string. |
on(event, listener) | Subscribes to widget lifecycle events: opened and closed. Returns an unsubscribe function. |
off(event, listener) | Unsubscribes a previously registered listener. |
isInitialized() | Returns true when the widget is currently mounted. |
Configuration options
Pass configuration through the object supplied to init().
agentSlug is required. All other properties are optional.
Top-level options
| Option | Type | Default | Description | |
|---|
agentSlug | string | Required | Unique identifier for your AI agent. You can get this from https://app.weav.com/agents → Chat tab | |
launcherZIndex | `number | string` | 2147483000 | CSS z-index for widget elements |
launcherHidden | boolean | false | Hides the launcher button when set to true. The widget can still be opened programmatically with open() | |
mountElement | HTMLElement | Auto-created | Optional DOM node to render into instead of creating one automatically | |
Branding options
Use the branding object to customize the launcher button.
| Option | Type | Default | Description | |
|---|
branding.accent_color | string | #0f172a | Primary accent color for the launcher background | |
branding.icon | `string | null` | null | Icon shown on the launcher. Can be an emoji, text, or an image URL |
branding.name | `string | null` | null | Name used in the launcher button ARIA label, such as Chat with AI Assistant |
Use the widget object to customize behavior and appearance.
| Option | Type | Default | Description | |
|---|
widget.mode | enum | light | Visual theme of the widget | |
widget.button_icon | enum | chat | Icon type for the launcher button | |
widget.button_position | enum | bottom-right | Position of the launcher button | |
widget.welcome_message | `string | null` | Hello! How can I help you today? | Welcome message shown in the chat interface |
widget.message_placeholder | `string | null` | Ask me anything... | Placeholder text for the message input |
widget.footer_text | `string | null` | null | Custom footer text shown in the chat interface |
| Value | Description |
|---|
light | Light theme with a white background |
dark | Dark theme with a dark background |
| Value | Description |
|---|
chat | Default chat icon |
| Value | Description |
|---|
bottom-right | Bottom-right corner of the viewport |
bottom-left | Bottom-left corner of the viewport |
Examples
Minimal configuration
<script src="https://app.weav.com/widget.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
window.WeavWidget?.init({ agentSlug: '{agent slug}' })
})
</script>
Custom branding
<script src="https://app.weav.com/widget.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
window.WeavWidget?.init({
agentSlug: '{agent slug}',
branding: {
accent_color: '#8b5cf6',
icon: '🤖',
name: 'AI Assistant',
},
})
})
</script>
Custom icon using an image URL
<script src="https://app.weav.com/widget.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
window.WeavWidget?.init({
agentSlug: '{agent slug}',
branding: {
accent_color: '#10b981',
icon: 'https://example.com/logo.png',
},
})
})
</script>
<script src="https://app.weav.com/widget.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
window.WeavWidget?.init({
agentSlug: '{agent slug}',
widget: {
button_position: 'bottom-left',
},
})
})
</script>
<script src="https://app.weav.com/widget.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
window.WeavWidget?.init({
agentSlug: '{agent slug}',
widget: {
mode: 'dark',
},
})
})
</script>
<script src="https://app.weav.com/widget.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
window.WeavWidget?.init({
agentSlug: '{agent slug}',
widget: {
welcome_message: 'Welcome! How can we assist you?',
message_placeholder: 'Ask a question...',
footer_text: 'Powered by Weav',
},
})
})
</script>
High z-index for complex sites
<script src="https://app.weav.com/widget.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
window.WeavWidget?.init({
agentSlug: '{agent slug}',
launcherZIndex: 999999,
})
})
</script>
Programmatic control
- Use
window.WeavWidget.open() to open the widget without user interaction
- Use
window.WeavWidget.close() to close it programmatically
- Use
window.WeavWidget.destroy() to remove the widget entirely
- Use
window.WeavWidget.init(newOptions) at any time to re-initialize the widget with updated configuration\
Queued open() and close() calls made immediately after init() run as soon as the React tree is ready, so you do not need to wait for a callback.
Events
Use on() and off() to react to widget lifecycle events.
<script>
document.addEventListener('DOMContentLoaded', () => {
const widget = window.WeavWidget
if (!widget) return
widget.init({ agentSlug: '{agent slug}' })
const unsubscribeOpened = widget.on('opened', () => {
console.log('Chat widget opened')
})
const unsubscribeClosed = widget.on('closed', () => {
console.log('Chat widget closed')
})
// Later
// unsubscribeOpened()
// unsubscribeClosed()
})
</script>
Listeners run inside a guard so thrown errors are logged without breaking other listeners.
Custom mount point
Provide mountElement if you want to render the widget inside your own container.
<div id="weav-mount"></div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const mount = document.getElementById('weav-mount')
window.WeavWidget?.init({
agentSlug: '{agent slug}',
mountElement: mount,
})
})
</script>
The widget clears the provided element before rendering. Calling destroy() leaves the element in place so you can reuse it for future mounts.
You can open the widget and optionally send a pre-filled message from any element on your page.
This is useful when you want buttons, links, or other UI elements to start a specific conversation.
Open and send a message by element ID
<button id="my-id">Ask about getting started</button>
<script src="https://app.weav.com/widget.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
window.WeavWidget?.init({ agentSlug: '{agent slug}' })
document.getElementById('my-id')?.addEventListener('click', () => {
WeavWidget.open()
WeavWidget.sendMessage('How do I get started?')
})
})
</script>
Open and send a message by class name
<button class="my-class">Ask about getting started</button>
<script src="https://app.weav.com/widget.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
window.WeavWidget?.init({ agentSlug: '{agent slug}' })
document.querySelector('.my-class')?.addEventListener('click', () => {
WeavWidget.open()
WeavWidget.sendMessage('How do I get started?')
})
})
</script>
You can attach different messages to different elements.
<button class="weav-trigger" data-message="How do I get started?">Getting Started</button>
<button class="weav-trigger" data-message="How do I reset my password?">Reset Password</button>
<button class="weav-trigger" data-message="What pricing plans are available?">Pricing</button>
<script src="https://app.weav.com/widget.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
window.WeavWidget?.init({ agentSlug: '{agent slug}' })
document.querySelectorAll('.weav-trigger').forEach((button) => {
button.addEventListener('click', () => {
const message = button.getAttribute('data-message')
WeavWidget.open()
if (message) {
WeavWidget.sendMessage(message)
}
})
})
})
</script>
Advanced usage
Programmatic control only
The launcher button is visible by default.
To hide it and control the widget entirely through JavaScript, set launcherHidden: true and use open() and close().
<button id="contact-support">Contact support</button>
<script>
document.addEventListener('DOMContentLoaded', () => {
const widget = window.WeavWidget
if (!widget) return
widget.init({
agentSlug: '{agent slug}',
launcherHidden: true,
})
document.getElementById('contact-support')?.addEventListener('click', () => {
widget.open()
})
})
</script>
When launcherHidden is true, the launcher button is completely hidden and the widget can only be opened with window.WeavWidget.open().
This is useful when you want to integrate the widget into your own custom UI.
Re-initializing with new options
window.WeavWidget.destroy()
window.WeavWidget.init({
agentSlug: '{agent slug}',
branding: {
accent_color: '#22d3ee',
},
})
Re-initializing ensures updated configuration values are applied cleanly.