Creative Research
Work

The 140-Budget Problem

How we turned hand-edited Meta budgets across 15 ad accounts into two schedules, one spreadsheet and a log that explains every decision it makes.

Case study · October 2026 · Live · 6 min read

A charcoal 24-hour dial on ecru paper

Several times a day, someone at a performance marketing agency we work with opened Ads Manager and started editing budgets. The job covered 15 ad accounts, about 140 budgets and roughly ₹10 lakh of spend a day, and three or four interns shared it between them.

The agency knew exactly what it wanted. Trim spend that isn't earning, back the days that are, and never fall below Meta's minimum. The rules were clear. Following them by hand, across 140 budgets, several times a day, is where it broke.

Where manual edits break

Nobody was doing the job badly. The job itself was shaped wrong for people.

  • Edits collided. Two people would touch the same ad set within minutes of each other, and the second change quietly undid the first.
  • Limits slipped. With no single view of every budget, some drifted past the limits the agency had set.
  • It grew with headcount. Each new account added more editing passes, which meant more hours from more people.

None of this is a training problem. Any process that asks humans to apply the same arithmetic to 140 numbers, five times a day, will produce exactly these errors.

What the platform rewards

Before writing anything, we looked at how Meta actually spends a budget, because the design has to work with the delivery system instead of fighting it. Three things shaped everything that followed.

A daily budget is an average, and Meta treats it like one. Meta can spend up to 75% more than an ad set's daily budget on a single day when it sees good opportunities, as long as the week stays within seven times the daily figure.1 A weak ad set left alone in the morning can keep spending well into the evening, so corrections have to happen while the day is still running.

Big edits cost you. A budget change can send an ad set back into Meta's learning phase "depending on the magnitude," and Meta has never said where that line sits.2 The learning phase looks for around 50 optimization events in seven days,3 so resetting it on a busy ad set throws away real progress. Many small steps are safer than a few large ones.

Timing carries signal. The agency's own experience was that delivery improves when weak spend is trimmed through the day and strong days are rewarded once they're complete. That gave us the shape of the system before we wrote a line of it.

Two rhythms

The optimizer runs on two schedules that do opposite things.

00:0006:0012:0018:0024:00 07:0112:0117:0121:0123:3100:01 Day cut Night raise IST
Five day cuts and one night raise, every day, for every budget.

Day cuts run five times a day. Every budget whose return on ad spend (ROAS) is below the agency's cut bar is trimmed by a small step. An ad set that has spent a minimum amount with zero purchases counts as zero ROAS and gets trimmed too. There's no limit on how many cuts a budget can take in a day, only a floor at Meta's minimum that it can never go under.

The night raise runs once, just before midnight. Any budget whose day cleared that account's raise bar, with enough spend and at least one purchase behind it, gets a larger step up. Each account has its own raise bar.

The interesting part is where the two overlap. The raise bar sits below the cut bar, so an ad set that's decent but not great gets trimmed during the day and rewarded at night. That's deliberate. Steady performers grow slowly, weak ones shrink, and strong ones only ever go up.

Raise barCut bar Cut by day Cut by day, raised at night Raised at night Lower ROASHigher ROAS
The middle band is the point: decent ad sets are trimmed by day and rewarded at night, so they grow slowly.

Budgets live in different places depending on how a campaign is set up. Some sit on the ad set, and some sit on the campaign when Meta's campaign-level budget is switched on. The optimizer reads which one holds the money and acts on that.

The spreadsheet is the interface

The agency's team already lived in Google Sheets, so we didn't build them a dashboard. Every rule lives in a sheet with two tabs, one for cuts and one for the night raise, and any row can be set at three levels.

LevelRaise bar set toWhat the budget uses
Defaultaa
Accountblanka, inherited
Ad set or campaignbb
The most specific level wins and a blank cell inherits. Values here are placeholders.

That gives the team one place to change the whole system, one account, or a single stubborn ad set, without asking us. Edits take effect on the next run.

Every decision explains itself

Software that moves money needs to show its work. Every run writes to a decision log with one tab per account and one tab for all of them. Each row records what the optimizer did to a budget and why: cut, raised, held with a reason, or failed with an error.

When someone asks why a budget dropped at noon on Tuesday, the answer is a row in a sheet rather than a guess.

Built so a bad day can't get worse

An optimizer that edits ₹10 lakh of daily spend has to fail safely before it does anything clever. We started from the failure modes and worked backwards.

If this happensThe system does this
A value in the settings sheet is invalidNothing runs at all
One account fails mid-runIt's logged, the run is marked failed, and an email alert goes out
A run crashes partwayNo retries, so no budget can ever be cut twice
We change the codeA self-test, including a full fake run of cuts, raises and campaign budgets, has to pass before deploy
Something reads the sheetsA robot account that can only read settings and only write to the log

The no-retry rule looks wrong at first, because retrying is normally the safe choice. Here it's the dangerous one, because a retry after a partial run would cut budgets that were already cut. A failed run plus an alert is easy to recover from. A double cut on a hundred ad sets isn't.

Running it for almost nothing

Two schedulescuts and raise Cloud Run jobone run per trigger Meta Marketing APIedits budgets Settings sheet Decision log Email alert read onlywriteon failure
The whole system on Google Cloud. The Meta token sits in Secret Manager, and state lives in private storage.

Two schedules trigger a Cloud Run job, which spins up, does its work and disappears. Nothing runs between triggers, so the system costs close to ₹0 a month.

What we learned

  • The rules were the agency's. Our job was making them safe to run around the clock.
  • Work with the platform's grain. Small, frequent steps fit how Meta learns. Large, rare ones fight it.
  • The best interface was already open on their screens. A spreadsheet the team trusts beats a dashboard they'd have to learn.
  • Explain every move. A reason on every row makes the optimizer's work easy to check.

What's next

It still runs on a personal access token that expires every 60 days, so changes show up under one person's name in Ads Manager. Moving it to a system user owned by the agency is next. Adding a new account still takes a two-minute rebuild, and we want that to be zero.

The bigger question is memory. The optimizer judges each day on its own, which is right for small steps and wrong for big ones. We're working through that in Judging ads on days, not hours.

Sources

  1. Jon Loomer, Increased budget flexibility, on Meta spending up to 75% over a daily budget within a weekly cap.
  2. Jon Loomer, Facebook ads edits and the learning phase, on budget changes and Meta's unstated threshold.
  3. Ignite Social Media, Exiting the Facebook learning phase, on the 50 events in 7 days guideline.