27 days in: what we got wrong about CTV supply
Written by The Adbustr team
We turned on production traffic on October 16. Today is November 12. We promised ourselves we would write something honest about the first month, before the rationalizations set in. So here it is.
Fraud was not the biggest problem
We spent most of the summer building fraud detection. Pixalate integration, our own anomaly heuristics, IP reputation scoring, app-ads.txt enforcement. We expected to spend the first month chasing invalid traffic across our integrations.
What actually happened: 2.1% IVT rate across the first 27 days. That is below industry baseline for CTV. The fraud layer worked roughly as designed.
The real problem was inventory consistency. CTV bid requests are not standardized the way mobile is. One of our larger publishers sent us 47 different formats for the app.bundle field over 11 days. We had no idea this was even possible. Some used reverse-domain. Some used app-store IDs. Some used freeform strings. A few sent the publisher's internal SKU. Our matchers exploded.
We shipped a normalization layer in week three. It now resolves about 80% of the format weirdness automatically. The remaining 20% gets queued for a human to look at. We will probably be staring at queues like that for a while.
CPM range broke our floors
On mobile we knew what to expect. Interstitial: $2 to $8. Rewarded: a bit higher. Banner: a lot lower. Predictable.
On CTV the spread was not predictable. Filler inventory came in around $0.40. A pre-roll on a kids edutainment FAST channel cleared at $34. The same publisher's pre-roll on the same content type at a different time of day cleared at $11. We rebuilt our floor logic twice in three weeks. The current version adapts per inventory class instead of using a single curve, and it is much closer to right.
White-glove onboarding is real
We had this idea that 80% of publishers would self-onboard through the dashboard. We had a clean form, a sensible verification flow, automated app-ads.txt checks, and reasonable defaults.
Reality: every single publisher in the first batch had at least one thing wrong. Wrong app-ads.txt format. Missing GDPR consent flag. Geo-IP that did not match the declared country of operation. A misconfigured SDK that double-fired impression pixels. None of these were anyone's fault. They were just the thousand small things that come from building integrations across an open ecosystem.
So we are doing it the slow way. White-glove onboarding for the first hundred publishers. Someone on the team reviews every integration personally. We take a 30-minute call with each one before we route any traffic. It is not scalable. It is the right thing to do at this stage.
Three things we would do differently
- Ship the inventory normalization layer before going live next time. We thought we could iterate on it post-launch. We could not.
- Build floor logic that adapts per inventory class from day one. Single-curve floors do not work in CTV.
- Stop being optimistic about onboarding automation in year one. White-glove is the right answer until the data tells you otherwise.
We will write another one of these in 90 days. By then we should know whether the lessons stuck.
- operations
- ctv
- post-mortem