Sovren · Live ads · Shipped 2025
How I shipped ads into live in 45 days by cutting half the build.
Leadership wanted live as a flagship bet and gave it 90 days. The research said nobody wanted to originate a stream with us, so I cut origination, received streams instead, and spent the time on ad insertion against the ad server we already owned. Then I raised the floors on purpose.
90 days to build origination: ingest, encode, a player, chat and a creator capture tool.
Leadership wanted live as a flagship bet, and they were right to want it. The plan was 90 days. Ingest, encode, a player, chat, and a full creator capture tool, built against platforms with a decade of head start.
So I went and looked at who would use it. We did not have an audience that wanted to originate a livestream on our platform. Nobody was waiting for us to build them a broadcasting tool.
What we had were two groups nobody had counted. Creators already going live elsewhere, happy to also broadcast with us. And network partners willing to share channel feeds they were already producing.
Receive instead of originate. Half the build gone, ads live in 45 days.
The plan assumed we had to originate. All we had to do was receive. That killed half the build. Ingest over RTMP and HLS, a player that could take those streams, and everything we saved went into server-side insertion against the ad server we already owned.
45 days means partner channels were live with ads in them. It doesn't mean the system was finished, and it doesn't mean I built it.
Two supplies: a pre-roll per viewer at the door, and one pod per break inside a partner's schedule.
A viewer taps a creator's stream and a pre-roll plays before it attaches. One serve call per viewer, with the creator's profile carried as the targeting. Network feeds come the other way, an HLS pull from a broadcaster's origin, and we sell breaks inside a schedule somebody else sets.
Both paths clear through our own ad server against our own supply, and every bidder was an advertiser we had sold to ourselves. Hand-set prices clear at face value. Machine-managed bids clear second price. An internal auction over inventory we own.
Pre-roll at the door has a real cost. A viewer who stays three hours sees one ad. I took that trade because cutting into a creator's stream on a platform they were simulcasting to was the fastest way to lose the supply we had just convinced them to give us.
Breaks arrive as SCTE-35 cues, in three dialects across our partners (CUE-OUT, DATERANGE and OATCLS), and the stitcher splices the pod into the HLS manifest. A cue gives you single-digit seconds, and a live splice has to budget for the decision's worst case. So the pod is decided ahead of the break, and the cue only fires a splice we have already priced. I specified that sequence before anyone wrote the stitcher.
The whole break, beat by beat.
No floor on day one. Then floors by tier: fill down to 77, revenue per avail up to 160.
No floor on day one, on purpose. Nothing was proven, the book was thin, and a floor on a thin book is mostly a reason for a break to go empty. We wanted fill, and evidence the model worked at all.
Then we instrumented the funnel. Realized eCPM per slot, pod position, fill source, clearing price, all queryable. It showed the floors we had since introduced were non-binding. Nothing was clearing near them. A floor nothing touches protects no revenue and costs none.
So I raised floors by tier. Fill went down. Revenue per avail went up. Indexed to the week before the raise, fill settled at 77 and revenue per avail at 160. Steady state settled into a 60 to 80 percent band with the floors holding. I held them where that band held. Above 90 percent I read the floors as set too low.
One definition, because it's the one people skip. That fill number counts house spots, the partner's own promos running at zero against unsold network breaks. Filled and monetized are different numbers.
Then I had to explain a fill number that came down on purpose. It got reported with revenue per avail beside it and the band named as the target. Walking leadership from fill to revenue per avail is what keeps the authority to make that call again.
The creator as the sellable unit, with the condition for switching to the viewer written down.
Everyone's instinct in ad tech is finer targeting. We widened. In a second-price auction the runner-up sets your revenue, so restricting which campaigns are eligible for a break narrows the field, and on a thin book a narrow field drags the clearing price toward the reserve. Ten bidders in an open break can clear higher than two in a perfectly targeted one.
We could describe the viewer in the request and let campaigns decide whether to care. We stopped short of making segment membership a condition of eligibility, because at our demand depth the marginal bidder was worth more than the marginal signal. So the sellable thing became the creator. Category, brand-safety tier, audience band, computed per stream.
The counterargument is real. Bidder count and bidder value aren't independent, an open field summons cheaper bidders, and some budgets won't transact without audience signal at all. At our demand depth, widening won. At a deeper book it would not, so it shipped with an exit condition: eligible-demand depth per stream. When the pools reach the hundreds, viewer targeting ships.
The partner terms and the sales slot, both settled before any integration code.
Filling a broadcaster's breaks replaces their own ad sales, so the deal came before the deploy. Revenue share on filled breaks, their house spots as our fallback fill, and measurement they trusted, meaning our impression beacons against their reconciliation. That conversation started the same week the engineering did.
Sales got the reserved first slot as a sponsorship product on select streams, a real thing to sell that didn't require bypassing the auction. What I kept was the price. They could sell the slot, and they had to clear the floor I set.
Our director of business development pushed to fill below the floor. He was measured on the number of advertisers on the platform, and a cheap yes is the fastest way to move that number. I said no and held it. Every advertiser after him would have priced against whatever we let him pay, and the floor I had spent a quarter finding would have been worth nothing.
The wrong fallback shipped first: a cut back to programming that read as a bug.
Live broke two ways. Cues misfired, arriving at the wrong moment or for a duration the pod couldn't fill. And decisions sometimes came back with nothing. An open window and nothing to put in it.
Our first fallback was cutting straight back to programming. It was wrong. The abrupt return read as a malfunction, so viewers experienced a bug where we had built a recovery. Slate replaced it, holding the window with something that looks deliberate.
Slate seconds became the guardrail metric after that. It's the failure a viewer feels, and we instrumented it after shipping the worse version.
The scope cut, the targeting model, the floors, the terms, the guardrail. The pipeline was his.
I co-owned this with a senior engineering lead. He owned how the pipeline got built.
Mine
- The scope cut and the research behind it.
- The targeting model.
- The floors, and when to move them.
- What sales could sell and at what price.
- The terms we offered broadcasters.
- The definition of the guardrail metric.
Not mine
- The manifest stitcher.
- The rendition ladder.
- The delivery work.
Scale, demand I didn't own, and a metric I never chose.
The system has served over 10 million ad impressions. That is a lifetime count. Peak concurrency was tens of thousands, and millions concurrent is a different problem.
The 45 days was standing up the live product and integrating an ad server that already existed. Building that ad server was separate work, done long before this.
Every advertiser in these auctions was ours, sold by our own team through our own interface, so nothing here proves I've run demand I didn't own. And it was co-owned with an engineering lead who deserves half the credit for everything above.
I made the cut without deciding which number would settle it. That part is in How I build now.
Every decision was keyed to the stream. At 30 million concurrent it has to move inside it.
I keyed every decision to the stream, because each stream carried one audience. At one stream and tens of millions of audiences, that keying has to move inside it. The pipeline has to personalize on the opposite axis.
Four questions I'd take into week one:
- Demand depth. At what depth does per-viewer eligibility beat a wider field? That's the exit condition I wrote down and never got to trip.
- Pod decisions. Is the pod decided once for the stream or once per viewer, and what does that cost the splice budget?
- Frequency capping. Where does it get enforced when one break becomes millions of distinct pods?
- The guardrail. What's the metric here, and who has the authority to hold a launch on it?