Case studySiteScout

Finding the shops their websites are failing

I built SiteScout to show my PM skills end to end: not just understanding the business problem, but rapid prototyping, fixing bugs in production and deploying it myself. The question it answers: can one person run a complete outreach product, from discovery and qualification to follow-up, on its own for $0 a month?

SiteScout is an outreach product I designed, built and run. It finds local businesses that are losing bookings to their own websites. Then it shows each owner a better version of their site before asking for anything.

Live in production
Move your cursor over the map
Role
Solo builder (personal project)
Timeline
Aug to Sep 2026, about 20 sprints
Team
Solo, built with AI coding tools
Status
Live experiment, running every 10 minutes
6stages that run every 10 minutes on their own
3,300+logged runs in the first three weeks
738automated tests guarding every live send
$0monthly infrastructure, all on free tiers
01The problem

Good prospects are hidden, and generic pitches get deleted.

Plenty of barbershops and salons rank on Google Maps but run websites that quietly cost them bookings. The site is slow on a phone, there's no way to book online, or the phone number is buried.

Fixing that is straightforward. Finding these businesses is the slow, manual part. You search a city, open every site, judge it, hunt for an email address and write a message. The message that finally goes out sounds like every other agency pitch the owner has already ignored.

That gave me two problems to solve. The first was finding the right businesses at a volume one person can't reach by hand. The second was earning a reply from an owner who has never heard of the sender.

02The bet

Show, don't pitch. An owner who sees their own shop on a better site will reply.

This bet shaped the whole product. The first email names one specific problem the owner can check for themselves. After that, a personalised demo site, which I call a ghost site, does the persuading. It uses their real name, services and photos, and it's live for seven days.

kingsrowbarbers-wichita.com
photo still loading

Hours: Tue to Sat, 9 to 6. Walk-ins welcome.

To book an appointment please call us during business hours. Click here for directions.

Their site todaySlow on phones. The only way to book is a phone call while the shop is open.
kings-row.preview-site.com

Sharp cuts on Douglas Avenue.

Open today until 6pm
Book online
Skin fade$32
Beard trim$18
Hot towel$25
The ghost siteBuilt from the shop's own details, bookable in two taps, and linked from the follow-up email.

Illustrative example. The business is made up.

03How it works

From one line of input to a demo site in the owner's inbox.

I type a niche and a city. Everything after that runs on a schedule, and I only step in when an owner replies.

  1. Input

    "Hair salons in Wichita, Kansas"

    The only thing I type.

  2. 01 Discover

    Search the city in circles

    It splits the city into 3 km search circles on Google Places, because a single broad search stops at about 60 results.

  3. 02 Qualify

    Check every website

    It looks for online booking and a call button, runs Google's PageSpeed test, and scores the opportunity from 0 to 100.

  4. 03 Reach out

    Lead with the specific problem

    An AI-written first email names what's wrong. Up to four follow-ups go out, timed for each owner's local morning.

  5. 04 Show

    Build the ghost site

    It builds a demo from the business's real content and publishes it with a seven-day expiry.

  6. 05 Listen

    Read the replies

    It tracks clicks on the demo, reads replies with AI to separate interest from "no thanks", and catches emails that bounced.

An admin dashboard shows the queue, settings and run history, and can run any stage on demand. Built with Python, Notion as the CRM, Google Places and PageSpeed, Gemini, Cloudflare Pages and Workers, and a free Google Cloud server.

04Qualification

Score what costs the owner customers, not what looks old.

My first version qualified leads on seven technical PageSpeed signals. It found sites that were slow but not necessarily losing business. I rebuilt the score around conversion, so missing online booking and a missing call button carry most of the weight. Mobile performance counts, but it can't push a site to the top on its own.

Kings Row Barbers

Opportunity score, illustrative
67.5of 100
Online bookingNot found
40 / 40
Call buttonCouldn't tell
7.5 / 30
Mobile speedPoor
20 / 20

"No online booking, and the site loads poorly on phones. Someone who can't book at 10pm books with the shop down the road."

When the crawler can't tell whether a feature exists, it scores a quarter of the weight. Not finding something isn't proof that it's missing, so "couldn't tell" should never score as high as a confirmed gap. It shouldn't score as if the site were fine, either.

05Key decisions

Five calls that shaped the product.

01Qualification

