Using Request Interceptors with Embedded Chat
Overview
Request interceptors allow you to customize API requests made by the embedded JavaScript chat widget at runtime. This powerful feature enables you to inject dynamic body parameters based on your application's current state, user context, or tool configuration requirements.
When to Use Request Interceptors
Request interceptors are ideal for scenarios where you need to:
- Tool Configuration: Provide tool-specific parameters like company IDs or data filters
- Contextual Data: Include user preferences, application state, or environmental information
- Dynamic Content: Add context files or modify memory settings based on user permissions
Basic Implementation
To use request interceptors, add the requestInterceptor
function to your widget initialization:
window.WabeeChat.init({
target: '#chat-container',
apiKey: 'YOUR_API_KEY',
agentId: 'YOUR_AGENT_ID',
agentUrl: 'https://your-agent-url.com',
sseUrl: 'https://your-sse-url.com',
fileServiceUrl: 'https://your-file-service-url.com',
// Request interceptor function
requestInterceptor: (config) => {
// Modify config.body as needed
return config;
}
});
Configuration Object
The interceptor function receives a configuration object with:
Property | Type | Description |
---|---|---|
body |
Record<string, unknown> |
Request body data (optional) |
message |
string |
User's message |
Using Data Filter Hints
One of the most powerful uses of request interceptors is to dynamically apply data filter hints that control how your agent's tools access and filter data:
requestInterceptor: (config) => {
const user = getCurrentUser();
const company = getCompany();
// Configure tools with dynamic filters for data access control
config.body.data_filter_hints = [
{
tool_name: "CustomerDataTool",
filter_type: "equals",
filter_key: "company_id",
filter_value: company.id
},
{
tool_name: "CustomerDataTool",
filter_type: "equals",
filter_key: "user_department",
filter_value: user.department
}
];
return config;
}
Available Filter Types
Filter Type | Description | Example Use Case |
---|---|---|
equals |
Exact match | company_id = "123" |
gt |
Greater than | date > "2024-01-01" |
lt |
Less than | price < 100 |
gte |
Greater than or equal | score >= 85 |
lte |
Less than or equal | age <= 65 |
like |
Pattern matching | name LIKE "%smith%" |
Role-Based Data Access
Implement different data access levels based on user permissions:
requestInterceptor: (config) => {
const user = getCurrentUser();
const company = getCompany();
// Base filter for company isolation
const baseFilters = [
{
tool_name: "CustomerDataTool",
filter_type: "equals",
filter_key: "company_id",
filter_value: company.id
}
];
// Add role-specific filters
if (user.role === 'admin') {
// Admins see all company data
config.body.data_filter_hints = baseFilters;
} else if (user.role === 'manager') {
// Managers see their department's data
config.body.data_filter_hints = [
...baseFilters,
{
tool_name: "CustomerDataTool",
filter_type: "equals",
filter_key: "department",
filter_value: user.department
}
];
} else {
// Regular users see only their assigned data
config.body.data_filter_hints = [
...baseFilters,
{
tool_name: "CustomerDataTool",
filter_type: "equals",
filter_key: "assigned_user_id",
filter_value: user.id
}
];
}
return config;
}
Additional Configuration Options
Context Files and Memory
requestInterceptor: (config) => {
// Include relevant context files
config.body.context_files = [
"inputs/chat-files/user123/project-requirements.pdf",
"inputs/chat-files/user123/meeting-notes.txt"
];
// Enable memory retention for premium users
const user = getCurrentUser();
config.body.auto_memory_retain = user.plan === 'premium';
return config;
}
Message-Based Logic
Customize behavior based on the user's message content:
requestInterceptor: (config) => {
const message = config.message.toLowerCase();
if (message.includes('customer') || message.includes('client')) {
config.body.context_files = [
"inputs/customer-data/current-customers.csv"
];
config.body.data_filter_hints = [
{
tool_name: "CustomerDatabase",
filter_type: "equals",
filter_key: "status",
filter_value: "active"
}
];
}
return config;
}
Async Operations
Request interceptors support asynchronous operations:
requestInterceptor: async (config) => {
try {
// Fetch dynamic data
const userProfile = await fetchUserProfile();
const permissions = await fetchUserPermissions();
config.body.data_filter_hints = [
{
tool_name: "UserDataTool",
filter_type: "equals",
filter_key: "user_id",
filter_value: userProfile.id
}
];
return config;
} catch (error) {
console.warn('Failed to fetch user data for request interceptor:', error);
return config; // Return original config if async operations fail
}
}
Complete Example
window.WabeeChat.init({
target: '#chat-container',
apiKey: 'wabee_api_key_example_123',
agentId: 'agent-uuid-here',
agentUrl: 'https://api.wabee.ai',
sseUrl: 'https://sse.wabee.ai',
fileServiceUrl: 'https://files.wabee.ai',
requestInterceptor: (config) => {
const user = getCurrentUser();
const company = getCompany();
// Configure data filter hints for multi-tenant data access
config.body.data_filter_hints = [
{
tool_name: "BubbleDataTool",
filter_type: "equals",
filter_key: "company_id",
filter_value: company.id
},
{
tool_name: "BubbleDataTool",
filter_type: "equals",
filter_key: "access_level",
filter_value: user.accessLevel
}
];
// Enable memory retention for premium users
config.body.auto_memory_retain = user.plan === 'premium';
return config;
}
});
Error Handling and Security
Built-in Error Handling
The widget includes automatic error handling: - If the interceptor throws an error, the original request configuration is used - Errors are logged to the console with warning messages - Chat functionality continues working normally
Security Best Practices
- Sensitive Data: Avoid logging sensitive information in the interceptor
- Input Validation: Validate user input before including it in requests
- Token Management: Ensure tokens and API keys are securely stored and regularly refreshed
- Access Control: Implement proper access control checks before setting filter values
requestInterceptor: (config) => {
try {
// Your custom logic here
config.body.data_filter_hints = processDataFilters();
return config;
} catch (error) {
console.warn('Custom interceptor logic failed:', error);
return config; // Return config as-is if errors occur
}
}
Troubleshooting
Common Issues
- Interceptor Not Called: Ensure the function is properly defined in the
init
options - Filter Hints Ignored: Check that tool names match exactly and filter types are valid
- Body Parameters Ignored: Ensure body parameter names match the expected API schema
Debugging
Enable browser developer tools to monitor: - Network requests to see applied body data - Console warnings for interceptor errors - Request/response timing and status codes
requestInterceptor: (config) => {
console.log('Original config:', config);
// Your modifications
config.body.data_filter_hints = [
{
tool_name: "DebugTool",
filter_type: "equals",
filter_key: "debug_mode",
filter_value: "enabled"
}
];
console.log('Modified config:', config);
return config;
}
Next Steps
- Learn more about data filter hints for API integration
- Explore the embedding chat widget tutorial for basic setup
- Review the API documentation for complete endpoint reference