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]
Every page does the same 4 things:
- Set
window.LEAD_WEBHOOK_URLin<head> - Form
submitevent callssubmitLead({email, source, tier, ...}) - POST JSON to webhook with rich UTM + page context
- 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});
}
};
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
tierfield 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:
- Write 1 lead-capture HTML in 30 min
- Stand up the webhook in 30 min
- Drive 100 visitors via 1 dev.to or Substack post
- 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)