Residential Cleaning Company
Job Performance Analytics
Result: Built an automated data extraction and analytics pipeline — every job, every cleaner, every metric
January 2026
The Problem
The scheduling platform was great for booking jobs. Terrible for understanding them.
Every job had data — customer name, address, square footage, revenue, cleaners assigned, clock-in/clock-out times. But it was all trapped behind a web interface with no export button and no public API. If you wanted to know how a specific cleaner performed last month, you’d click through 30+ job modals one at a time and write the numbers down.
Nobody does that. So nobody had the answers.
The owner was making staffing decisions — who gets the high-value jobs, who needs retraining, which routes are efficient — without data. Just observation and gut feel. With 22 cleaners across the Raleigh metro, that’s a lot of gut.
What I Built
An automated extraction system that pulls every job, every day, without touching the platform’s UI.
The system uses a headless browser to log into the scheduling platform, navigate to each job, open the detail modal, and extract structured data:
- Job date, customer, home name, job type, job ID
- Cleaner assigned (normalized against a known employee list)
- Hours scheduled, square footage, revenue
- Clock-in and clock-out times
- Whether it’s a deep clean, team job, recurring service
For two-cleaner jobs, revenue and square footage get split 50/50 — each cleaner gets their own row. This matters when you’re comparing per-person productivity.
The extraction handles the mess real-world data creates:
- Square footage appears in at least five different formats across the platform (“1,200 sqft”, “1200 sq ft”, “only cleaning 800 sq”, a pipe-delimited field, or buried in free-text notes). The system tries all five patterns in priority order.
- Cleaner names have variations — the system normalizes “María” and “Maria” and “MARIA” to the same person.
- Some jobs have broken HTML in the notes field. The parser handles that too.
Job type classification is inferred, not just read:
- Solo: 1 cleaner, standard service
- Duo: 2 non-trainee cleaners
- Solo + Trainee: 1 experienced + 1 training
- Deep Clean variants (solo deep, duo deep)
- Recurring frequency (weekly, biweekly, monthly)
The platform doesn’t label most of this. The system figures it out from the data.
The QA Layer
Extracting data is one thing. Trusting it is another.
I built a verification system that screenshots every job modal and saves the raw text alongside the extracted data. Then an AI reviewer compares the screenshots against the Excel output — row by row — and flags any discrepancy.
Each job gets a verdict: CORRECT, BUG, or EDGE CASE. Every bug found gets traced back to the extraction code and fixed.
After hardening: 16 consecutive jobs, 21 data rows, all verified correct. The system has been running clean since.
The Result
The owner can now answer questions that were previously impossible:
- Which cleaners have the highest revenue per hour?
- Are deep cleans actually more profitable than regular service, or just more expensive?
- How does square footage correlate with actual cleaning time vs. scheduled time?
- Which job types have the widest gap between estimated and actual hours?
These aren’t vanity metrics. When you’re scheduling 22 people across dozens of homes every week, knowing who performs best on which type of job is the difference between optimized routes and wasted payroll.
The data runs daily. No manual intervention. The owner opens a dashboard, and the numbers are there — current as of yesterday.
Stack: Python · Selenium WebDriver · openpyxl · Claude API (verification) · Chrome automation
How it gets built
Understand the bottleneck, the data, and what success looks like.
Design the simplest solution that fully solves the problem.
Iterative development with working previews at each stage.
Handoff with documentation, training, and a 30-day support window.
Ready for results like these?
A 15-minute call is enough to scope your project and give you a real number.