Skip to content

Website Agent

The Website Agent is Rose's flagship AI agent that powers conversational experiences on B2B websites. It answers visitor questions 24/7, keeps them engaged, and guides them toward conversion.

Overview

The Website Agent is deployed as an embeddable chat widget that integrates with any website. It combines:

  • Retrieval-Augmented Generation (RAG) for knowledge-based responses
  • Multi-agent router architecture for specialized intent handling
  • Visitor enrichment for personalized conversations
  • Lead qualification with interest signal detection
  • Form collection through natural conversation

Architecture

flowchart TB subgraph Frontend["Frontend (widget/)"] Loader[Rose Loader] Widget[React Widget] Shadow[Shadow DOM] end subgraph API["API Gateway"] CF[Cloudflare Workers] end subgraph Backend["Backend (search API)"] FastAPI[FastAPI Service] IXChat[ixchat Package] Graph[LangGraph Orchestration] end subgraph Shared["Shared Infrastructure"] RAG[ixrag - LightRAG] LLM[ixllm - Azure OpenAI] Mongo[(MongoDB)] Neo4j[(Neo4j)] Redis[(Redis)] end Loader --> Widget Widget --> Shadow Widget --> CF CF --> FastAPI FastAPI --> IXChat IXChat --> Graph Graph --> RAG Graph --> LLM RAG --> Mongo RAG --> Neo4j Graph --> Redis

Component Locations

Component Location Purpose
Frontend Widget frontend/widget/ Embeddable React chat interface
Search API backend/apps/api/search/ FastAPI service handling chat requests
ixchat Package backend/packages/ixchat/ LangGraph-based chatbot core

Core Capabilities

Intelligent Conversations

The Website Agent uses LangGraph to orchestrate a complex workflow:

  1. Intent Classification - Classifies visitor intent (LEARN, CONTEXT, SUPPORT, OFFTOPIC, OTHER)
  2. Action Routing - Routes to specialized handlers based on intent and signals
  3. RAG Retrieval - Fetches relevant context from the knowledge base
  4. Response Generation - Produces contextual, brand-aligned answers
  5. Suggestion Generation - Creates follow-up questions or answer options

Visitor Enrichment

Multi-source enrichment pipeline identifies visitors:

Priority Source Description
1 Redis Cache Fast, short-lived cache
2 Supabase Lookup IP hash lookup for returning visitors
3 Browser Reveal Client-side company identification
4 Snitcher Radar Session UUID identification
5 Enrich.so Server-side API fallback

Browser Reveal: The loader auto-captures window.reveal data if present on the page.

Snitcher Radar: The widget loads the Snitcher Radar SDK (cdn.snitcher.com) to capture session UUIDs for backend enrichment. The SDK is initialized with:

  • Namespace: "Rose"
  • All tracking features disabled (only need session UUID)
  • Session ID available via getSnitcherSessionId() and sent with API requests

Lead Qualification

The agent tracks interest signals throughout the conversation:

  • Engagement signals - Message count, time on page
  • Buying signals - Pricing questions, timeline mentions
  • Context signals - Company size, use case details

When signals exceed the site-specific threshold, the agent proposes a demo or next step.

Form Collection

Extracts information naturally during conversation:

  • Email, phone, company name
  • Dynamic CTA URLs with extracted values
  • Confidence thresholds for accuracy

Features

The Website Agent includes several specialized features:

Backend Package: ixchat

The ixchat package is the core backend component of the Website Agent. It provides:

  • LangGraph orchestration - Complex conversation workflow management
  • Multi-agent router - Intent-based routing to specialized handlers
  • Session memory - Redis-based conversation persistence
  • Streaming responses - Real-time token streaming for fast UX

See IXChat Package Documentation for detailed architecture.

Key Modules

Module Purpose
ixchat/chatbot.py Main chatbot with LangGraph orchestration
ixchat/service.py Singleton service manager
ixchat/nodes/ LangGraph node implementations
ixchat/enrichment/ Visitor enrichment pipeline
ixchat/memory.py Session persistence with Redis

Frontend Widget

The widget is built with React and deployed as a UMD bundle:

Key Features

  • Shadow DOM isolation - CSS isolation from host website
  • Streaming responses - Real-time token display
  • Mobile responsive - Adapts to all device sizes
  • Hidden zone mode - Click-to-reveal for non-intrusive UX
  • Multi-language support - Automatic language detection

Deployment Targets

Target Description
widget Production website integration
chrome-plugin Browser extension version
preprod-ui Testing interface

