Skip to content
Learn Agentic AI
Learn Agentic AI14 min read6 views

Building a Lead Qualification Chat Agent: Collecting and Scoring User Information

Build a complete lead qualification chat agent with structured question flows, conditional branching logic, real-time lead scoring models, and CRM integration to convert website visitors into qualified sales opportunities.

From Traffic to Pipeline

Most B2B websites convert less than 3% of visitors into leads. A well-built lead qualification chat agent changes that equation by engaging visitors in real time, asking the right questions, scoring their fit, and routing qualified leads to sales — all without human intervention. The best qualification agents feel like a helpful conversation, not a form to fill out.

The architecture has three layers: a question flow engine that guides the conversation, a scoring model that evaluates fit in real time, and a CRM integration that delivers qualified leads to the right salesperson.

The Lead Data Model

Start by defining what a qualified lead looks like:

Hear it before you finish reading

Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.

Try Live Demo →
sequenceDiagram
    autonumber
    participant Caller as Caller
    participant Agent as CallSphere Agent
    participant API as CRM API
    participant DB as CRM Database
    participant Webhook as Webhook Listener
    Caller->>Agent: Inbound call begins
    Agent->>Agent: STT plus intent detection
    Agent->>API: Lookup contact by phone
    API->>DB: Read contact record
    DB-->>API: Contact and history
    API-->>Agent: Personalized context
    Agent->>API: Create call activity
    Agent->>API: Update deal stage
    API->>Webhook: Outbound webhook fires
    Webhook-->>Agent: Confirmed
    Agent->>Caller: Spoken confirmation
from pydantic import BaseModel, Field
from enum import Enum
from datetime import datetime

class LeadScore(str, Enum):
    HOT = "hot"        # 80-100 points, route to sales immediately
    WARM = "warm"      # 50-79 points, nurture sequence
    COLD = "cold"      # 0-49 points, marketing list

class LeadData(BaseModel):
    session_id: str
    name: str | None = None
    email: str | None = None
    company: str | None = None
    company_size: str | None = None
    role: str | None = None
    budget: str | None = None
    timeline: str | None = None
    use_case: str | None = None
    pain_points: list[str] = Field(default_factory=list)
    score: int = 0
    grade: LeadScore = LeadScore.COLD
    source_page: str | None = None
    created_at: datetime = Field(default_factory=datetime.utcnow)

    def calculate_score(self) -> int:
        score = 0

        # Company size scoring
        size_scores = {
            "1-10": 5, "11-50": 10, "51-200": 20,
            "201-1000": 30, "1000+": 40
        }
        score += size_scores.get(self.company_size or "", 0)

        # Role scoring - decision makers score higher
        role_keywords = {
            "cto": 25, "vp": 25, "director": 20, "head": 20,
            "manager": 15, "engineer": 5, "developer": 5,
        }
        if self.role:
            role_lower = self.role.lower()
            for keyword, points in role_keywords.items():
                if keyword in role_lower:
                    score += points
                    break

        # Budget scoring
        budget_scores = {
            "under_1k": 5, "1k_5k": 15, "5k_20k": 25,
            "20k_50k": 35, "50k_plus": 40
        }
        score += budget_scores.get(self.budget or "", 0)

        # Timeline scoring - urgency increases score
        timeline_scores = {
            "immediate": 20, "this_month": 15,
            "this_quarter": 10, "exploring": 5
        }
        score += timeline_scores.get(self.timeline or "", 0)

        self.score = min(score, 100)
        if self.score >= 80:
            self.grade = LeadScore.HOT
        elif self.score >= 50:
            self.grade = LeadScore.WARM
        else:
            self.grade = LeadScore.COLD

        return self.score

Conversational Question Flow

Use a state machine to guide the conversation while keeping it natural. The agent asks questions in a logical sequence but adapts based on previous answers:

from dataclasses import dataclass, field

@dataclass
class QualificationStep:
    field_name: str
    question: str
    follow_ups: dict[str, str] = field(default_factory=dict)
    skip_if: str | None = None

QUALIFICATION_FLOW = [
    QualificationStep(
        field_name="use_case",
        question="What brings you to our site today? I'd love to understand what you're looking for.",
    ),
    QualificationStep(
        field_name="company",
        question="Which company are you with? That will help me tailor my recommendations.",
    ),
    QualificationStep(
        field_name="company_size",
        question="How large is your team?",
    ),
    QualificationStep(
        field_name="role",
        question="And what's your role there?",
    ),
    QualificationStep(
        field_name="timeline",
        question="What's your timeline for getting started?",
        follow_ups={
            "immediate": "Great, sounds like this is a priority. Let me make sure I connect you with the right person.",
            "exploring": "No rush at all. Let me share some resources that might help your evaluation.",
        },
    ),
    QualificationStep(
        field_name="email",
        question="What's the best email to reach you at? I'll send over the details we discussed.",
    ),
]

class QualificationEngine:
    def __init__(self):
        self.lead = LeadData(session_id="")
        self.current_step = 0
        self.completed_fields: set[str] = set()

    def get_next_question(self) -> str | None:
        while self.current_step < len(QUALIFICATION_FLOW):
            step = QUALIFICATION_FLOW[self.current_step]
            if step.field_name not in self.completed_fields:
                return step.question
            self.current_step += 1
        return None

    def process_answer(self, field_name: str, value: str) -> str | None:
        setattr(self.lead, field_name, value)
        self.completed_fields.add(field_name)

        step = QUALIFICATION_FLOW[self.current_step]
        follow_up = step.follow_ups.get(value)

        self.current_step += 1
        next_q = self.get_next_question()

        if follow_up and next_q:
            return f"{follow_up} {next_q}"
        return next_q

AI-Powered Extraction

