AI-translated. Read the original in KoreanEmbedded slides, videos and images remain in their original language.
Improving Ad Budget Pacing, Part 2: Finer Control and Business Results
Software Engineer
Software Engineer

Hello, we're Bale and Liam from the Ad Engine team. In Part 1, we described our budget pacing architecture improvements and the observability we gained. This time, we will show how that work enabled better functionality and business impact. Since this builds on the earlier changes, we recommend reading Part 1 first.
Toward more precise budget pacing
Controlling planned budgets more precisely is a common challenge across advertising systems. The answer may sound obvious: evaluate pacing more frequently and adjust it more finely. We achieved that through three main improvements.
1. Evaluate more frequently
Frequent evaluation matters for both reaching budget targets and optimizing performance. If pacing runs every ten minutes, a spending spike between evaluations may cause overspend. As control errors accumulate, a campaign may fail to meet its budget target or lose the spending pattern designed to optimize performance.
Yet Buzzvil's early pacing system worked reasonably well despite a fairly long cycle. How? The spending plan could correct accumulated errors. For example, if a campaign intended to spend KRW 100,000 per hour spends KRW 120,000 for five hours, the system can pause spending for the next hour and return to plan, eventually approaching the total budget target. Shorter evaluation cycles allow more frequent corrections and closer adherence to the plan.
Buzzvil evaluates every active campaign each cycle, so frequency depends on evaluation performance and delays such as spend aggregation. The microservice extraction and aggregation improvements described in Part 1 provided performance gains and lower latency. Today, every campaign is evaluated once every 15 seconds, following its spending plan much more reliably than before.
2. Plan spending at finer intervals
Suppose evaluation is frequent enough, but the plan simply says to spend KRW 100,000 per hour. What could go wrong? The campaign might spend all of it in ten minutes and serve no ads for the next 50. A lack of continuous exposure can be a problem in itself, and early spending may leave no budget for later periods with better opportunities.
Buzzvil initially planned spend hourly; now we plan it by the minute. Narrowing the planning interval is not difficult on its own, but the planning and evaluation intervals must be coordinated for it to be useful. This improvement was therefore also enabled by the system's ability to evaluate more frequently.
3. Control delivery volume more finely
Our original pacing logic enabled ad delivery when evaluation called for more spending and disabled it otherwise. That works, but what happens when ad traffic grows tenfold or a hundredfold? Enabling delivery at 100 times the traffic can generate enormous spending almost instantly. Even shorter control and planning intervals may then fail to deliver the intended behavior. Buzzvil's traffic had grown substantially as partner inventory expanded, and simple on/off control could no longer pace spending smoothly.
We found a useful example in a paper published by LinkedIn. At the control level, it uses a delivery rate instead of switching delivery on or off. Gradually adjusting that rate smooths spending and accommodates traffic growth up to a point. The proposed method contains many more details; we recommend reading the paper if you are interested.
We adapted the approach to Buzzvil's circumstances. More frequent evaluation, finer spending plans, and finer delivery control together produced the positive change shown above.
Moving faster
As these system improvements were completed, new business requirements arrived around ad performance and campaign operations. Their details varied by ad product and campaign objective.
Until then, we had focused on stronger control and were not fully confident in our understanding of the detailed internals, so we examined the logic. It abstracted pacing across all campaigns, but requirements added during the transition had introduced branches throughout the code by product and objective. This made behavior hard to follow and side effects difficult to predict.
Given our still-developing understanding of the problem domain, the team considered this premature abstraction. We chose to refactor toward a structure that was easier to change. From current requirements and existing implementations, we identified several patterns as “pacing strategies” and lowered the abstraction level so that each strategy implemented its own control logic.
We then added requirements such as early closure to end spending safely for each strategy, and average daily budget guarantees to reduce operational effort. These changes affected many campaigns at once, demanding stronger validation than before.
We had already felt that our validation process needed improvement. Ordinary APIs often respond immediately, may not change state, and frequently require little validation over time, making unit and integration tests in CI sufficient. Pacing, however, has the feedback loop described in Part 1. Testing individual pieces did not give us confidence in the final behavior.

To shorten validation and let implementers and reviewers inspect the same results with shared confidence, we built a campaign simulator. Implemented as a simple command, it generates ad request traffic, produces delivery and impression events according to the pacing system's decisions, and visualizes the result in Grafana panels for review.
We began using the simulator during implementation and review. Work that previously took around a week to develop and validate could now reach production in an average of one or two days. As an implementer, I also spent less time anxiously monitoring the system. From November, when the simulator was introduced, our greater confidence translated into a visible increase in deployment frequency.

Production validation still required care. But replacing analytics-log panels with several minutes of delay with the real-time panels built during our observability work let us see current conditions and respond immediately. We could proceed more confidently. We also saw value for campaign operators, so the same capability was added to internal campaign operations tools, where it is proving useful.
These changes helped us respond to growing business requirements and dramatically shorten validation. In the process, we deepened our understanding of each product and the pacing system. Next, I will share how that experience and understanding led to measurable results.
Improvements that compound
As introduced in Surviving the Live Commerce Battle, live commerce advertising needs to reach many users early in a campaign. Because the goal is to attract viewers during the broadcast, we generate many impressions in a short period. Some are delayed by users' environments. Traffic arriving after a broadcast ends has no value for the advertiser, while the ad system still incurs unnecessary inventory costs, hurting profitability.

Our first hypothesis was that better pacing would naturally improve part of this problem. Throughout the earlier work, we periodically checked whether the proportion of post-campaign spend was falling, but saw no meaningful improvement. Still, excessive impressions after a broadcast were a clear problem, and solving it could improve both the product and profitability. With confidence gained from the system work, I proposed tackling it, and the team agreed.
We began by examining the data. On average, about 10–15% of all impressions occurred after the campaign ended. Delays from ad delivery to recorded impression could reach two hours, but around 75% of impressions were recorded within 15 minutes of delivery. Since most live commerce campaigns run for only one or two hours, those delays had a substantial effect after the end.
We hypothesized that allocating the budget with an exponentially decreasing spending rate rather than a linear one would let delayed impressions be better accounted for toward the end, reducing impressions after the broadcast finished.

Validating and applying this hypothesis was straightforward because our earlier improvements paid compound returns. The spending types introduced to support different patterns made it easy to add a new one. We extended the simulator to model delayed impressions, allowing us to verify behavior and improvement before deployment. Implementation, validation, and production rollout took just two days.
Ultimately, we reduced publisher spend after broadcast completion by around 60% and improved the product's overall profitability by about 3.5%. Bringing in more viewers early and closing smoothly toward the end also improved advertiser satisfaction. The results were gratifying, but experiencing the accumulated benefits of incremental improvement made the process even more rewarding.
Closing thoughts
Thank you for following the Ad Engine team's budget pacing journey. We covered a lot. First, we defined the system's key inputs, outputs, and metrics, then set a target state. Rather than changing everything at once, we improved incrementally. Along the way, observability gave us confidence and accelerated hypothesis validation.
This is not the end. We have implemented only part of the team's plans. We intend, for example, to build inventory forecasting models to improve budget allocation strategies and experiment with different algorithms or models for determining pacing state. We will also tackle many other problems to improve advertising performance. We hope you will join us for future posts.
None of this would have been possible without feedback and support from many teams. Special thanks to Ad Management and CM for working with us on pacing logic, and to Datavil and DevOps for their platform support.