Integration

<script src="https://cdn.userose.ai/loader/rose-loader.js"></script>
<script>
window.InboundXLoader.init({
  api_key: "YOUR_API_KEY",
  api_host: "https://api.userose.ai/rose",
  cdn_url: "https://cdn.userose.ai/widget/your-domain"
});
</script>

API Endpoints

Endpoint Method Description
/api/version GET Health check and environment detection
/api/lightrag/query POST Single-turn query with response
/api/lightrag/query/stream POST Server-Sent Events streaming
/api/lightrag/reset_memory POST Clear conversation history
/api/lightrag/sites GET List supported sites
/api/sites/check POST Verify domain is configured (Chrome extension)

Streaming Response Format

{"type": "thinking", "content": "Thinking..."}
{"type": "token", "content": "The"}
{"type": "token", "content": " answer"}
{"type": "complete", "content": "The answer is...", "metadata": {...}}

Configuration

Site Configuration (Supabase)

Per-site settings in the site_configs table:

Setting Type Description
domain string Site domain identifier (primary key)
name string Human-readable site name for analytics
color hex Brand color for theming
widget_display_mode string 'hidden_zone_click' or normal (default)
traffic_allocated 0-100 Gradual rollout percentage
api_endpoint URL Site-specific API override
legacy_api_endpoint URL Switches to legacy N8N mode if set
display_only_on_urls string[] URL inclusion patterns (whitelist)
session_utm_name string UTM parameter name added to CTA URLs

custom_config Fields:

Field Type Description
enable_mobile boolean Show widget on mobile (default: false)
z_index number Widget stacking order (default: 9999)
exclude_url_patterns string[] URL exclusion patterns
booking_workflow boolean Enable email collection before redirect
always_show_disclaimer boolean Show disclaimer in collapsed view
dynamic_questions.number_of_questions number How many questions to display (default: 2)

Global feature flags in global_client_config table (single row, id=1):

Setting Description
features.followup_suggestions Global default for AI follow-ups

Agent Configuration (Supabase)

Behavior settings in the agent_config table:

Column Group Purpose
Identity company_name, website_url, client_description
Prompts Pricing responses, case studies, calculators
Behavior Interest thresholds, suggested answers rules

Traffic Control (Gradual Rollout)

The traffic_allocated field controls what percentage of visitors see the widget:

Value Behavior
0 Widget disabled for all visitors
1-99 Widget shown to that percentage of visitors
100 Widget enabled for all visitors

How it works:

  1. Widget generates a stable client ID (stored in localStorage)
  2. Client ID is hashed to produce a bucket number (0-99)
  3. If bucket < traffic_allocated, widget displays

This ensures consistent experience per visitor across page loads.

Hidden Zone Mode

When widget_display_mode: 'hidden_zone_click' is set, the widget displays as an invisible 16x16px click target in the bottom-left corner instead of showing immediately.

Use case: This mode enables launching the widget in production on customer websites without showing it explicitly to their visitors. It's used for:

  • Client testing in production - Clients can click on the hidden zone to test the widget
  • Soft launches - Deploy to production without committing to full visibility
  • Internal QA - Team members can test on the live site without affecting user experience

Technical detail: The hidden zone button is rendered outside the Shadow DOM in its own container to ensure fixed positioning works correctly across all browsers.

Mobile Support

By default, the widget is hidden on mobile devices. To enable mobile display:

  1. Set custom_config.enable_mobile: true in the site's Supabase configuration
  2. The widget uses a 1236px breakpoint for responsive layout adjustments (not for display decisions)

Important: Even when mobile is enabled, dynamic questions are disabled on mobile by code - only the search bar is shown (no rotating suggestions). This is a hardcoded behavior in dynamicQuestionManager.ts.

Mobile detection uses User Agent string matching only (iOS, Android, etc.). The 1236px breakpoint is used for responsive layout, not display decisions.

See Widget Display Logic for the full display decision flow.

Analytics

All events tracked with rw_ prefix via PostHog:

Event Description
rw_widget_impression Widget displayed
rw_query_sent User sends message
rw_response_received Response completed
rw_demo_cta_clicked CTA button clicked
rw_message_evaluated Quality rating (like/dislike)

Development

Local Development

# Backend
cd backend
just dev test

# Frontend
cd frontend/widget
just dev

Testing

# Backend tests
cd backend
poetry run pytest packages/ixchat/

# Frontend tests
cd frontend
just test