Finding Leads and Generating Website Demos
Given a target niche/location (e.g., "dentists in Austin, TX"), produce four deliverables in sequence:
leads.xlsx— 25-100 qualified leads with contact info- One demo HTML/CSS file per lead (
demo-{business-slug}.html) - Cloudflare Pages deployment steps per demo
- One WhatsApp message per lead, with the live URL inserted
Do not skip ahead — each stage depends on the output of the previous one. Track progress with the checklist in the Workflow section.
Progress:
- [ ] Step 1: Source 25-100 leads, verify each has email, phone, or Instagram
- [ ] Step 2: Build structured Excel spreadsheet
- [ ] Step 3: Generate personalized demo landing page per lead
- [ ] Step 4: Write Cloudflare Pages deployment instructions (generic + per-lead naming)
- [ ] Step 5: Draft WhatsApp message per lead with live URL placeholder/final link
Step 1: Source Leads
Qualify a lead as "needs a website" if one of these is true:
- No website found in search/maps listing
- Website is broken, unstyled, or clearly abandoned (no SSL, outdated copyright year, Flash/table-based layout)
- Only has a Facebook/Instagram page as their "web presence"
Each lead must have at least one of: email, phone number, Instagram handle. Prioritize leads with phone + Instagram (needed for WhatsApp + visual context).
Capture per lead:
- Business name
- Category/niche (e.g., "bakery", "plumber", "yoga studio")
- City/region
- Phone (with country code if possible)
- Email (if available)
- Instagram handle (if available)
- Current web presence status (none / broken / social-only)
- Notes (e.g., tone of business, standout detail to personalize outreach)
If sourcing from a provided list/CSV, dedupe by phone+name. If sourcing via search, cap at the requested range (default to 50 if unspecified) and stop once qualified.
Step 2: Build the Spreadsheet
Use openpyxl (or pandas.to_excel) to produce leads.xlsx with one row per lead and these columns, in order:
| # | Business Name | Category | City | Phone | Email | Instagram | Web Status | Demo File | Live URL | Notes |
- Freeze header row, autofit column widths, bold headers.
- Leave
Live URLblank until Step 4 deployment is confirmed — fill in afterward. Demo Filecolumn stores the filename generated in Step 3 for traceability.
Step 3: Generate Personalized Demo Pages
For each lead, output a single self-contained HTML file (inline <style>, no external deps) named demo-{business-slug}.html. Personalize:
- Business name in
<title>, hero heading, and footer - Industry-appropriate hero image placeholder (use a relevant Unsplash source URL or CSS gradient matching the niche color palette — e.g., warm tones for bakeries, blues/greens for medical/dental)
- Sections: Hero (name + tagline + CTA button), About/Services (3 generic but niche-relevant service cards), Contact (phone, email/Instagram, embedded Google Maps iframe using city name), Footer
- A visible "This is a free demo built for [Business Name] — contact us to make it live!" banner, since these are outreach demos, not final deliverables
- Mobile-responsive via CSS flexbox/grid + media queries, no JS frameworks required
Template skeleton to adapt per lead:
HTML<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{Business Name} | {Category} in {City}</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> :root { --primary: {hex-color-for-niche}; --dark: #1a1a1a; } * { margin:0; padding:0; box-sizing:border-box; font-family: 'Segoe UI', sans-serif; } .banner { background:var(--primary); color:#fff; text-align:center; padding:10px; font-size:14px; } .hero { background: linear-gradient(135deg, var(--primary), #000); color:#fff; padding:100px 20px; text-align:center; } .hero h1 { font-size: 3rem; } .hero p { font-size:1.2rem; margin:15px 0 30px; } .cta { background:#fff; color:var(--primary); padding:15px 30px; border-radius:30px; text-decoration:none; font-weight:bold; } .services { display:grid; grid-template-columns:repeat(auto-fit, minmax(220px,1fr)); gap:20px; padding:60px 10%; } .card { border:1px solid #eee; border-radius:12px; padding:30px; text-align:center; box-shadow:0 2px 8px rgba(0,0,0,0.05); } .contact { background:#f7f7f7; padding:60px 10%; text-align:center; } footer { background:var(--dark); color:#aaa; text-align:center; padding:20px; font-size:13px; } @media(max-width:600px){ .hero h1{font-size:2rem;} } </style> </head> <body> <div class="banner">🚀 Free demo built for {Business Name} — contact us to make it live!</div> <section class="hero"> <h1>{Business Name}</h1> <p>{Niche-tailored tagline}</p> <a class="cta" href="#contact">Get In Touch</a> </section> <section class="services"> <div class="card"><h3>{Service 1}</h3><p>{short desc}</p></div> <div class="card"><h3>{Service 2}</h3><p>{short desc}</p></div> <div class="card"><h3>{Service 3}</h3><p>{short desc}</p></div> </section> <section class="contact" id="contact"> <h2>Visit Us in {City}</h2> <p>📞 {Phone} | 📧 {Email or Instagram handle}</p> </section> <footer>© 2024 {Business Name}. Demo site — not yet live.</footer> </body> </html>
Save each file into a /demos folder, named to match the spreadsheet's Demo File column.
Step 4: Deploy to Cloudflare Pages (free staging URL)
Provide these instructions once (reusable for all leads), plus the per-lead project naming convention:
- Go to https://dash.cloudflare.com → Workers & Pages → Create → Pages → Upload assets.
- Project name: use the lead's slug, e.g.
demo-joes-bakery(lowercase, hyphenated, must be globally unique on your account). - Drag-and-drop the single
demo-{business-slug}.htmlfile. Rename it toindex.htmlbefore upload (Cloudflare Pages servesindex.htmlat root). - Click Deploy site. Cloudflare issues a live URL instantly:
https://demo-{business-slug}.pages.dev. - Copy that URL into the
Live URLcolumn ofleads.xlsxfor that lead. - Repeat per lead — each demo is its own Pages project (free tier supports unlimited projects).
- (Batch option) For many leads, use
wrangler:
Put each lead's renamedBashnpm install -g wrangler wrangler login wrangler pages deploy ./demos/{business-slug} --project-name=demo-{business-slug}index.htmlin its own subfolder under/demos/{business-slug}/first.
Step 5: Draft WhatsApp Outreach Message
One message per lead, personalized, casual-professional tone, under ~60 words, with the live URL from Step 4 inserted. Format for direct paste into WhatsApp Web (no markdown, use emojis sparingly).
Template:
Hi {Business Name} team! 👋 I noticed {specific observation — e.g., "you don't have a website yet" / "your current site isn't mobile-friendly"}. I put together a free demo page for you: {Live URL}
No obligation — just wanted to show what's possible. Want me to make it live on your domain? Happy to chat!
Output as a table/list mapping lead → final WhatsApp message, matching the spreadsheet row order, so it can be copy-pasted or bulk-sent via a WhatsApp Web automation tool.
Example 1: Input: Niche = "family dentists", City = "Denver, CO", target count = 30 Output:
leads.xlsxwith 30 rows (dentist name, phone, email/Instagram, "no website" status)- 30 files in
/demos/, e.g.demo-brightsmile-dental.html, each with blue/white medical color scheme and "Teeth Cleaning / Cosmetic Dentistry / Emergency Care" service cards - Deployment steps producing
https://demo-brightsmile-dental.pages.dev - WhatsApp message: "Hi Bright Smile Dental team! 👋 I noticed you don't have a website yet — patients often check online before booking. I put together a free demo: https://demo-brightsmile-dental.pages.dev No obligation, just wanted to show what's possible. Want me to make it live on your domain?"
Example 2: Input: Niche = "hair salons", City = "Miami, FL", only Instagram available (no phone/email) Output: Lead still qualifies (Instagram present). WhatsApp message instead becomes an Instagram DM-ready message (note this substitution explicitly when phone is absent), same structure, sent via Instagram DM instead of WhatsApp.
- Always verify "no website" claims with an actual search before including a lead — false positives waste outreach credibility.
- Match hero image/color palette to the business niche; generic gray templates reduce response rates.
- Keep each demo to a single HTML file — simplifies both review and Cloudflare upload.
- Use consistent, predictable slugs (
business-name-citylowercased, hyphenated) across spreadsheet, filenames, and Pages project names so everything stays traceable. - Fill
Live URLin the spreadsheet immediately after each deployment, not in a separate pass — avoids mismatches. - Keep WhatsApp messages short and specific to the business (mention something real, like their category or city) — generic mass-text phrasing gets ignored or flagged as spam.
- Don't include leads missing all three contact methods (email, phone, Instagram) — they're unreachable and break the outreach step.
- Don't reuse one Cloudflare Pages project name for multiple leads — names must be unique or deploys will overwrite each other.
- Don't forget to rename the demo file to
index.htmlbefore upload — Cloudflare won't serve it at the root URL otherwise. - Don't load external JS frameworks/CDNs with flaky uptime in the demo — keep it self-contained so it always renders correctly when prospects click the link.
- Don't send identical WhatsApp copy to every lead — swap in the specific observation/detail per business, or it reads as spam.