Skip to content

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 headers and 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:

  • Authentication & Authorization: Pass dynamic user tokens, session IDs, or custom authentication headers
  • 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
  • Tracking & Analytics: Add request metadata for monitoring and debugging purposes

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.headers and config.body as needed
    return config;
  }
});

Configuration Object

The interceptor function receives a configuration object with:

Property Type Description
headers Record<string, string> HTTP headers (optional)
body Record<string, unknown> Request body data (optional)
message string User's message

Customizing Request Headers

Request interceptors allow you to add or modify HTTP headers sent with each request. This is useful for authentication, session management, tracking, and passing custom metadata.

Session Management Example

You can manage chat sessions by setting the session-id header with your own UUID:

// Import a UUID library or use your own UUID generator
import { v4 as uuidv4 } from 'uuid';

// Generate a session ID when user starts chatting
const userSessionId = uuidv4(); // e.g., "550e8400-e29b-41d4-a716-446655440000"

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',

  requestInterceptor: (config) => {
    // Set the session-id header to track conversations
    config.headers['session-id'] = userSessionId;

    return config;
  }
});

This allows you to: - Track conversation continuity across page refreshes - Associate chat sessions with user accounts in your system - Implement custom session management logic - Debug and monitor specific user sessions

Request Tracking Example

Add a unique request ID to each message for debugging and monitoring:

// Simple UUID generator function
function generateRequestId() {
  return Date.now().toString(36) + Math.random().toString(36).substr(2);
}

requestInterceptor: (config) => {
  // Add a unique request ID for tracking and debugging
  config.headers['request-id'] = generateRequestId();

  return config;
}

Combining Session and Request Tracking

Use both headers together for comprehensive tracking:

import { v4 as uuidv4 } from 'uuid';

// Generate session ID once when user starts chatting
const sessionId = uuidv4();

// Simple request ID generator
function generateRequestId() {
  return Date.now().toString(36) + Math.random().toString(36).substr(2);
}

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',

  requestInterceptor: (config) => {
    // Track the conversation session
    config.headers['session-id'] = sessionId;

    // Track each individual request
    config.headers['request-id'] = generateRequestId();

    return config;
  }
});

Supported Headers

Header Use Case
session-id Track conversation sessions across requests
request-id Trace individual requests for debugging

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

This comprehensive example demonstrates how to use both headers and body parameters together:

import { v4 as uuidv4 } from 'uuid';

// Generate session ID when user starts chatting
const sessionId = uuidv4();

// Simple request ID generator
function generateRequestId() {
  return Date.now().toString(36) + Math.random().toString(36).substr(2);
}

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();

    // Add custom headers for session and request tracking
    config.headers['session-id'] = sessionId;
    config.headers['request-id'] = generateRequestId();

    // 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';

    // Add context files if user has uploaded relevant documents
    const userFiles = getUserContextFiles();
    if (userFiles.length > 0) {
      config.body.context_files = userFiles;
    }

    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

  1. Sensitive Data: Avoid logging sensitive information in the interceptor
  2. Input Validation: Validate user input before including it in requests
  3. Token Management: Ensure tokens and API keys are securely stored and regularly refreshed
  4. 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
  • Headers Not Applied: Verify header names are valid HTTP header names (avoid spaces and special characters)
  • 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
  • Authentication Errors: Verify that custom headers don't conflict with existing authentication headers

Debugging

Enable browser developer tools to monitor: - Network requests to see applied headers and body data - Console warnings for interceptor errors - Request/response timing and status codes

function generateRequestId() {
  return Date.now().toString(36) + Math.random().toString(36).substr(2);
}

requestInterceptor: (config) => {
  console.log('Original config:', config);

  // Your modifications
  config.headers['request-id'] = generateRequestId();

  config.body.data_filter_hints = [
    {
      tool_name: "DebugTool",
      filter_type: "equals",
      filter_key: "debug_mode",
      filter_value: "enabled"
    }
  ];

  console.log('Modified headers:', config.headers);
  console.log('Modified body:', config.body);
  return config;
}

Next Steps