DEV Community

RyanCwynar
RyanCwynar

Posted on • Originally published at ryancwynar.com

How I Built a Self-Running Prospecting Pipeline That Found 150 Leads in a Week

I got tired of manually searching for prospects. So I built a system that does it for me — every two hours, across four different campaigns, completely hands-off.

Here's how it works and what I learned.

The Problem

I'm selling AI services to local businesses — dentists, law firms, medical practices in South Florida. The kind of businesses that still have websites saying "YES, WE ARE NOW ON THE WORLD WIDE WEB!!" in 2026.

Finding them manually was eating 2-3 hours a day. Search Google Maps, check the website, grab the phone number, add to a spreadsheet. Repeat. Soul-crushing work that a machine should be doing.

The Architecture

The system runs on a single VPS (Hostinger, $10/month) and uses three main pieces:

  • Redis as the queue — prospects get pushed onto a list with their name, phone, website, city, and campaign tag
  • Cron jobs that fire every 2 hours, each running a different campaign angle
  • Google Maps scraping to find businesses matching specific criteria

Each cron job searches for a different type of business in a different South Florida city, validates the results against what's already in the queue (dedup by phone number), and pushes new prospects to Redis.

Four Campaigns, One Queue

Instead of one generic pitch, I'm running four parallel campaigns with different hooks:

  1. Receptionist — "What happens when someone calls after hours?"
  2. Reviews — "How are you handling negative Google reviews?"
  3. AI — "Which tasks eat most of your admin time?"
  4. Boring — "What's the most repetitive thing you do every day?"

Same target market, different angles. The prospect finder tags each lead with its campaign, so downstream outreach (SMS via Twilio, email via Mailgun) uses the right messaging.

This isn't A/B testing one variable. It's testing four completely different assumptions about what local business owners care about.

Deduplication Matters More Than You Think

The biggest lesson: dedup logic is everything. When you're running 8+ searches per day across overlapping geographies, you'll hit the same businesses constantly. My first version had no dedup and the queue bloated with duplicates within hours.

Now every prospect gets checked against the existing queue by phone number before insertion. Simple, but it cut waste by about 60%.

The Numbers

After one week of running:

  • 153 unique prospects in the queue
  • 4 campaign categories tagged and ready
  • ~30 duplicates caught and skipped per day
  • Zero manual intervention after initial setup

The system runs on cron, logs everything to daily memory files, and I check in once a day to review what it found.

What I'd Do Differently

Redis is fine for a queue this size, but I'm already hitting the limits of storing everything as a single JSON blob. Next iteration will use PostgreSQL with proper indexing — I already have a Postgres instance running on the same box.

I'd also add automatic website quality scoring. Right now I manually check if a prospect's site is outdated enough to need help. A simple Lighthouse score or even just checking for mobile responsiveness would automate that filter.

The Stack

  • Server: Hostinger VPS, Ubuntu, Docker
  • Queue: Redis with JSON list operations
  • Scheduling: Cron jobs (every 2 hours, staggered)
  • Search: Google Maps API for business discovery
  • Outreach: Twilio (SMS) + Mailgun (email)
  • Monitoring: Daily markdown logs, reviewed by AI assistant

Total infrastructure cost: about $15/month.

Takeaway

The best prospecting system is the one that runs while you sleep. Mine found 150 leads in a week for the cost of a couple coffees. The hard part wasn't the code — it was getting the dedup and campaign tagging right so the downstream outreach actually makes sense.

If you're doing manual prospecting for more than an hour a day, you're leaving money on the table. Automate the search, focus your energy on the conversation.

Top comments (0)