How we cut CDN costs from $5,000/month to $200 at Katha Ads
40-50TB of media per month, 125k DAU, and a two-part trick that dropped our CDN bill by 95%.
At Katha Ads, we run unizone.one - an advertising product that at peak season sees north of 125k daily active users. A big chunk of what we serve is media: images, videos, creatives. Lots of it, constantly.
CDN is not optional at that scale. Latency on media directly affects engagement, and engagement is the product. So we had Cloudflare, AWS CloudFront, the works.
The problem was the bill.
The numbers before
Standard retail CDN pricing across AWS, Akamai, and Cloudflare sits around $100 per TB of data transferred. We were moving 40-50 TB per month. You do the math: $4,000 to $5,000 a month, just for CDN.
We were paying $200-$300.
Here’s how.
Part 1 - Cloudflare free tier as the first layer
Cloudflare has a free CDN tier. The limitation is that it doesn’t give you the same performance guarantees as a paid CDN setup - you’re sharing infrastructure, cache-hit rates can vary, and for latency-sensitive requests it’s not always ideal.
But here’s the thing: not all media requests are equally latency-sensitive.
When a user is actively interacting with something - scrolling through a feed, viewing a creative, about to click - that media needs to load fast. A 200ms difference is noticeable. For everything else - background preloads, thumbnails further down the page, assets loading off-screen - a slightly slower CDN is completely fine.
So we built this distinction into the app. Two CDN origins:
storage.katha.today- AWS CloudFront, full performance, paidcdn.katha-ads.in- Cloudflare free tier, sitting in front of CloudFront
The routing in CloudFront was straightforward: anything hitting cdn.katha-ads.in/image.png gets passed through as-is to storage.katha.today/image.png, which then hits S3 if it’s a cache miss. Both layers cache the response, so once an asset is warm on Cloudflare, it never touches paid infrastructure again for that asset.
cdn.katha-ads.in/image.png
-> storage.katha.today/image.png [CloudFront cache]
-> S3 [only on cache miss]
The app-level logic decides which URL to use per request. High-priority, in-viewport, user-facing media goes straight to storage.katha.today. Everything else goes through cdn.katha-ads.in.
The result: the vast majority of our data transfer gets absorbed by Cloudflare’s free tier. Only the performance-critical requests - a fraction of total volume - ever touch AWS CDN.
Part 2 - AWS billing partners
Even for the traffic that did hit AWS, we weren’t paying retail.
Here’s something most people don’t know: AWS CDN at retail is $100/TB, but through an AWS billing partner you can get it for around $30/TB. That’s a 70% discount on the same infrastructure.
Why does this discount exist? And why doesn’t AWS just offer it directly?
It comes down to billing risk. AWS is a postpaid service - you use it, and you pay at the end of the month. The problem is that a non-trivial number of companies spin up infrastructure, run large workloads, and then disappear without paying. Startups fold. Teams abandon projects. Sometimes it’s intentional.
AWS mitigates this by offloading that risk to billing partners - essentially resellers who take on the collection risk themselves in exchange for volume commitments. The billing partner guarantees AWS will get paid, and in exchange AWS gives them a rate that makes the business viable.
What’s interesting is what this implies about AWS’s actual cost to serve CDN traffic. If they can profitably sell at $30/TB through a partner, the real infrastructure cost is likely somewhere around $20/TB. The other $80 at retail is margin - and a chunk of that retail margin is essentially a risk premium on the chance you don’t pay.
Finding the right billing partner took some research, but the conversation is usually straightforward once you know to ask for it.
What this looks like in practice
Running both together:
- Cloudflare absorbs the bulk of traffic - free
- The remaining performance-critical traffic hits AWS CDN at $30/TB instead of $100/TB
- 40-50TB becomes maybe 5-8TB of actual billable AWS traffic after Cloudflare’s cache does its job
- 5TB at $30 = $150. Add some overhead, monitoring, S3 costs, and you land in the $200-$300 range
The engineering cost was maybe a week - the URL routing logic in the app, the CloudFront passthrough config, and the partner paperwork. Against $4,500/month in savings, the payback period was measured in days.
The thing I keep thinking about with this one: neither trick was clever in isolation. Cloudflare’s free tier is well-known. Billing partner discounts are not a secret. The insight was just combining them deliberately, with app-level routing that made the free tier usable without compromising user experience.
Most infrastructure cost problems have a version of this - the cheap path exists, it just has a catch, and the catch is often solvable with a bit of logic.