Instead of rigid multiple-choice answers, let the LLM extract structured data from natural conversation:

from agents import Agent, function_tool, Runner

@function_tool
def update_lead_field(field_name: str, value: str) -> str:
    """Update a lead qualification field with extracted information.
    field_name: one of name, email, company, company_size, role, budget, timeline, use_case
    value: the extracted value from the conversation
    """
    return f"Updated {field_name} to {value}"

@function_tool
def get_qualification_status() -> str:
    """Check which qualification fields have been collected and what to ask next."""
    return "Returns current lead state and next question"

qualification_agent = Agent(
    name="Lead Qualifier",
    instructions="""You are a friendly lead qualification agent. Your goal is to
    understand the visitor's needs and collect qualification information naturally.

    Rules:
    - Never ask more than one question at a time
    - Extract information from natural responses (if they say "I'm a CTO at Acme",
      extract both role and company)
    - Be conversational, not robotic
    - After collecting use_case, company, role, and timeline, ask for email
    - Use update_lead_field to store extracted information
    - If the lead score is high, express enthusiasm and offer to book a demo""",
    tools=[update_lead_field, get_qualification_status],
)

CRM Integration

When the lead is qualified, push it to your CRM. Here is a HubSpot integration example:

interface HubSpotContact {
  email: string;
  firstname?: string;
  lastname?: string;
  company?: string;
  jobtitle?: string;
  hs_lead_status: string;
  lead_score: number;
}

async function pushToHubSpot(lead: LeadData): Promise<string> {
  const nameParts = (lead.name || "").split(" ");

  const contact: HubSpotContact = {
    email: lead.email!,
    firstname: nameParts[0],
    lastname: nameParts.slice(1).join(" "),
    company: lead.company || undefined,
    jobtitle: lead.role || undefined,
    hs_lead_status: lead.grade === "hot" ? "NEW" : "OPEN",
    lead_score: lead.score,
  };

  const response = await fetch(
    "https://api.hubapi.com/crm/v3/objects/contacts",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${process.env.HUBSPOT_TOKEN}`,
      },
      body: JSON.stringify({ properties: contact }),
    },
  );

  if (!response.ok) {
    const error = await response.json();
    if (error.category === "CONFLICT") {
      return await updateExistingContact(lead.email!, contact);
    }
    throw new Error(`HubSpot API error: ${error.message}`);
  }

  const result = await response.json();
  return result.id;
}

Real-Time Score Display

Give the user a sense of progress by subtly showing qualification advancement. On the backend, recalculate the score after each field update and send it to the frontend:

Still reading? Stop comparing — try CallSphere live.

CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.

async def on_field_update(ws, engine: QualificationEngine):
    score = engine.lead.calculate_score()
    await ws.send_json({
        "type": "lead_progress",
        "fields_collected": len(engine.completed_fields),
        "total_fields": len(QUALIFICATION_FLOW),
        "score": score,
        "grade": engine.lead.grade.value,
    })

FAQ

How do I prevent the agent from feeling like an interrogation?

Interleave value-giving with questions. After the user shares their use case, provide a relevant insight or case study before asking the next question. Limit consecutive questions to two before offering something helpful. The conversation should feel like a consultative discussion, not a form with a chatbot face.

What if the user provides their email early — should I skip ahead?

Yes. Always extract information opportunistically. If the user says "I'm John at [email protected], we need help with X," extract the name, email, and use case in one pass, skip those steps in the flow, and move directly to the questions you still need answered. Rigid flows that repeat already-answered questions frustrate users and reduce conversion rates.

How do I handle leads who refuse to share their email?

Respect the boundary. Offer alternatives: "No problem at all. Would you prefer I share some resources you can review on your own?" Provide value regardless — a useful recommendation or link. Track these sessions separately as anonymous qualified leads. Often, users return later and are more willing to share contact information after seeing the agent is genuinely helpful.


#LeadQualification #Sales #CRM #Scoring #ChatAgent #AgenticAI #LearnAI #AIEngineering

Share

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.

Related Articles You May Like

AI Strategy

Outbound Sales Chat in 2026: 11x, Artisan, and Why Pure-AI BDR Replacement Reverted

11x.ai and Artisan promised to replace BDRs entirely. By 2026 most adopters reverted to hybrid models. Here is the outbound chat pattern that actually works.

AI Voice Agents

Voice Agent + CRM in 2026: Salesforce, HubSpot, and the API Limit Trap

Outbound AI voice agents writing to CRMs at 50k+ calls per day hit Salesforce API limits fast. The integration playbook that actually scales.

AI Voice Agents

Financial Advisor Voice AI 2026: KYC Pre-Screen + Discovery Call Booked

Independent RIAs and advisors lose qualified prospects to slow callbacks. Here is how a 2026 voice agent runs a structured pre-screen, soft-AUM ask, and books a discovery call cleanly.

Sales

Detroit Sales Teams: Wire CallSphere Voice + Chat Into HubSpot and Salesforce in Under 72 Hours

Wire CallSphere's voice and chat sales agents into HubSpot, Salesforce, or Pipedrive for your Michigan sales team — go-live in under 3 days, full CRM sync.

Sales

Ohio RevOps Playbook: Plug CallSphere Voice + Chat Into Your CRM Without Rewriting a Single Workflow

Wire CallSphere's voice and chat sales agents into HubSpot, Salesforce, or Pipedrive for your Ohio sales team — go-live in under 3 days, full CRM sync.

Sales

Hassle-Free CallSphere Rollout for Pennsylvania Sales Orgs: 5 Concurrent AI Dials, Live Whisper Transcripts, Auto Lead Score

Wire CallSphere's voice and chat sales agents into HubSpot, Salesforce, or Pipedrive for your Pennsylvania sales team — go-live in under 3 days, full CRM sync.