System 1 of 4

Closed-loop Google Ads optimization engine

Turns phone calls into verified leads, attributes them to the campaign and keyword that produced them, uploads them to Google Ads as offline conversions, and runs an unattended nightly optimization cycle across 8 accounts.

In production, nightly, unattended

Role
Sole architect, engineer, and operator
Size
59,000 lines of Python, 115 CLI commands
Scope
$460K+ annual spend across 8 accounts
Stack
Python, Google Ads API and GAQL, Claude API, CallRail API, Microsoft Graph, SQLite, Click CLI, launchd
Outcome
Cost per qualified lead down 38% while monthly spend fell 33%

Problem

I inherited campaigns where only 5% of ad-driven phone calls were qualified leads. Google's bidding was optimizing on call volume, which meant it was optimizing on noise. The truth about each call lived in its transcript, not in the ad platform, so no off-the-shelf tool could close the loop. The engine was built to replace the bidding signal with verified outcomes and then to act on that signal every night without me.

Architecture

One nightly cycle, scheduled by launchd with missed-run recovery, in this order:

  1. Snapshot performanceCampaign and keyword metrics pulled across all 8 accounts via GAQL.
  2. Classify every new callTranscripts pulled from the call-tracking API and classified by the Claude API as qualified lead, applicant, existing client, or cannot service, with a cache to hold cost near $0.03 per call.
  3. Attribute leads to keywordsA custom attribution engine joins each call to the campaign and keyword that produced it. 124K attribution rows to date.
  4. Upload offline conversionsQualified leads are uploaded to Google Ads as call conversions, with an alert if the pipeline stalls. 4,449 uploaded. Along the way I found that click-conversion uploads do not attribute for call ads, a quiet API behavior that would have invalidated the whole loop.
  5. Grade campaigns and keywordsEvery campaign and keyword graded A through F against qualified-lead truth, not against Google's reported conversions.
  6. Mine waste patternsCannot-service transcripts are mined for recurring waste and converted into negative keywords, with location-aware compliance exceptions.
  7. Generate and execute the action queueBudget-aware, deduplicated, risk-tiered. Low-risk actions execute automatically. Medium and high wait for approval.
  8. Detect anomalies and failuresPer-campaign z-score deviation against 30-day baselines, zero-spend detection, bid-strategy phase checks, and self-monitoring that alerts when the engine itself is broken.
  9. ReportA prioritized email with a triaged subject line, from critical down to all clear with the count of optimizations applied.

Weekly, the engine also drafts new campaign proposals with ad groups, keywords, and budget sizing, and checks for experiment learnings that have not been applied.

Controls that let it spend real money

Evaluation

Numbers

Cost per qualified leaddown 38%
Monthly spend over the same perioddown 33%
Weekly cost per acquisition$107 against a $150 target
Estimated wasted spend eliminated$30–50K per year
Call transcripts AI-classified19,968
Offline conversions uploaded to Google4,449
Attribution rows124K
Controlled A/B experiments38
Codebase59,000 lines of Python
CLI surface115 commands
LLM cost per call~$0.03
All figures appear on my resume. Cost per lead is spend divided by AI-verified qualified leads across all 8 accounts.

Built on the same data