Michel CunillMC

Michel Cunill

Growth · Paid Acquisition & Internal Tooling

Caracas, Venezuela · remote, US EST hours
michelcunill1@gmail.com · +58 424 152 0466

I'm a paid search marketer who writes software because the job stopped being doable without it. Running around 100 client accounts, the bottleneck wasn't strategy. Nobody can look at 100 accounts every morning. So I built the things that look for me: a reporting platform that syncs the whole book every 20 minutes, and an automation suite that catches broken ad destinations before a client does. Different stacks, one documented interface between them. Other managers work out of both.

The build

Two systems other people use

Both in production, both solving a problem I had personally before anyone asked for a solution, and both now used by managers other than me. That last part changed how I build: once a colleague's morning depends on it, "works on my machine" stops being a finish line.

Designed and built, 2025

Multi-account reporting platform

The problem

Performance data for hundreds of client accounts lives behind one manager account, and the native interface makes you look at accounts one at a time. Answering "which accounts are pacing badly this week" meant opening them one by one.

It syncs every account under the agency's manager accounts into a database every 20 minutes and keeps around 400 days of per-campaign-per-day history, then serves it through a web app: cross-account comparison, spend pacing at a glance, asset search across the whole book, and a map view of campaign location targeting. The team uses it daily and some of our reporting workflows depend on it now.

DecisionWhy
Read-only It holds credentials for every client account in the book. Write access would mean a bug could change live ad data, so no write path is exposed at all. The blast radius of anything going wrong is a bad chart.
Resumable sync The scheduled job runs in phases and keeps its progress in the database, so a timeout or a failure mid-sync picks up where it stopped instead of starting the whole book again.
History, not snapshots Storing every campaign-day rather than the current state is what makes "is this worse than last month" answerable at all. The API won't tell you later.
2FA and domain-locked sign-up It aggregates real client spend across an entire agency book. Sign-up is restricted to the company domain and needs admin approval, and accounts carry a second factor.

Stack
TypeScript on serverless functions / Postgres / React and Vite / Leaflet for the map / JWT and TOTP auth
Started as a Python and SQLite prototype. I rewrote it onto this stack once it was clear the team was going to depend on it.

Built 2026, still in development

Paid search automation suite

The problem

Ads point at client websites that change without telling you. A page gets renamed during a redesign and the ad keeps running, keeps charging, and lands people on a 404. Across 100 accounts, nobody has the hours to check every destination URL by hand. Same story for the other recurring chores: drafting a campaign for a new client, or finding the search terms naming towns a client can't serve.

Five services behind one dashboard. A checker that sweeps live ads and probes every destination URL and sitelink. An extractor that reads a client site for products, images, and landing pages. A generator that drafts campaign structures from what it found. A geo tool that works in both directions, finding searches naming places outside the service area and existing negative keywords that are blocking traffic inside it. And an orchestrator with a job queue, an audit log, and an approval gate, fronted by a dashboard other managers work out of.

DecisionWhy
Two strikes A URL is only flagged after it fails twice in a row. Sites blip. An alerting system that cries wolf gets ignored within a week, and then it's worse than nothing.
Proposes, doesn't act It computes a suggested fix and hands it to a person rather than editing the account. Automated repair of something it misdiagnosed is a worse outcome than the original broken link. Every write path is dry-run by default.
Split trust zones The host that scrapes client websites never holds Google Ads credentials. The host that could write to Ads never fetches client sites. Compromising one doesn't hand over the other.
Swap, never edit in place A sitelink shared across many ads gets a new asset and a swap. Editing the shared one would silently change every other ad using it.
Probes aren't clicks Checks are plain HTTP fetches with per-host pacing and a tagged user agent, never the ad's own click URL. Monitoring a client's ads should never spend their budget or look like fraud.

Stack
Python / FastAPI / Postgres / htmx dashboard behind company SSO / queue workers, one per trust zone
276 tests, all running offline with no network and no credentials.

How they fit together

One interface between them

The automation suite reads its performance data from the reporting platform rather than querying the ads API again. That connection is a documented read-only contract, written so it could be lifted into a different codebase without reading any of the code that consumes it. Two systems, two languages, one interface, and neither one reaches into the other's internals.

Both built LLM-assisted. That's the honest version of "AI-native": it changed what I could ship on my own, not just how fast I write.

I've described these by what they do rather than naming the repos, since they run against live client accounts. Happy to walk through the code and the architecture in an interview.

Measurement

The tracking layer underneath

