DEV Community

孫昊
孫昊

Posted on

Building a $0 B2B Funnel: 15 Static HTML Lead Pages + Webhook

TL;DR: Static HTML + a single Cloudflare Workers webhook captures email leads with full UTM + tier scoring. No SaaS, no monthly fees. 15 pages live in 3 days. Real funnel conversion data below.


The pitch

You've seen the SaaS lead-capture stack: HubSpot + Calendly + Mailchimp + Zapier = ~$200/month before any leads.

I'm a solo iOS dev. I needed lead capture for B2B consulting that pays for itself before I monetize. Here's the $0 alternative.

Architecture

[15 HTML pages] → [Cloudflare Workers webhook] → [JSON log + email digest]
Enter fullscreen mode Exit fullscreen mode

Every page does the same 4 things:

  1. Set window.LEAD_WEBHOOK_URL in <head>
  2. Form submit event calls submitLead({email, source, tier, ...})
  3. POST JSON to webhook with rich UTM + page context
  4. Webhook appends to JSON log + sends daily digest email

That's it. No tracking pixel, no third-party JS, no GDPR pain.

The lead-capture pages

Page Lead source Tier scoring
b2b-quiz.html 7-question fit quiz tier_a (0-3) / tier_b (4-7) / tier_c (8+)
roi-calculator.html ROI estimate input tier when yearlyTotal > 0
quote-calculator.html Multi-step quote tier locked at step 2/3
book-call.html Calendly + email pre-capture warm
free-ai-audit.html 47-question audit hot/warm by completion %
free-templates.html Email template library warm
index.html Newsletter signup at scroll-50 cold
8 more pages Various ICP-specific lead magnets varies

The webhook (Cloudflare Workers)

~50 lines of TypeScript. Append-only log to KV, send daily SES digest. Done.

export default {
  async fetch(req: Request, env: Env) {
    const lead = await req.json();
    lead.timestamp = new Date().toISOString();
    lead.ip = req.headers.get('CF-Connecting-IP');

    await env.LEADS_KV.put(`lead:${lead.timestamp}`, JSON.stringify(lead));

    // Score-based routing
    if (lead.tier === 'tier_c') {
      await sendImmediateNotification(env, lead);
    }

    return new Response('ok', {status: 200});
  }
};
Enter fullscreen mode Exit fullscreen mode

Conversion data (3 weeks since launch)

Metric Value Notes
Unique visitors ~600 from organic Substack + 2 dev.to posts
Email captures 47 7.8% conversion
Tier C (sales-ready) 3 6.4% of captured
Calls booked 1 from tier-C
Honest signal low Cold start, no follower base

The number that matters: 1 call booked from $0 funnel in 3 weeks. SaaS stack would have cost $400-600 over the same period to reach the same signal.

What I'd skip if doing again

  • Quote calculator — too many fields. Lower-friction "quick-quote 60s" version converts 3× better
  • Pricing A/B test page — needs more traffic to mean anything
  • Refer-a-friend $50 — no one shares before they've experienced value

What surprised me

  • The tier field at submit-time is more useful than time-of-day or device-class
  • Pre-checking inboxes via the webhook digest beats a CRM dashboard 10×
  • Static HTML loads in 200ms vs SaaS-embed 2-4s. Conversion correlates with load time
  • Users like the no-tracking-pixel privacy claim — it's a differentiator for B2B

The boring truth

Most B2B funnels fail because of bad copy, not bad tech. The webhook took 2 hours. The 15 pages took 3 days. Iterating the copy on which page converts is still taking weeks.

If you're cold-starting, do this:

  1. Write 1 lead-capture HTML in 30 min
  2. Stand up the webhook in 30 min
  3. Drive 100 visitors via 1 dev.to or Substack post
  4. Watch conversion. Iterate copy weekly

Don't build the funnel before you can write the post.

Source

GitHub Pages source — all 15 pages public, MIT licensed. Fork freely.


Want the 30-day execution plan from cold start to first paid client? iOS Indie Launch Playbook on Gumroad — covers B2B + product launches, real numbers.

Top comments (0)