Vanilla JavaScript Integration
Integrate Ozwell into any website using plain JavaScript, without any framework dependencies.
Quick Startβ
Script Tag (CDN)β
The simplest approach β add a single script tag:
<script
src="https://cdn.ozwell.ai/embed.js"
data-api-key="ozw_scoped_xxxxxxxx"
data-agent-id="agent_xxxxxxxx"
></script>
See the CDN documentation for full details.
ES Module Importβ
For bundled applications:
import { Ozwell } from '@ozwell/vanilla';
const ozwell = new Ozwell({
apiKey: 'ozw_scoped_xxxxxxxx',
agentId: 'agent_xxxxxxxx',
});
ozwell.mount('#ozwell-container');
Installationβ
NPM / Yarn / PNPMβ
npm install @ozwell/vanilla
# or
yarn add @ozwell/vanilla
# or
pnpm add @ozwell/vanilla
CDN (IIFE)β
<script src="https://cdn.ozwell.ai/ozwell.min.js"></script>
<script>
const ozwell = new Ozwell.default({
apiKey: 'ozw_scoped_xxxxxxxx',
agentId: 'agent_xxxxxxxx',
});
ozwell.mount(document.body);
</script>
API Referenceβ
Constructorβ
import { Ozwell } from '@ozwell/vanilla';
const ozwell = new Ozwell({
// Required
apiKey: 'ozw_scoped_xxxxxxxx',
agentId: 'agent_xxxxxxxx',
// Optional
theme: 'auto', // 'light' | 'dark' | 'auto'
position: 'bottom-right', // 'bottom-right' | 'bottom-left'
primaryColor: '#4f46e5',
width: '400px',
height: '600px',
autoOpen: false,
greeting: 'Hello! How can I help?',
placeholder: 'Type a message...',
showTrigger: true,
context: {},
});
Configuration Optionsβ
| Option | Type | Default | Description |
|---|---|---|---|
apiKey | string | required | Scoped API key |
agentId | string | required | Agent ID |
theme | string | 'auto' | Color theme |
position | string | 'bottom-right' | Widget position |
primaryColor | string | '#4f46e5' | Accent color |
width | string | '400px' | Chat window width |
height | string | '600px' | Chat window height |
autoOpen | boolean | false | Open on mount |
greeting | string | Agent default | Initial message |
placeholder | string | 'Type a message...' | Input placeholder |
showTrigger | boolean | true | Show launcher button |
context | object | {} | Context data for agent |
Methodsβ
mount(target)β
Mount the widget to a DOM element.
// Using a selector
ozwell.mount('#container');
// Using an element reference
ozwell.mount(document.body);
unmount()β
Remove the widget from the DOM.
ozwell.unmount();
open()β
Open the chat window.
ozwell.open();
close()β
Close the chat window.
ozwell.close();
toggle()β
Toggle the chat window open/closed.
ozwell.toggle();
sendMessage(content)β
Send a message programmatically.
ozwell.sendMessage('Hello, I need help with...');
setContext(context)β
Update the context data sent to the agent.
ozwell.setContext({
userId: 'user_123',
page: window.location.pathname,
customData: { ... },
});
updateConfig(options)β
Update widget configuration.
ozwell.updateConfig({
theme: 'dark',
primaryColor: '#10b981',
});
Propertiesβ
| Property | Type | Description |
|---|---|---|
isReady | boolean | Widget is initialized |
isOpen | boolean | Chat window is open |
isMounted | boolean | Widget is mounted to DOM |
if (ozwell.isReady && !ozwell.isOpen) {
ozwell.open();
}
Eventsβ
Listen to widget events:
ozwell.on('ready', () => {
console.log('Widget ready');
});
ozwell.on('open', () => {
console.log('Chat opened');
});
ozwell.on('close', () => {
console.log('Chat closed');
});
ozwell.on('user-share', (data) => {
// Only fires when user explicitly shares
console.log('User shared:', data);
});
ozwell.on('error', (error) => {
console.error('Error:', error);
});
// Note: No 'message' event - conversations are private between user and Ozwell
off(event, handler)β
Remove an event listener:
function handleOpen() {
console.log('Opened');
}
ozwell.on('open', handleOpen);
ozwell.off('open', handleOpen);
Examplesβ
Basic Setupβ
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
</head>
<body>
<h1>Welcome</h1>
<div id="ozwell-container"></div>
<script type="module">
import { Ozwell } from 'https://cdn.ozwell.ai/ozwell.esm.js';
const ozwell = new Ozwell({
apiKey: 'ozw_scoped_xxxxxxxx',
agentId: 'agent_xxxxxxxx',
});
ozwell.mount('#ozwell-container');
</script>
</body>
</html>
Custom Trigger Buttonβ
<button id="chat-button">π¬ Chat with us</button>
<div id="ozwell-container"></div>
<script type="module">
import { Ozwell } from '@ozwell/vanilla';
const ozwell = new Ozwell({
apiKey: 'ozw_scoped_xxxxxxxx',
agentId: 'agent_xxxxxxxx',
showTrigger: false,
});
ozwell.mount('#ozwell-container');
document.getElementById('chat-button').addEventListener('click', () => {
ozwell.toggle();
});
</script>
With User Contextβ
import { Ozwell } from '@ozwell/vanilla';
// Get user data from your application
const user = getCurrentUser();
const ozwell = new Ozwell({
apiKey: 'ozw_scoped_xxxxxxxx',
agentId: 'agent_xxxxxxxx',
context: {
userId: user?.id,
email: user?.email,
plan: user?.subscription?.plan,
page: window.location.pathname,
},
});
ozwell.mount(document.body);
// Update context when user navigates
window.addEventListener('popstate', () => {
ozwell.setContext({
...ozwell.context,
page: window.location.pathname,
});
});
Analytics Integrationβ
Track chat lifecycle events (not contentβthat's private):
import { Ozwell } from '@ozwell/vanilla';
import { track } from './analytics';
const ozwell = new Ozwell({
apiKey: 'ozw_scoped_xxxxxxxx',
agentId: 'agent_xxxxxxxx',
});
ozwell.on('open', () => {
track('chat_opened');
});
ozwell.on('close', () => {
track('chat_closed');
});
ozwell.on('user-share', (data) => {
// Only fires when user explicitly shares
track('user_shared_data', data);
});
ozwell.mount(document.body);
Conditional Displayβ
import { Ozwell } from '@ozwell/vanilla';
const ozwell = new Ozwell({
apiKey: 'ozw_scoped_xxxxxxxx',
agentId: 'agent_xxxxxxxx',
});
// Only show on certain pages
const hiddenPaths = ['/checkout', '/auth', '/admin'];
function shouldShowChat() {
return !hiddenPaths.some(path =>
window.location.pathname.startsWith(path)
);
}
if (shouldShowChat()) {
ozwell.mount(document.body);
}
// Handle SPA navigation
window.addEventListener('popstate', () => {
if (shouldShowChat() && !ozwell.isMounted) {
ozwell.mount(document.body);
} else if (!shouldShowChat() && ozwell.isMounted) {
ozwell.unmount();
}
});
Multiple Agents (Route-Based)β
import { Ozwell } from '@ozwell/vanilla';
const agents = {
'/docs': 'agent_docs_xxxxxxxx',
'/support': 'agent_support_xxxxxxxx',
default: 'agent_general_xxxxxxxx',
};
function getAgentForPath(path) {
for (const [prefix, agentId] of Object.entries(agents)) {
if (prefix !== 'default' && path.startsWith(prefix)) {
return agentId;
}
}
return agents.default;
}
let ozwell = new Ozwell({
apiKey: 'ozw_scoped_xxxxxxxx',
agentId: getAgentForPath(window.location.pathname),
});
ozwell.mount(document.body);
// Reinitialize on navigation
window.addEventListener('popstate', () => {
const newAgentId = getAgentForPath(window.location.pathname);
if (ozwell.config.agentId !== newAgentId) {
ozwell.unmount();
ozwell = new Ozwell({
apiKey: 'ozw_scoped_xxxxxxxx',
agentId: newAgentId,
});
ozwell.mount(document.body);
}
});
TypeScriptβ
Full TypeScript definitions are included:
import { Ozwell, type OzwellConfig, type Message, type OzwellError } from '@ozwell/vanilla';
const config: OzwellConfig = {
apiKey: 'ozw_scoped_xxxxxxxx',
agentId: 'agent_xxxxxxxx',
theme: 'dark',
};
const ozwell = new Ozwell(config);
ozwell.on('message', (message: Message) => {
console.log(message.role, message.content);
});
ozwell.on('error', (error: OzwellError) => {
console.error(error.code, error.message);
});
ozwell.mount(document.body);
Troubleshootingβ
Widget Not Appearingβ
- Check that the container element exists in the DOM
- Verify
mount()is called after DOM is ready - Check browser console for errors
Events Not Firingβ
- Register event listeners before calling
mount() - Verify the event names are correct
Multiple Instancesβ
Only create one Ozwell instance per page. If you need different agents, use unmount() and create a new instance.
Next Stepsβ
- CDN Integration β Simplest script-tag approach
- Iframe Details β Security deep-dive
- Backend API β Server-side integration