An autonomous Meta Ads agent. No human in the loop.
At a glance
- →Three-phase state machine: discovery (find the bid that unlocks delivery), scaling (grow budget on strong ROAS), corrective (pull back when ROAS drops)
- →Emergency check every cycle: pauses on spend-without-sales runaway or ROAS collapse below floor
- →Fatigue monitor clones ad sets when frequency spikes or CTR drops vs. 7-day baseline
- →Real Net ROAS calculation pulls from Whop revenue API (filters out upsells per client config)
- →Six n8n workflows handle Discord alerts, daily/weekly digests, Meta token rotation, and health heartbeats
- →All decisions logged to Postgres with full audit trail (state, decisions, alerts, snapshots, errors)
A direct-response advertiser was running Meta Bid Cap campaigns at six-figure-monthly spend. Bid Cap requires hands-on operator attention — you set the bid, watch what Meta does with it, and adjust. If the bid is too low, the auction never unlocks and the ad set sits with zero delivery. If the bid is too high, you overpay. If ROAS drifts down, you have to react fast or burn budget. The advertiser wanted to scale without scaling the operator’s hours, and Meta’s built-in auto-bidder didn’t give them the discipline they wanted around a Real Net ROAS target (which had to factor real paid revenue and exclude certain product upsells).
We built an autonomous ad ops agent — a Python engine that runs every 30 minutes via cron, reads Meta ad performance and Whop sales from a Supabase warehouse, and runs each ad set through a three-phase state machine. Discovery raises the bid by $1 every 6 hours until the auction unlocks. Scaling grows the daily budget by 20% every 4 hours while Real Net ROAS holds above target. Corrective runs an escalating pullback ladder when ROAS drops — lower bid, then reduce budget, then pause — each step gated by three consecutive bad cycles. An emergency check runs every cycle and pauses immediately on spend-without-sales runaway or ROAS collapse. A fatigue monitor clones ad sets when frequency spikes or CTR craters. Six n8n workflows handle alerts to Discord, daily and weekly digests to Gmail, Meta token rotation, and a 15-minute health heartbeat.
The agent has logged over 300 autonomous decisions and 190 alerts in production — every bid change, every budget step, every pause, with a full audit trail in Postgres. The advertiser stopped hand-tuning ad sets and started running the configuration: tune the target ROAS, the emergency floor, the bid ceiling, the cycle cadence — the agent runs the playbook between cycles.
Respecting Meta’s API rate limits without missing decisions
A dedicated rate limiter enforces Meta’s hard cap (4 mutations per hour per ad set, 9,000 points per 300 seconds for the account). Daily counters reset at midnight UTC via a separate cron. The engine refuses to mutate when it’d push past the cap and queues the decision for the next eligible cycle, with a Discord alert if a mutation gets deferred.
Real Net ROAS, not Meta’s reported ROAS
Whop’s payment API is polled every 15 minutes into a Supabase table. The agent calculates ROAS using actual paid revenue per ad set, filtered to specific Whop products (configurable inclusion/exclusion) — so upsells or refunds flow through cleanly instead of inflating the Meta-reported number.
Decisions had to be safe to ship
A development mode reads every metric and logs every decision but never touches Meta. The agent only mutates ads when explicitly set to production. A file lock prevents overlapping cron runs. Config validation refuses to start the engine if any required parameter is missing. An "insights guard" skips ad sets when Meta’s API returns empty data instead of deciding on bad info. Every mutation is logged before it’s executed so post-hoc review is always possible.
From spreadsheets and email threads to one operations platform.
From MP4 upload to processed catalog, no human in the loop.
An autonomous trading agent. No human in the loop.
Ready to build?
15 minutes. No pitch deck. Just a conversation about what you’re trying to solve.
Book an intro