Skip to main content

Frontend Integration Overview

Ozwell is an embeddable AI assistant that runs inside an iframe on your website. Users chat with it. The AI can call tools you define β€” JavaScript functions that read from or write to your page. Conversations are private by default; your page only sees tool calls and lifecycle events, never message content.

Try it live: See Ozwell in action at the demo site.

What You're Building​

There are two parts: define tools on your page so the AI knows what it can do, then handle tool calls when the AI invokes them.

1. Define Tools and Load the Widget​

Your page declares the tools the AI can call β€” their names, descriptions, and parameter schemas. By default, an agent can call any tool the page presents. No server-side configuration needed.

Here's a page that exposes two tools: one that reads the current email (get) and one that updates it (set):

<script>
window.OzwellChatConfig = {
apiKey: 'agnt_key-your-agent-key',
tools: [
{
type: 'function',
function: {
name: 'get_user_email',
description: 'Reads the current email address from the page',
parameters: { type: 'object', properties: {} }
}
},
{
type: 'function',
function: {
name: 'set_user_email',
description: 'Updates the email address on the page',
parameters: {
type: 'object',
properties: {
email: { type: 'string', description: 'The new email address' }
},
required: ['email']
}
}
}
]
};
</script>
<script src="https://ozwell-dev-refserver.opensource.mieweb.org/embed/ozwell-loader.js"></script>

2. Handle Tool Calls​

When the AI calls a tool, the loader dispatches an ozwell-tool-call event. Listen for it and call respond() with the result:

<script>
document.addEventListener('ozwell-tool-call', (e) => {
const { name, arguments: args, respond } = e.detail;

if (name === 'get_user_email') {
// READ from your page
respond({ email: document.getElementById('email').value });

} else if (name === 'set_user_email') {
// WRITE to your page
document.getElementById('email').value = args.email;
respond({ success: true });
}
});
</script>

You must call respond(). The AI waits for the result β€” if you don't respond, the conversation hangs.

Where Tools Can Be Defined​

ApproachTools defined inBest for
Page-defined (above)OzwellChatConfig.toolsPages that declare their own capabilities
Agent-definedAgent definition server-sideCentrally managed tools with full schemas and descriptions
BothAgent definition + OzwellChatConfig.toolsAgent owns core tools; page adds context-specific tools

How it works:

  • If the agent has no tools in its server-side definition, it can call any tool the page provides. This is the default.
  • If the agent has a tools list defined server-side, those tools are always available. The page can provide additional tools alongside them.
  • Agent-defined tool schemas take priority β€” if the same tool name appears in both, the agent's definition wins.

Tool Namespacing​

Page-provided tools are automatically prefixed with postMessage: on the wire so they can't collide with tools the agent server implements natively. This is transparent to your page β€” the prefix is added by the loader when the widget discovers tools, and stripped before your ozwell-tool-call handler fires. You never see the prefix in your code.

Controlling Page Tools​

By default, agents accept all page-provided tools. The agent definition can restrict this with the pageTools field:

# Allow all page tools (default β€” can be omitted)
pageTools: all

# Only allow specific page tools
pageTools:
restricted:
- get_user_email
- set_user_email

# Allow all page tools except these
pageTools:
blocked:
- dangerous_tool

See Agent Registration API β†’ pageTools for details.

The widget runs in a sandboxed iframe β€” it cannot touch your DOM, read your cookies, or access your JavaScript directly. Only tool calls and their responses cross the iframe boundary.

➑️ Full tutorial with tool calling β€” the CDN embed guide walks through this step by step.

Integration Approaches​

Quick Comparison​

MethodSetup TimeBuild RequiredBest For
CDN Embed~5 minNoStatic sites, quick prototypes
Framework~15 minYesProduction SPAs
Iframe~10 minOptionalCustom implementations

CDN Embed (Fastest)​

Add Ozwell to any website with a single script tag. No build step required. Supports tool calling out of the box β€” define what your AI can do, then handle tool calls in a simple event listener.

<script>
window.OzwellChatConfig = { apiKey: 'agnt_key-your-agent-key' };
</script>
<script src="https://ozwell-dev-refserver.opensource.mieweb.org/embed/ozwell-loader.js"></script>

