SaaS Demo Request Form: B2B Lead Generation with Lead Scoring
Demo request forms are the front door to enterprise sales. The difference between a high-converting form and a mediocre one isn't just conversion rate - it's lead quality. Here's how to build forms that qualify leads automatically while keeping friction low enough to actually get submissions.
The challenge with B2B forms is balancing information collection against form abandonment. Every field you add reduces completion rate. But every field you skip means less qualification data for sales. The answer isn't fewer fields - it's smarter fields that earn their place.
We'll build a demo request form that scores leads in real time, routes high-value prospects to immediate attention, and adapts its questions based on what the user has already told you.
Contact Information Basics
Start with the essentials: name, work email, and phone. Work email is critical - it tells you the company and filters out gmail.com tire-kickers. Phone is optional but valuable for high-intent leads.
const contactSection = form.addSubform('contact', {
title: 'Contact Information'
});
contactSection.addRow(row => {
row.addTextbox('firstName', {
label: 'First Name',
isRequired: true
});
row.addTextbox('lastName', {
label: 'Last Name',
isRequired: true
});
});
contactSection.addRow(row => {
row.addEmail('workEmail', {
label: 'Work Email',
isRequired: true,
placeholder: 'name@company.com'
});
row.addTextbox('phone', {
label: 'Phone Number',
pattern: '^[0-9\-\+\(\)\s]+$'
});
});The placeholder "name@company.com" subtly communicates that personal email addresses aren't what you're looking for. It's a soft filter without explicit rejection.
Company Qualification
Company size and industry are the two most important qualification signals. A 1,000-person fintech company is a very different prospect than a 5-person retail shop. Collect this upfront to inform everything that follows.
const companySection = form.addSubform('company', {
title: 'Company Information'
});
companySection.addRow(row => {
row.addTextbox('companyName', {
label: 'Company Name',
isRequired: true
});
row.addTextbox('jobTitle', {
label: 'Job Title',
isRequired: true
});
});
companySection.addRow(row => {
row.addDropdown('companySize', {
label: 'Company Size',
options: [
{ id: '1-10', name: '1-10 employees' },
{ id: '11-50', name: '11-50 employees' },
{ id: '51-200', name: '51-200 employees' },
{ id: '201-500', name: '201-500 employees' },
{ id: '501-1000', name: '501-1,000 employees' },
{ id: '1000+', name: '1,000+ employees' }
],
isRequired: true
});
row.addDropdown('industry', {
label: 'Industry',
options: [
{ id: 'tech', name: 'Technology' },
{ id: 'finance', name: 'Finance & Banking' },
{ id: 'healthcare', name: 'Healthcare' },
{ id: 'retail', name: 'Retail & E-commerce' },
{ id: 'manufacturing', name: 'Manufacturing' },
{ id: 'education', name: 'Education' },
{ id: 'other', name: 'Other' }
]
});
});Job title is required because it matters for routing. A CEO at a 50-person company gets different treatment than an analyst researching vendors. You need to know who you're talking to.
Pro tip
Company size ranges should match your sales segmentation. If you have SMB, mid-market, and enterprise teams, your size options should align with those cutoffs so routing is automatic.
Built-In Lead Scoring
Here's where code-based forms shine. Calculate a lead score in real time based on every answer. This score can route leads to different queues, trigger different follow-up sequences, or prioritize the sales queue.
// Lead scoring based on company size and role
const leadScore = form.computedValue(() => {
let score = 0;
// Company size scoring
const sizeScores: Record<string, number> = {
'1-10': 10,
'11-50': 20,
'51-200': 40,
'201-500': 60,
'501-1000': 80,
'1000+': 100
};
score += sizeScores[companySize.value() ?? ''] ?? 0;
// Role-based scoring
const title = (jobTitle.value() ?? '').toLowerCase();
if (title.includes('ceo') || title.includes('founder') || title.includes('owner')) {
score += 50;
} else if (title.includes('vp') || title.includes('director') || title.includes('head')) {
score += 40;
} else if (title.includes('manager') || title.includes('lead')) {
score += 25;
}
// Timeline urgency
const timelineScores: Record<string, number> = {
'immediate': 30,
'1-month': 25,
'1-3-months': 15,
'3-6-months': 5,
'just-looking': 0
};
score += timelineScores[timeline.value() ?? ''] ?? 0;
return score;
});
// Use score for routing
const isHighPriority = form.computedValue(() => leadScore() >= 80);The scoring logic is transparent and adjustable. If your sales team says VP-level titles should score higher, change one number. If immediate timeline matters more than company size for your business, adjust the weights.
Use Case and Needs Assessment
Generic demo requests waste everyone's time. "I want to see a demo" tells sales nothing about what to show. Collect use cases upfront so demos can be tailored to actual needs.
const needsSection = form.addSubform('needs', {
title: 'Your Needs'
});
needsSection.addRow(row => {
row.addSuggestionChips('useCases', {
label: 'What are you looking to solve?',
suggestions: [
{ id: 'automation', name: 'Process Automation' },
{ id: 'collaboration', name: 'Team Collaboration' },
{ id: 'analytics', name: 'Analytics & Reporting' },
{ id: 'integration', name: 'System Integration' },
{ id: 'compliance', name: 'Compliance & Security' },
{ id: 'scaling', name: 'Scaling Operations' }
],
min: 1
});
});
needsSection.addRow(row => {
row.addDropdown('currentSolution', {
label: 'Current Solution',
options: [
{ id: 'competitor-a', name: 'Competitor A' },
{ id: 'competitor-b', name: 'Competitor B' },
{ id: 'spreadsheets', name: 'Spreadsheets/Manual' },
{ id: 'homegrown', name: 'In-house Solution' },
{ id: 'none', name: 'Nothing Currently' }
]
});
row.addDropdown('timeline', {
label: 'Purchase Timeline',
options: [
{ id: 'immediate', name: 'Immediately' },
{ id: '1-month', name: 'Within 1 month' },
{ id: '1-3-months', name: '1-3 months' },
{ id: '3-6-months', name: '3-6 months' },
{ id: 'just-looking', name: 'Just exploring' }
],
isRequired: true
});
});Suggestion chips work better than checkboxes for use cases. They're more visual, take less vertical space, and feel less like a survey. The minimum selection of 1 ensures you get at least some signal.
Budget and Authority
These questions feel aggressive but are essential for sales efficiency. A prospect with no budget and no authority to purchase is a tire-kicker, not a lead. Better to know upfront than waste a sales rep's time.
needsSection.addRow(row => {
row.addDropdown('budget', {
label: 'Budget Range',
options: [
{ id: 'under-1k', name: 'Under $1,000/month' },
{ id: '1k-5k', name: '$1,000 - $5,000/month' },
{ id: '5k-10k', name: '$5,000 - $10,000/month' },
{ id: '10k-25k', name: '$10,000 - $25,000/month' },
{ id: '25k+', name: '$25,000+/month' },
{ id: 'unknown', name: 'Not sure yet' }
]
});
row.addDropdown('decisionMaker', {
label: 'Decision Making',
options: [
{ id: 'sole', name: 'I make the final decision' },
{ id: 'part', name: 'Part of buying committee' },
{ id: 'influencer', name: 'I influence the decision' },
{ id: 'researcher', name: 'Researching for others' }
]
});
});
// Conditional follow-up for researchers
needsSection.addRow(row => {
row.addTextbox('decisionMakerName', {
label: 'Decision Maker Name',
isVisible: () => decisionMaker.value() === 'researcher',
isRequired: () => decisionMaker.value() === 'researcher'
});
row.addEmail('decisionMakerEmail', {
label: 'Decision Maker Email',
isVisible: () => decisionMaker.value() === 'researcher'
});
});The conditional follow-up for researchers is clever. If someone admits they're researching for someone else, get that person's contact info. That's the actual decision maker.
Pro tip
"Not sure yet" is a valid budget answer. Don't force people into ranges they haven't determined. But do use that answer in scoring - it signals earlier-stage evaluation.
Demo Preferences and Scheduling
Not everyone wants a live demo. Some prefer to watch a recording first. Others want to dive straight into a trial. Offer options and adapt the follow-up accordingly.
const schedulingSection = form.addSubform('scheduling', {
title: 'Schedule Your Demo'
});
schedulingSection.addRow(row => {
row.addRadioButton('demoType', {
label: 'Demo Preference',
options: [
{ id: 'live', name: 'Live demo with sales rep' },
{ id: 'recorded', name: 'Watch recorded demo first' },
{ id: 'trial', name: 'Start free trial directly' }
],
orientation: 'vertical',
defaultValue: 'live'
});
});
// Live demo scheduling
schedulingSection.addRow(row => {
row.addDropdown('preferredTime', {
label: 'Preferred Time',
options: [
{ id: 'morning', name: 'Morning (9am-12pm)' },
{ id: 'afternoon', name: 'Afternoon (12pm-5pm)' },
{ id: 'flexible', name: 'Flexible' }
],
isVisible: () => demoType.value() === 'live'
});
row.addDropdown('timezone', {
label: 'Timezone',
options: [
{ id: 'pst', name: 'Pacific (PT)' },
{ id: 'mst', name: 'Mountain (MT)' },
{ id: 'cst', name: 'Central (CT)' },
{ id: 'est', name: 'Eastern (ET)' },
{ id: 'other', name: 'Other' }
],
isVisible: () => demoType.value() === 'live'
});
});The scheduling fields only appear for live demo requests. Someone requesting a recording doesn't need to specify their preferred time slot. This is conditional logic reducing friction.
Technical Requirements
For integration-focused use cases, collect technical requirements. This section only appears if the user selected "System Integration" as a use case. No point asking everyone about Salesforce connectivity.
const technicalSection = form.addSubform('technical', {
title: 'Technical Requirements',
isVisible: () => useCases.value()?.includes('integration')
});
technicalSection.addRow(row => {
row.addCheckboxList('integrations', {
label: 'Systems to Integrate',
options: [
{ id: 'salesforce', name: 'Salesforce' },
{ id: 'hubspot', name: 'HubSpot' },
{ id: 'slack', name: 'Slack' },
{ id: 'jira', name: 'Jira' },
{ id: 'sap', name: 'SAP' },
{ id: 'custom', name: 'Custom/Internal Systems' }
],
orientation: 'vertical'
});
});
technicalSection.addRow(row => {
row.addTextarea('technicalNotes', {
label: 'Technical Requirements or Concerns',
placeholder: 'Any specific integration needs, security requirements, or technical questions...',
rows: 3
});
});The textarea for technical notes captures anything the checkboxes miss. "We need SOC 2 compliance" or "Must integrate with our custom ERP" - these details help sales prepare before the call.
Dynamic Submit and Completion
The submit button and completion screen should reflect what the user actually requested. "Request Demo" vs "Start Free Trial" sets correct expectations. The confirmation message should match.
// Configure submit behavior
form.configureSubmitButton({
label: () => {
const type = demoType.value();
if (type === 'live') return 'Request Demo';
if (type === 'recorded') return 'Get Recording';
if (type === 'trial') return 'Start Free Trial';
return 'Submit';
}
});
// Configure completion screen based on selection
form.configureCompletionScreen({
type: 'text',
title: () => {
const type = demoType.value();
if (type === 'live') return 'Demo Requested!';
if (type === 'recorded') return 'Check Your Inbox!';
if (type === 'trial') return 'Trial Activated!';
return 'Thank You!';
},
message: () => {
const type = demoType.value();
if (type === 'live') {
return 'Our team will reach out within 24 hours to schedule your personalized demo.';
}
if (type === 'recorded') {
return 'We\'ve sent the demo recording to your email. Watch at your convenience.';
}
if (type === 'trial') {
return 'Your 14-day trial is ready. Check your email for login credentials.';
}
return 'We\'ll be in touch soon.';
}
});This level of personalization makes the form feel less like a generic lead capture and more like a thoughtful interaction. Small details that compound into a better experience.
See more B2B form examples in our gallery.
Email Domain Validation
Block personal email domains to ensure you're getting business leads. This is a common B2B pattern that improves lead quality significantly.
const personalDomains = ['gmail.com', 'yahoo.com', 'hotmail.com',
'outlook.com', 'aol.com', 'icloud.com'];
const isBusinessEmail = (email: string) => {
const domain = email.split('@')[1]?.toLowerCase();
return domain && !personalDomains.includes(domain);
};
contactSection.addRow(row => {
row.addEmail('workEmail', {
label: 'Work Email',
isRequired: true,
placeholder: 'name@company.com',
// Custom validation message if personal domain detected
tooltip: () => {
const email = workEmail.value() ?? '';
if (email && !isBusinessEmail(email)) {
return 'Please use your work email address';
}
return undefined;
}
});
});You can make this a hard block or a soft warning. Hard blocks reduce submissions but improve quality. Soft warnings let people proceed but flag the lead for review.
CRM Integration Data
Structure your form data to match your CRM fields. This makes integration seamless and ensures all qualification data flows through to sales.
// On form submission, structure data for CRM
form.configureSubmitBehavior({
sendToServer: true
});
// The submission payload will include:
// - All field values by ID
// - Computed lead score
// - Timestamp and source tracking Consider what fields your CRM expects and name form fields to match. companySize should match your CRM's company size field. This eliminates mapping headaches during integration.
Putting It Together
A complete demo request form flows logically: contact info establishes who's asking, company info qualifies the opportunity, needs assessment explains why, and preferences determine next steps. Lead scoring runs throughout, informing how urgently sales should respond.
The form adapts based on answers. Integration users see technical questions. Researchers are asked for decision maker info. Live demo requesters specify scheduling preferences. Everyone else skips those sections entirely.
Common Questions
How many fields is too many for a demo form?
The real limit is perceived effort, not field count. 15 well-organized fields with smart conditionals can feel lighter than 8 poorly designed ones. Group fields logically, use progressive disclosure, and make sure every field earns its place with clear sales value.
Should I gate recorded demos behind the same form?
Use a shorter form for recorded demos - just email and company. It's a lower-intent action, so match the friction to the commitment. You can collect more info when they request a live follow-up.
How do I handle leads from different countries?
Add a country dropdown and use it for timezone detection and regional sales routing. Some companies also adjust qualification criteria by region - a 50-person company in one market might be equivalent to a 200-person company in another.
What about GDPR consent checkboxes?
If you operate in GDPR jurisdictions, add consent checkboxes for marketing communications. These should be separate from the form submission consent (which is implied by submitting). Make them optional and track the response for compliance.