Tooling that reports on conversion data is only worth as much as the conversion data. I own tracking implementation across client sites, which is where I learned not to trust a number just because a dashboard rendered it.

  • Google Tag Manager: container setup, triggers, QA before publish
  • GA4: event configuration, conversion validation, debugging discrepancies between GA4 and Ads
  • UTM structure and conversion event design across a book of accounts
  • Meta Pixel and the Conversion API, including server-side, set up on my own projects rather than through an employer
  • Enough HTML and JavaScript to open a page and work out why a tag isn't firing

The recurring lesson: Smart Bidding optimizes toward whatever you tell it a conversion is. A tag firing on the wrong event doesn't produce an obviously broken report. It produces a confident one that's wrong, and the algorithm spends real money against it.

Domain

Why the tools are the right tools

I didn't build these from a spec someone handed me. I built them because I was the one doing the work badly by hand.

My book

~100client accounts
~$39Kmonthly ad spend

The full agency book the platform covers

450accounts
2,261campaigns
19,017assets tracked
$2.61Mspend, Apr 2025 – Jul 2026

Day to day that was Google Ads across Search, Display, and Performance Max for fintech, SaaS, and events clients: pacing, bidding strategy, keyword and audience work, ad copy testing, and the client meetings where you explain what changed and why. My buying experience is Google-side; I haven't run campaigns in Meta Ads Manager.

The book-wide figures are the whole agency, not my personal results. They're here because they describe the surface area the platform covers. My own book was about 100 accounts and $465K in spend over the engagement.

Outcome

What happened to the accounts I took over

The book turned over constantly. I picked up new accounts most months and handed others off, so comparing my numbers in June against my numbers a year later measures churn rather than work. New accounts arrive expensive and reset the average.

So I measured it a different way. I pulled the assignment history out of the CRM, joined it to per-day campaign metrics, and indexed every account against the agency's own cost per conversion for that same calendar month. Then I grouped by how long I'd held the account. That controls for the churn and for the seasonal swing at once. An index of 100 is the agency average, and lower is better.

Months heldAccountsMy CPA Agency, same monthIndex
0, at takeover227$14.93$13.32112
1192$13.95$12.81109
2163$12.99$12.58103
3132$12.38$12.13102
489$10.65$12.8583
560$10.53$13.2979
648$13.96$16.0687
741$18.58$17.14108
838$16.23$17.1695

Accounts came to me running about 12% worse than the agency average and were running 17 to 21% better by month four or five. That's across 227 accounts at takeover.

The honest limit: past month six the sample thins and the gap closes again. Months seven and eight sit on 38 to 41 accounts and month seven is back above the benchmark. The part I'd defend is the first six months.

Before this

Background

Digital Marketing Specialist · Event Hawk, Chicago (remote) Jun 2025 – Aug 2026

Everything above.

Product Marketing Specialist · Ugami, Inc., Miami (remote) Mar 2021 – Mar 2023

Consumer fintech app. Ran App Store and Google Play presence: listings, creatives, and metadata optimized for install conversion. Ran A/B tests and fed results into UX and copy. Built go-to-market and acquisition strategy including in-app brand and character development.

Medical Interpreter, EN/ES · Propio Language Services Aug 2024 – Jun 2025

88%+ quality accuracy inside the first month, among the highest in my cohort, and no complaints across the engagement. Live interpreting under time pressure, which is why I don't hedge about working in English.

Sales Executive · Jungleworks, Caracas Jun 2024 – Aug 2024

Outbound lead generation for a SaaS platform: prospecting, demos, negotiation, closing.

Psychology · Universidad Central de Venezuela Oct 2016 – Jun 2024

Completed 9 of 10 semesters before going full-time into marketing.

Also

Tools and languages

  • Paid media: Google Ads Search (standard and dynamic), Display, and Performance Max
  • Analytics and tracking: GA4, Google Tag Manager, conversion tracking setup and QA
  • Backend: Python, FastAPI, TypeScript, Postgres, SQLite, the Google Ads API, pytest. Comfortable with queues, scheduled jobs, and auth.
  • Frontend: React, Vite, htmx, Tailwind, Leaflet. Enough to build a working interface, not enough to call myself a designer.
  • CRM: HubSpot, GoHighLevel
  • AI: Claude and other LLMs daily for research, copy variations, and building the tools above. Both platforms exist because LLM assistance changed what one marketer could ship on their own.
  • Languages: English (professional, native-level conversational) · Spanish (native)