Skip to content

In-Chat Booking Email Collection

Overview

When a visitor clicks a booking CTA (e.g., "Book a Demo") and their email is not known, the system collects it through conversation before redirecting to the booking page with the email pre-filled.

User Flow

flowchart TD A[User clicks CTA] --> B{Email known?} B -->|Yes| C[Redirect with ?email=xxx] B -->|No| D[Bot asks for email] D --> E[User provides email] E --> F[Redirect with ?email=xxx]

Key Files

Backend

File Purpose
ixchat/nodes/booking_handler.py Main booking flow handler
ixchat/nodes/action_router.py Routes to booking_handler
ixchat/utils/email_extraction.py Email regex extraction
ixchat/pydantic_models/booking_state.py BookingState model
ixchat/chatbot.py Loads visitor profile from Supabase on session start
ixdata/clients/conversation_storage.py get_visitor_profile_data() for cross-session persistence

Frontend

File Purpose
utils/widget/bookingReducer.ts Booking state management
hooks/widget/useBookingReducer.ts Hook wrapping useReducer
components/ExpandedChatView.tsx Booking flow orchestration

State Management

BookingState tracks progress across turns:

  • is_booking_flow - Active booking flow from CTA click
  • awaiting_email - Waiting for user to provide email
  • email_collected - Email successfully captured
  • redirect_url - Target URL for redirect

Cross-Session Persistence

Email and visitor profile data (company, sector) persist across sessions:

  1. Saving: When email is captured, it's stored in Supabase visitors table
  2. Loading: On new session start, get_visitor_profile_data() loads saved data
  3. Merging: Loaded data merges into visitor_profile if current session has no data

This means returning visitors skip email collection if they provided it previously.

Debugging

Backend logs use the 📧 [BOOKING HANDLER] prefix:

📧 [BOOKING HANDLER] Extracted email from user input: john@example.com
📧 [BOOKING HANDLER] Email already known, generating confirmation

Cross-session persistence logs:

📋 Loaded visitor profile data from Supabase: fields=['email', 'company_name']
[Visitor Profile] Loaded data for person_id=abc12345...: fields=['email', 'company_name']

Common Issues

Issue Cause Solution
Email not extracted Invalid format Check regex pattern accepts the format
Stuck in awaiting state visitor_profile not updating Check completion event includes visitor_profile
Redirect not triggering useEffect dependencies Verify visitorProfile changes trigger effect

Testing

poetry run pytest packages/ixchat/tests/test_booking_handler.py -v
poetry run pytest packages/ixchat/tests/test_email_extraction.py -v