Internal tool · 2026
Trawl
Finding the businesses that need a website, with Claude.
- Role
- Design and engineering
- Timeline
- Built in a concentrated burst
- Status
- Private
- Year
- 2026

01 / The problem
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.
02 / What it does
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: the specific operational problem a website would solve.
What comes out is a dashboard of qualified prospects with the evidence attached, so any outreach can reference something real.
03 / The constraints that shaped it
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 turns into a monthly bill nobody budgeted for.
Small, trusted user base. Sign-in is username and password, because an internal tool with a handful of operators has no business doing inbox round-trips 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.
04 / The scope
The 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 39 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 discipline is the one clients are asking about now.
Stack
- 01Next.js 15 (App Router), TypeScript
- 02Supabase: Postgres, Auth, row-level security
- 03Apify for the Google Maps listing crawl
- 04Anthropic Claude API for structured extraction
- 05Vitest and Playwright