Internal tool · 2026
Trawl
PrivateFinding the businesses that need a website, with Claude.
- Role
- Design and engineering, solo
- Timeline
- Built in a concentrated burst
The problem
The businesses most likely to need a website are the hardest ones to find, because by definition they do not have one to find. They exist as a maps listing, a phone number and a stack of reviews.
The reviews are the interesting part. A restaurant with forty comments complaining that you cannot see the menu online has told you exactly what to build, in its own customers' words. That is a far better opening than a cold template.
What it does
Trawl scrapes listings for Singapore businesses with no real web presence, pulls their reviews, and runs those through the Claude API to extract recurring, concrete complaints — not a sentiment score, but the specific operational problem a website would actually solve.
What comes out is a dashboard of qualified prospects with the evidence attached, so any outreach can reference something real.
The constraints that shaped it
A 60-second ceiling. The scrape endpoint runs on a hosting tier that terminates a function at 60 seconds, which is well short of a full crawl. So the endpoint starts the job, returns a run ID immediately, and a separate poll-and-import path collects the result later. Nothing blocks on the crawl.
Cost per lead. Enrichment reads review text from the database and never re-hits the scraping API, so re-running analysis on a prospect costs nothing extra. Getting that boundary wrong is how a lead tool quietly turns into a monthly bill nobody budgeted for.
Small, trusted user base. Sign-in is username and password rather than email, because it is an internal tool with a handful of operators and nobody wants an inbox round-trip to log in. New accounts sit pending until an admin approves them, and a policy check prevents the last remaining admin from deleting themselves out of the system.
Honest scope
This is a working internal tool, not a product. It was built in a concentrated burst on top of patterns I already had, and it carries 42 tests over the paths that would cost real money if they broke.
It is here because it is the clearest example of using a language model as a component rather than as an assistant — structured extraction inside a pipeline, with a defined output shape, a cost ceiling and tests around it. That is a different discipline from asking a chatbot for help, and it is the one clients are actually asking about now.
Stack
- Next.js 15 (App Router), TypeScript
- Supabase — Postgres, Auth, row-level security
- Apify — Google Maps listing crawler
- Anthropic Claude API — structured extraction
- Vitest and Playwright
Need something in this shape?
Tell me what you are trying to build and roughly when you need it. I reply to every enquiry within one business day, including the ones I am not the right fit for.