Webchat Client Tools Integration
This example demonstrates how to use client-side tools with Cognipeer Webchat, allowing the AI to execute JavaScript functions directly in the user's browser during conversations.
Overview
Client tools enable powerful interactions by letting the AI:
- Access browser APIs (geolocation, notifications, localStorage, etc.)
- Perform calculations and data processing
- Call external APIs from the client
- Interact with the page DOM
- Execute custom business logic
Quick Start
typescript
import { CognipeerWebchat, ClientTool } from '@cognipeer/sdk';
// Define client tools
const tools: ClientTool[] = [
{
name: 'get_current_time',
description: 'Get the current date and time',
execute: async () => {
return new Date().toLocaleString();
}
},
{
name: 'calculate',
description: 'Perform a mathematical calculation',
parameters: {
type: 'object',
properties: {
expression: {
type: 'string',
description: 'Mathematical expression (e.g., "2 + 2")'
}
},
required: ['expression']
},
execute: async (args) => {
const expression = args.expression as string;
// Use a safe math parser in production!
const sanitized = expression.replace(/[^0-9+\-*/().%\s]/g, '');
const result = Function('"use strict"; return (' + sanitized + ')')();
return `${expression} = ${result}`;
}
}
];
// Create webchat with tools
const webchat = new CognipeerWebchat({
hookId: 'your-hook-id',
tools: tools
});
// Listen to tool calls (optional)
webchat.on('tool-call', (event) => {
console.log('Tool called:', event.data);
});
// Mount webchat
webchat.mount({
containerId: 'chat-container',
width: '100%',
height: '600px'
});Running This Example
- Install dependencies:
bash
npm install- Set your Hook ID in
.env.local:
env
NEXT_PUBLIC_COGNIPEER_BASE_URL=https://app.cognipeer.com- Run the development server:
bash
npm run devOpen
http://localhost:3000/webchat-widgetTry asking:
- "What time is it?"
- "Calculate 25 * 4"
Example Tools
1. Get Current Time
typescript
{
name: 'get_current_time',
description: 'Get the current date and time',
execute: async () => {
return new Date().toLocaleString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
timeZoneName: 'short'
});
}
}2. Get User Location
typescript
{
name: 'get_user_location',
description: 'Get the user\'s approximate location',
execute: async () => {
try {
const response = await fetch('https://ipapi.co/json/');
const data = await response.json();
return JSON.stringify({
city: data.city,
region: data.region,
country: data.country_name,
timezone: data.timezone
});
} catch (error: any) {
throw new Error(`Failed to get location: ${error.message}`);
}
}
}3. Calculate
typescript
{
name: 'calculate',
description: 'Perform a mathematical calculation',
parameters: {
type: 'object',
properties: {
expression: {
type: 'string',
description: 'Mathematical expression to evaluate'
}
},
required: ['expression']
},
execute: async (args) => {
try {
// Basic validation and sanitization
const sanitized = args.expression.replace(/[^0-9+\-*/().%\s]/g, '');
const result = Function('"use strict"; return (' + sanitized + ')')();
return `${args.expression} = ${result}`;
} catch (error: any) {
throw new Error(`Calculation failed: ${error.message}`);
}
}
}4. Browser Information
typescript
{
name: 'get_browser_info',
description: 'Get information about the user\'s browser and device',
execute: async () => {
return JSON.stringify({
userAgent: navigator.userAgent,
platform: navigator.platform,
language: navigator.language,
cookiesEnabled: navigator.cookieEnabled,
onLine: navigator.onLine,
screenWidth: window.screen.width,
screenHeight: window.screen.height
});
}
}5. Show Notification
typescript
{
name: 'show_notification',
description: 'Show a browser notification to the user',
parameters: {
type: 'object',
properties: {
title: { type: 'string', description: 'Notification title' },
message: { type: 'string', description: 'Notification message' }
},
required: ['title', 'message']
},
execute: async (args) => {
if (!('Notification' in window)) {
throw new Error('Browser does not support notifications');
}
if (Notification.permission === 'granted') {
new Notification(args.title, { body: args.message });
return 'Notification displayed successfully';
} else if (Notification.permission !== 'denied') {
const permission = await Notification.requestPermission();
if (permission === 'granted') {
new Notification(args.title, { body: args.message });
return 'Permission granted and notification displayed';
}
}
throw new Error('Notification permission denied');
}
}Widget with Client Tools
typescript
import { CognipeerWebchat } from '@cognipeer/sdk';
const widget = CognipeerWebchat.createWidget({
hookId: 'your-hook-id',
position: 'bottom-right',
buttonColor: '#14b8a6',
tools: [
{
name: 'get_current_time',
description: 'Get current time',
execute: async () => new Date().toLocaleString()
},
{
name: 'calculate',
description: 'Perform calculation',
parameters: {
type: 'object',
properties: {
expression: { type: 'string' }
},
required: ['expression']
},
execute: async (args) => {
const sanitized = args.expression.replace(/[^0-9+\-*/().%\s]/g, '');
return String(Function('"use strict"; return (' + sanitized + ')')());
}
}
]
});
// Listen to tool execution
widget.on('tool-call', (event) => {
console.log('Tool called:', event.data.toolName);
console.log('Args:', event.data.args);
console.log('Execution ID:', event.data.executionId);
});Dynamic Tool Registration
You can also register tools after creating the webchat instance:
typescript
const webchat = new CognipeerWebchat({
hookId: 'your-hook-id'
});
// Register a tool later
webchat.registerTool({
name: 'my_custom_tool',
description: 'Does something useful',
execute: async () => {
return 'Result';
}
});
// Unregister when no longer needed
webchat.unregisterTool('my_custom_tool');Best Practices
1. Clear Descriptions
Write clear, specific descriptions that help the AI understand when to use each tool:
typescript
// ✅ Good
{
name: 'get_cart_total',
description: 'Calculate the total price of items in the shopping cart including tax and shipping',
execute: async () => { /* ... */ }
}
// ❌ Bad
{
name: 'get_cart_total',
description: 'Gets total',
execute: async () => { /* ... */ }
}2. Error Handling
Always handle errors gracefully and return user-friendly messages:
typescript
{
name: 'fetch_data',
description: 'Fetch data from API',
execute: async () => {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error(`API returned ${response.status}`);
}
return await response.json();
} catch (error: any) {
throw new Error(`Failed to fetch data: ${error.message}`);
}
}
}3. Security
- Never use
eval()on user input without sanitization - Validate all parameters
- Request browser permissions properly
- Sanitize any user-provided data
typescript
// ⚠️ Dangerous
execute: async (args) => {
return eval(args.code); // NEVER DO THIS!
}
// ✅ Safe
execute: async (args) => {
const sanitized = args.expression.replace(/[^0-9+\-*/().%\s]/g, '');
return Function('"use strict"; return (' + sanitized + ')')();
}4. Performance
- Keep execution fast (< 5 seconds recommended)
- Cache results when appropriate
- Handle timeouts gracefully
- Show loading states for long operations
How It Works
- Tool Registration: When you create a webchat with tools, they're registered via postMessage to the iframe
- AI Decision: During conversation, the AI decides when to call a tool based on the description
- Tool Call Event: The webchat iframe sends a
tool-callevent with the tool name and arguments - Local Execution: Your
executefunction runs in the browser - Result Return: The result is sent back to the iframe via
tool-resultevent - Conversation Continues: The AI uses the result to continue the conversation
User: "What time is it?"
↓
AI decides to call get_current_time()
↓
postMessage: { type: 'tool-call', toolName: 'get_current_time' }
↓
Your execute() function runs
↓
postMessage: { type: 'tool-result', output: '3:45 PM' }
↓
AI: "It's currently 3:45 PM"Events
Listen to tool call events for monitoring and debugging:
typescript
webchat.on('tool-call', (event) => {
console.log({
toolName: event.data.toolName,
args: event.data.args,
executionId: event.data.executionId,
conversationId: event.data.conversationId,
messageId: event.data.messageId
});
});Troubleshooting
Tool Not Being Called
- Check tool description - make it clear and specific
- Verify parameter schema is correct
- Check browser console for registration logs
Execution Errors
- Check browser console for error messages
- Validate args match the parameter schema
- Ensure execute function is async
Tool Not Registered
- Verify iframe is loaded properly
- Check Hook ID is correct
- Look for registration console logs
Use Cases
- E-commerce: Calculate cart totals, check inventory, apply discount codes
- Customer Support: Fetch account info, check order status, access user data
- Productivity: Set reminders, create tasks, access calendar
- Data Processing: Generate charts, transform data, parse CSV
- Browser Integration: Read cookies, check localStorage, access device APIs