AdWash — Autonomous Google Ads Management
Built at Yelu Marketing · live SaaS · adwash.ai
Delivered — measured against the live production database, 2026-09-04
Codebase, counted 2026-09-08: 45,148 lines of TypeScript · 63 API routes · 27 pages · 21 Prisma models · 27 migrations.
The problem
When a heat wave crosses 95°F, emergency AC searches spike within hours. A campaign adjusted next Tuesday has already missed it.
A contractor spending $5–20K a month on Google Ads can hire an agency and receive a monthly PDF explaining last month, or run it themselves and lose their evenings. Neither reacts to what actually drives the demand.
How it runs
-
Write the campaign
01 / 06
A business profile becomes a complete Search campaign — ad groups, keywords, headlines, sitelinks, negatives — checked against Google’s own field limits.
-
Critique it
02 / 06
A generator, an adversarial critic, a deterministic strength gate and a grounding audit all run before anything reaches a real ad account.
-
Bid on the weather
03 / 06
Service areas are watched against live forecasts and classified per trade; budgets and bid modifiers move, then unwind when conditions normalise.
-
Hold spend to plan
04 / 06
Real spend is ingested from the Google Ads API, and campaigns pause at the plan’s ceiling.
-
Suggest, and wait
05 / 06
Rules over performance data raise suggestions with a concrete action attached; nothing is applied without an opt-in.
-
Attribute revenue
06 / 06
Two-way sync with Housecall Pro and ServiceTitan matches booked jobs back to the click that produced them.
The guards, and what each one prevents
HoverTap a card to read what it prevents.
- A failed read is not an empty result
A malformed query once reported “no campaigns exist”, and a caller archived 75 live campaigns on it. Success is now reported separately from results, and callers that write abort instead.
- The automation can undo itself
The weather engine keeps a ledger of its own writes and resets only values that still match what it put there. Anything a person has changed since is left alone.
- AI edits are typed operations
The model emits operations from a closed vocabulary, applied to a clone of the live plan. A deep comparison refuses the whole change if anything moved that no operation claimed.
- Success requires evidence of work
A mutation that returns “ok” while matching nothing live is reported as a failure, not “Done”. Nobody investigates a cheerful success.
- Writes are off by default
Without an explicit flag, every Google Ads mutation is validate-only, so a misconfigured environment cannot spend anyone’s money.
- Deploys assert their own outcome
The build ID is present, the restart counter advanced, the homepage returns 200 and an authenticated endpoint 401 — or the deploy exits non-zero.
Limits, stated plainly
- AdWash is Yelu Marketing’s product, built in my employed role as its only engineer. The engineering is mine; the product is not.
- The headline numbers on adwash.ai — ROAS, time-to-live, the named testimonials — are promotional copy, not telemetry. None of them is on this page.
- Weather bidding is a forecast-driven heuristic, not a demand model. It does not predict revenue.
- Revenue attribution needs the CRM connected and the click ID to survive the journey. A call to a number that was never tracked cannot be matched.
Built with
- Next.js
- TypeScript
- PostgreSQL
- Prisma
- Google Ads
- Stripe