➑️ Full CDN documentation with tool calling tutorial


Framework Integration​

For production applications using modern JavaScript frameworks, we provide dedicated integration guides:

FrameworkGuideStatus
ReactReact Integrationβœ…
Next.jsNext.js Integrationβœ…
Vue 3Vue 3 Integrationβœ…
Vue 2Vue 2 Integrationβœ…
SvelteSvelte Integrationβœ…
Vanilla JSVanilla JS Integrationβœ…

All framework integrations render Ozwell within an isolated iframe, ensuring:

  • πŸ”’ Security isolation from your host page
  • 🎨 Consistent styling that won't conflict with your CSS
  • πŸ“± Responsive behavior out of the box

Standards-inspired: Ozwell's iframe architecture implements an inverted MCP postMessage transport, drawing from proposals by Josh Mandel and the W3C WebMCP community. Learn more in MCP postMessage Standard.


Security Model​

Privacy First​

Ozwell is built on a foundation of user privacy and control. When a user opens Ozwell, their conversation is privateβ€”the host site cannot see, intercept, or log what is said. This creates a safe space where users can:

  • Ask any question without embarrassment
  • Explore topics freely without surveillance
  • Trust that their dialogue stays between them and Ozwell

Sharing is always opt-in. Only when a user explicitly chooses to share information does it become visible to the host site.

Scoped API Keys​

Frontend integrations use scoped API keys which are:

  • βœ… Agent-specific: Tied to a single agent configuration
  • βœ… Permission-limited: Only allows operations the agent is authorized for
  • βœ… Rate-limited: Protected against abuse
  • βœ… Revocable: Can be rotated or disabled without affecting other keys

Iframe Isolation​

All frontend integrations run inside an iframe with:

  • Sandboxed execution β€” No access to parent page DOM
  • Origin isolation β€” Separate security context
  • CSP compliance β€” Strict content security policies
  • No message relay β€” Conversation content stays in the iframe
  • User-controlled sharing β€” Only explicit user actions can share data

➑️ Learn more about iframe security


Customization Options​

Appearance​

OptionDescriptionDefault
themeLight or dark modeauto
primaryColorAccent color for buttons/links#4f46e5
positionWidget position (bottom-right, bottom-left, etc.)bottom-right
widthChat window width400px
heightChat window height600px

Behavior​

OptionDescriptionDefault
autoOpenOpen chat on page loadfalse
greetingInitial message to displayAgent's default
placeholderInput field placeholder text"Type a message..."

Privacy by Design​

The conversation between Ozwell and the user is private by default.

Why Privacy Matters​

  • No message relay: Conversation content is never sent to the host site
  • Safe space: Users can ask any question without fear of judgment or surveillance
  • User control: Only the user decides if and when to share conversation details
  • Trust: The Ozwell brand stands for privacy and user empowerment

What the Host Site Can See​

The host site receives only lifecycle events, never message content:

// βœ… Allowed: Lifecycle events (no content)
window.addEventListener('ozwell:ready', () => {
console.log('Ozwell widget loaded');
});

window.addEventListener('ozwell:open', () => {
console.log('Chat opened');
});

window.addEventListener('ozwell:close', () => {
console.log('Chat closed');
});

// ❌ Not available: Message content is private
// window.addEventListener('ozwell:message', ...) β€” Does not exist

User-Initiated Sharing​

If the user explicitly chooses to share information with the host site, they can do so through in-chat actions:

// Only triggered when user clicks "Share with site" in chat
window.addEventListener('ozwell:user-share', (event) => {
// User explicitly consented to share this specific data
console.log('User shared:', event.detail);
});

This ensures users always feel comfortable asking questionsβ€”even ones they might consider "dumb"β€”knowing the conversation stays between them and Ozwell.


Next Steps​

  1. Quick start: Try the CDN embed first
  2. Production app: Follow your framework guide above
  3. Custom needs: Review iframe integration
  4. Standards context: Read about the MCP postMessage Standard that inspired Ozwell's architecture
  5. Security deep-dive: Understand the iframe security model