GMT+8 SG --:-- 0000 X 0000 Y /
← 全部文章← All writing

VOLO engineering diary

Engineering Diary, Day 16: From 'Nice Website' to 'Take My Money' — Building a Conversion Funnel in One Day

Originally published on flyvolo.ai as part of the VOLO Engineering Diary (2026-03-08), documenting the build of the VOLO private-aviation platform between February and May 2026. When VOLO changed direction in September 2026 the 25 entries were moved here as an archive. The text is unchanged; the products, pages and links it mentions no longer exist. Original byline: VOLO CTO.

The Problem: A Beautiful Dead End

Yesterday we shipped analytics, scroll tracking, and speed fixes. But looking at the site with fresh eyes, I realized something embarrassing: we had no conversion funnel.

Every call-to-action on the site — "Explore Fleet," "Get Started," "Contact Us" — either scrolled the page or linked to /contact. That contact page was a generic form with name, email, and message fields. No flight details. No aircraft preference. No date. Just "tell us what you want" — the digital equivalent of walking into a Rolls-Royce dealership and being handed a suggestion box.

For a platform that promises AI-powered instant quotes, we were making users fill out a form and wait for an email. The gap between promise and reality was embarrassing.

What We Built

Eleven new components, one new API route, 1,400+ lines of code, 30+ files changed. Everything shipped in three commits.

1. QuickQuoteModal — The Heart of the Funnel

A global modal component with real functionality:

  • Airport autocomplete: Fuse.js search across 7,900+ airports, shows IATA codes
  • Date picker and passenger count
  • Email capture for lead follow-up
  • Submits to /api/v1/quotes/lead-capture

The key architectural decision: a QuoteModalProvider context wrapping the entire app. Any component anywhere in the tree can call openQuoteModal(). This means we can add quote triggers to any page without prop drilling or state management gymnastics.

// Any component can now trigger the quote flow
const { openQuoteModal } = useQuoteModal();
<button onClick={openQuoteModal}>Get Quote</button>

2. FloatingCTA Upgrade

The floating "Get a Quote" button in the bottom-right corner previously linked to /contact. Now it opens the QuickQuoteModal directly. Same gold accent styling, same scroll-aware visibility — but now it actually captures leads instead of dumping users on a generic form.

3. ExitIntentPopup — Last Chance Conversion

Desktop only (mouseleave detection doesn't work on mobile). Arms after 5 seconds on page to avoid annoying immediate popups. Shows once per session via localStorage. When triggered, offers one last chance to get a quote before leaving.

The implementation is deliberately gentle: a subtle dark overlay, a clean message, and a single CTA that opens the QuickQuoteModal. No aggressive countdown timers. No fake urgency. Just "Before you go — get a personalized quote in 60 seconds."

4. EmptyLegAlertSignup — Real Email Alerts

The empty legs page had "Set Up Alerts" links that went nowhere. Now there's a real signup form:

  • Email input with route preference (optional)
  • New API route: /api/v1/empty-legs/alerts
  • Preferences stored in Vercel KV
  • Confirmation email sent via Resend

This is our first real email list building feature. When we have empty leg deals, we can now notify interested users.

5. RelatedCaseStudies — Social Proof on Service Pages

Each of the 9 service pages (charter, membership, concierge, empty legs, corporate, group, event, pet travel, air ambulance) now displays 2-3 relevant case studies with stats and testimonials. The mapping is category-based — corporate charter shows Fortune 500 case studies, pet travel shows animal transport stories.

This is classic conversion optimization: when a potential client reads about charter services, they immediately see proof that real companies use VOLO for exactly that use case.

6. BlogQuoteCTA — Inline Content CTA

A styled CTA card inserted between blog post content and the newsletter signup. Every blog reader now sees a quote prompt. Content marketing → lead capture in one scroll.

Trust Signals Everywhere

7. TrustBadges Component

A reusable component showing three trust signals inline: "200+ Models · 50,000+ Jets Worldwide," "98% On-Time Rate," "24/7 Concierge." Added near CTAs on:

  • Homepage hero section
  • All service pages
  • QuickQuoteModal itself
  • CTA sections

Small text, big impact. When someone is deciding whether to click "Get Quote," seeing "98% on-time rate" right below the button reduces hesitation.

8. Hero CTA Optimization

The homepage hero had two buttons: "Explore Fleet" (scrolls down) and "How It Works" (scrolls down). Neither captured leads. Changed the primary button to "Get Instant Quote" → opens QuickQuoteModal. Added a trust micro-line below the buttons. The secondary button remains for users who want to browse first.

AEO: Optimizing for AI Search Engines

9. ServiceFAQ Component with JSON-LD

Google's AI Overviews and ChatGPT search are increasingly pulling structured FAQ data. We built a ServiceFAQ component that renders an accordion UI and injects FAQPage JSON-LD schema into the page head.

Added targeted FAQ sections to four high-traffic service pages:

  • Charter: 4 Q&As (booking lead time, cost factors, airports, cancellation)
  • Empty Legs: 3 Q&As (what are empty legs, savings, booking)
  • Membership: 3 Q&As (tiers, benefits, cost savings)
  • Concierge: 3 Q&As (AI capabilities, languages, availability)

13 total Q&As, each written to match the exact queries people ask AI assistants: "How much does it cost to charter a private jet?" "What is an empty leg flight?" These are Answer Engine Optimization (AEO) targets.

The Copy Fix That Matters Most

10–11. "200+ Aircraft" → "200+ Models · 50,000+ Jets"

CEO caught a critical messaging error. Our trust badges and hero text said "200+ Aircraft" — implying we own or operate 200+ planes. That's misleading. What we actually offer is access to 200+ aircraft models covering 50,000+ private jets worldwide through our operator network.

The distinction matters enormously:

  • "200+ Aircraft" sounds like a small regional fleet
  • "200+ Models · 50,000+ Jets Worldwide" communicates the true scale

Updated across all 4 locales (EN/ZH/FR/ES), TrustBadges component, hero section, and QuickQuoteModal. When you're asking someone to spend $30,000–$500,000 on a flight, every word in your trust signals must be precise and honest.

The Numbers

MetricBeforeAfter
Lead capture points1 (contact page)7+ (modal, floating CTA, exit intent, blog, service pages, hero, empty leg alerts)
CTA → conversion path2 clicks (CTA → /contact → submit)1 click (CTA → modal → submit)
Trust signals near CTAs0Every CTA
FAQ structured data013 Q&As across 4 pages
Email list featuresNewsletter onlyNewsletter + empty leg alerts
New components11
New API routes1
i18n keys added38 (×4 locales)

What's Next

The funnel exists now. Next we need to measure it. Server-side analytics from Day 15 will tell us:

  • How many users see the QuickQuoteModal
  • What percentage complete the form
  • Exit intent trigger rate and conversion
  • Empty leg alert signup volume
  • Which FAQ questions drive the most search impressions

We also need to wire the admin dashboard to real data — right now it shows mock numbers. And payment processing is still the elephant in the room.

Commits

Three commits today across 30+ files:

  • 9b6a1ae — CRO: 6 new features (QuickQuoteModal, ExitIntent, FloatingCTA, EmptyLegAlerts, RelatedCaseStudies, BlogQuoteCTA)
  • b19a422 — Social proof: TrustBadges, Hero CTA optimization, ServiceFAQ with JSON-LD
  • a7af908 — Copy fix: "200+ Aircraft" → "200+ Models · 50,000+ Jets Worldwide"