Make online booking the only pass or fail signal

I also detected each business's website platform, on the theory that an old platform meant an old site. It didn't predict pain, so I removed it. Online booking now decides qualification, and other signals only rank the leads that pass.

Trade-offFewer leads qualify, but each has a sharper reason to reply.

02Rollout

Prove the new score before it decided who got emailed

The system was already sending when I rebuilt the score. I shipped it in three steps: standalone with tests, then alongside the old rules without affecting anything, then as the live gate.

Trade-offAbout a day slower, with no risk of emailing the wrong businesses.

03Cost

Put a hard ceiling on API spend

Google Places allows 5,000 free searches a month, then charges $32 per thousand. Discovery now stops at 4,999 calls however many leads it has found, and resumes on the 1st.

Trade-offLead volume has a monthly limit. Costs can never surprise me.

04Deliverability

Protect the inbox before volume

When real emails started landing in spam, I added one switch that stops all outreach, follow-ups included, while the mailbox warms up. New sends are capped at 10 a day.

Trade-offA full pause, which beat burning the domain's reputation.

05Supply

Never let tomorrow's queue run dry

The system used to ask for a new city only once the current one was used up. Now, when fewer than a day's worth of leads are waiting, it asks every cycle and suggests a mid-sized US city.

Trade-offMore prompts in my inbox, and no more idle days.

—Planning

Plan in epics and numbered stories

Every change to qualification traces back to the user story it served. That made it easy to cut scope later without losing track of why each piece existed.

ResultScope cuts stayed deliberate, not accidental.

06What broke

Most of the product work happened after launch.

Every one of these failed silently. My recurring fix was to make failures loud.

  1. Scheduled runs failed quietly for 13 hours

    After the move to the cloud, the scheduler couldn't find the email tool, and two stages failed on every run.

    Fixed the environment, documented it, and added failure alerts.
  2. Bounced emails looked delivered

    A failed send still showed the lead as contacted in the CRM.

    Added bounce detection, plus a free check that a domain can receive mail before a lead is accepted.
  3. A missing key threw away every lead for 10 days

    Without the AI key, email copy couldn't be written, and qualified leads were dropped with no error.

    The system now refuses to start without the key.
  4. Long searches overlapped the next run

    A slow city search ran into the next cycle and created duplicate records.

    Added a lock that every run, scheduled or manual, has to respect.
  5. A rate limit was quietly losing leads

    The AI model's free tier allowed 20 requests a day, and anything over the limit was discarded.

    Added retries with backoff and moved to a model with a workable free quota.
  6. Emails started landing in spam

    The real bottleneck turned out to be deliverability, not lead quality.

    Paused all outreach for mailbox warmup.
07Scope

What I shipped, and what I chose to wait on.

Shipped
  • Grid-based discovery with a monthly cost cap
  • Conversion-focused scoring with a plain-English reason
  • Problem-specific first emails and four follow-ups
  • Ghost sites with a seven-day expiry and click tracking
  • AI reply sorting and bounce handling
  • An admin dashboard with editable settings and run history
Deliberately deferred
  • Paid tech-stack data, until the score had proved itself without it
  • Putting score weights in the settings panel while they were still changing
  • Fully automatic demo-site deployment. A simpler hand-off uses the same trigger, so nothing downstream will need to change
08What I learned

The bottleneck wasn't where I planned for it.

01Assumptions

The riskiest assumption wasn't the one I planned around.

I spent the early sprints on finding and scoring leads. The real constraint turned out to be whether emails reached the inbox at all.

02Reliability

Silent failure is the most expensive bug.

Most of the incidents above caused no visible damage and still cost real leads. Every stage now fails loudly.

03Constraints

Constraints sharpen priorities.

Free-tier limits, a monthly API ceiling and a daily send cap forced clearer choices than an open budget would have.

04Delivery

Stage the rollout, even as a team of one.

Running new logic alongside the old before switching let me change the core of a live system without harming a single lead.

09Next
  • 01Compare reply rates with and without a ghost site to test the core bet directly
  • 02Report the full funnel, from leads found to demos viewed and replies
  • 03Explore whether the approach could work as a self-serve tool for others

Thanks for reading.

SiteScout is a personal project I built on my own time to show the full range of PM work, from business understanding to prototyping, bug fixing and deployment. Business names and contact details are left out on purpose.