HostMate is a professional cleaning service marketplace operating across 170+ UK cities. Customers book same-day cleans from £50; cleaners are vetted, and every job ends with a photo report. Here's how I built it and what I learned.
The core challenge
Marketplaces have two sides: supply and demand. For cleaning, supply is local — a cleaner in Manchester can't take a job in London. I needed a system that could match availability by geography, handle real-time booking, and scale as I added cities.
Unlike Uber or Deliveroo, I couldn't assume cleaners were always "on" and nearby. Cleaners work in blocks: a morning slot, an afternoon slot. They might cover 3–4 postcodes in one area. I had to design for that reality.
Architecture decisions
I chose Next.js for the frontend and API routes, PostgreSQL for the database, and Stripe for payments. The stack is familiar, but the real work was in the data model: cities, postcodes, cleaner coverage areas, and slot availability.
Key insight: I treat postcodes as the primary geographic unit. UK postcodes follow a predictable structure (e.g. M1 1AA, M2 2BB). Cleaners define their coverage by postcode prefix (M1, M2, M3 for Manchester). When a customer enters their postcode, I query available cleaners in milliseconds using a simple WHERE coverage_prefixes @> $1 on a PostgreSQL array.
I considered using lat/long and radius-based matching, but postcodes gave cleaner UX (customers know their postcode) and faster queries. I maintain a postcode-to-prefix lookup table for edge cases.
Data model in practice
My core tables: cleaners, bookings, postcode_coverage, availability_slots. A cleaner has many coverage areas; a booking links a customer, cleaner, address, and time window. I use soft deletes for bookings so I can show history without losing data.
Pricing is dynamic: base rate per property size (studio, 1-bed, 2-bed, etc.) plus optional add-ons (oven clean, inside fridge). I store the quote at booking time so price changes don't affect existing bookings.
Same-day booking
Same-day availability required a different approach than standard scheduling. I don't pre-allocate slots — I check cleaner availability at booking time. Cleaners set their "available today" status in the morning; the system matches them to incoming requests.
Flow: customer enters postcode → the system shows available time windows (e.g. "9am–12pm" or "2pm–5pm") → customer selects → I send the request to matched cleaners → first to accept gets the job. I use a short timeout (2 minutes) so customers aren't left waiting. If no one accepts, I expand the radius slightly and retry.
This "request-then-confirm" model reduced no-shows. Cleaners only commit when they know they can make it. Customers get a confirmed booking, not a hope.
Vetting and photo reports
I built the vetting process manually at first: ID check, reference, trial clean. It worked but didn't scale. If I started again, I'd integrate background check APIs (e.g. Sterling, Onfido) from day one. Trust is non-negotiable when you're sending someone into people's homes.
Photo reports were a late addition but turned out to be one of the most valued features. After each job, the cleaner uploads 3–5 photos (before/after key areas). Customers see them in the app; I store them for 90 days. They build trust, reduce "it wasn't clean enough" disputes, and give cleaners proof of work. Simple feature, big impact.
Stripe and payouts
I use Stripe Connect for split payments. Customer pays HostMate; I take a platform fee (15%); the rest goes to the cleaner. Payouts run weekly. I had to handle edge cases: refunds (partial vs full), cancellations (who pays?), and failed payouts. Stripe's documentation is good, but the devil is in the edge cases.
What I'd do differently
- Background checks earlier — manual vetting doesn't scale past ~50 cleaners.
- Mobile app for cleaners sooner — the web app worked, but cleaners live on their phones. Push notifications for new requests would have improved acceptance rates.
- Postcode validation upfront — I added proper UK postcode validation (regex + API) later. Invalid postcodes caused support tickets early on.
HostMate is live at hostmateuk.com. If you're building a marketplace or location-based service, the postcode-first approach is worth considering. Start with the geography; everything else follows.