THE PROBLEM
"No website" on a listing is usually wrong
Finding businesses that need a website sounds easy: look for the ones whose Google listing has none. When I checked 19 of those by hand, 10 had a website after all. The listing only shows what the owner typed into it.
A call list built on that field wastes half its calls, and ringing a business about a website it already has is a poor way to start. The rest of a sales day has the same problem in smaller pieces: who was promised a call back, who never answered, and who to try next.
WHAT I BUILT
The data, the morning list, and the rest of a CRM
THE DATA
- One pull of the whole area: 106,937 business listings, bought once rather than search by search.
- Narrowed to our trades: 21,474 businesses in 43 categories, sorted by our own rules.
- A check before any call: two searches, a guess at the domain, and a match on phone number and street address, so "no website" means none.
THE MORNING LIST
- Ten calls by 6:30 every weekday: promised call-backs, previews built but never called, retries, anyone not reached, then new businesses that passed the check.
- Each card has tap to call, the first search result with a link to the same search, and one-tap outcomes with an exact undo.
- The day is drawn as our mark filling square by square, with a streak, points weighted toward booked calls, and a weekly goal.
THE REST OF A CRM
- A list with bulk actions and an export, and a drag-and-drop pipeline board.
- A page per business with its whole history, and one search across names, any phone format, emails, addresses and notes.
- Sales read from Stripe through a read-only key, and the content engine on its own tab.
- A booked call becomes a site brief with one button.
KEPT SAFE
- Every page reads through a login, with row-level security on every table in the database.
- A probe proves the public key reaches nothing: every table and function, checked against the live database.
- Contact details come from the data provider or the business itself, never from sources whose terms forbid keeping them.
HOW IT FLOWS
From a whole area to today's ten
The first four steps happen before the day starts. The amber steps are mine.
- Pull the area106,937 listings, in one purchase.
- Keep our trades21,474 businesses in 43 categories.
- Check for a siteTwo searches, a domain guess, and a phone and address match.
- Fill the dayAt 6:30, ten calls in the order that matters.
- CallOne tap from the card.
- Record itOne tap for the outcome, with an exact undo.
- Book the callA booked call throws squares, and becomes a site brief.
- Come backPromised call-backs return first on the right morning.
Runs on its ownA person does it
THE SIZE OF IT
What it holds
- 21,474local businesses in the CRM
- 43trades and categories, sorted by our own rules
- 10calls ready every weekday morning
- 10 of 19"no website" listings that had one when checked by hand
WHAT I DID
What I did
Checked listings by hand before trusting them, which is how the "no website" field was caught.
One pull of the whole area instead of paying per search, kept and reused.
The searches, the domain guess and the phone and address match that run before any call.
The order of the list, the outcomes, the undo, and the game that makes a call day visible.
The list, the pipeline, the business pages, the search and the Stripe sales.
Row-level security on every table, and a probe that proves nothing is reachable without a login.
BUILT WITH
Built with
- Next.js
- TypeScript
- Tailwind CSS
- Supabase (Postgres, row-level security)
- Vercel Cron
- DataForSEO
- Stripe (read-only)
- Resend
- Claude Code