This project was designed to solve a small but expensive operational problem: irrelevant search terms leaking into Performance Max campaigns without a disciplined cleanup process.
Problem
Reviewing search terms manually across accounts and campaigns is repetitive, easy to postpone, and difficult to keep consistent. That usually means wasted spend stays in the system longer than it should.
Solution
I built a scheduled Google Apps Script with TypeScript modules that reads approved keywords from Google Sheets, compares them against recent search-term data from Google Ads, and pushes non-matching terms into a campaign-level negative keyword list. Every change is logged to a sheet for visibility and review.
Execution mode
Scheduled runs
Audit trail
Google Sheets log
Scope
Multi-account capable
Safety mode
Capped rollouts
Why it is effective
- The tool keeps non-technical stakeholders in the loop by using Sheets as both config and audit surface.
- Safe rollout limits reduce the risk of pushing too many exclusions in one run.
- TypeScript structure and tests keep the Apps Script environment maintainable instead of turning into a single-file script blob.
- Bundling through esbuild solved the normal runtime and trigger friction of Apps Script projects.
Note
What is still missing
The notes describe the workflow well, but not the typical volume of exclusions, spend saved, or account sizes. Those are the main commercial proof points still missing from this version.
Outcome
The optimizer turns an error-prone maintenance task into a controlled recurring workflow that helps keep Performance Max traffic cleaner and easier to govern.

