The Silent Revenue Channel
Most mobile game developers treat in-app purchases as their primary monetization channel and ads as a secondary afterthought. CCFish flips this script: rewarded video ads account for 35% of total revenue, and the ad mediation stack runs on Cloudflare Workers for real-time waterfall optimization without third-party SDK bloat.
The core insight is simple: a player who will never buy a $4.99 gem pack will happily watch a 30-second video for an extra life or a double-reward multiplier. The challenge is building an ad mediation pipeline that maximizes eCPM across multiple networks while keeping latency under 100ms so the player never waits.
The Problem with Traditional Ad Mediation
Standard mobile game ad mediation uses SDK-side waterfalls: AdMob, Unity Ads, AppLovin, and others are called sequentially on the device. This approach has three fatal flaws:
- **Latency bloat:** Each SDK loads its own binary, inflating the app binary by 15-30MB. Players on older devices experience frame drops during ad loading.
- **Stale waterfall configs:** eCPM rates change hourly. An SDK-side waterfall configured today is suboptimal within six hours. CCFish needs sub-minute waterfall adjustments.
- **No server-side control:** Every waterfall update requires an app store resubmission. A/B testing ad placements means shipping new builds.
CCFish's solution: move the ad mediation logic to Cloudflare Workers, keeping only a lightweight ad request adapter in the Cocos Creator game client.
The Serverless Ad Mediation Architecture
CCFish's ad stack uses a Cloudflare Workers endpoint as the sole ad request gateway:
```
Player -> CCFish Client -> Cloudflare Worker (mediator) -> Ad Networks
<- Ad response <- Ad Network A (AdMob) |
<- Ad response <- Ad Network B (Unity Ads) |
<- Ad response <- Ad Network C (AppLovin) |
<- Best eCPM offer returned to player
```
The worker maintains an in-memory eCPM cache updated every 60 seconds via a cron trigger that polls each network's reporting API. When a player requests a rewarded ad, the worker:
1. Checks the player's geo and device tier from Cloudflare's request metadata
2. Queries the eCPM cache for the top-3 performing networks in that segment
3. Calls each network's server-side ad API in parallel using Promise.all()
4. Returns the highest eCPM offer within a 200ms timeout
Network Integration via Server-Side Ad APIs
Each ad network exposes a server-side API for publishers. CCFish integrates:
| Network | API Method | Key Metric | Integration Complexity |
|---------|-----------|------------|----------------------|
| AdMob | Mediation API | eCPM by ad unit | Low -- REST endpoint |
| Unity Ads | Ad Request API | Fill rate | Medium -- requires segment ID |
| AppLovin | MAX API | Waterfall latency | Low -- JSON request |
| Pangle (TikTok) | Programmatic API | Geo-specific eCPM | Medium -- OAuth setup |
The worker polls each network every 60 seconds, caches results in Cloudflare KV with a 55-second TTL, and exposes a single /ad-request endpoint to the CCFish client. The client sends a lightweight JSON payload with player_id, geo, and device_model, and receives the best available ad offer.
Real-Time Waterfall Optimization
The worker doesn't just forward requests -- it learns. Each ad response includes a served_at timestamp, eCPM bid, and fill status. These are logged to D1 for analytics:
```sql
INSERT INTO ad_waterfall_logs (player_id, network, eCPM_bid, filled, latency_ms)
VALUES ('p123', 'AdMob', 12.50, true, 89)
ON CONFLICT (player_id, served_at) DO NOTHING;
```
A separate analytics Worker runs every 5 minutes, querying D1 to:
- Identify networks with dropping fill rates (below 80% = deprioritize)
- Surface geo-eCPM anomalies (e.g., AppLovin outperforms in Brazil by 3x)
- Generate waterfall reorder recommendations via SQL window functions
The result: eCPM improved by 22% in the first week of deployment compared to the prior static waterfall, and the game binary shrank by 18MB by removing client-side ad SDK bundles.
Results and Monetization Impact
- **35% of total revenue** comes from rewarded video ads, up from 18% before serverless mediation
- **Binaries reduced by 18MB** by stripping client-side ad SDKs
- **eCPM improved 22%** in week 1 through real-time waterfall optimization
- **Zero app store resubmissions** for ad configuration changes
Key Takeaways
- Server-side ad mediation turns rewarded video from a secondary fill-in into a primary revenue channel
- Cloudflare Workers provide sub-200ms ad decision latency without SDK bloat
- Real-time eCPM caching with D1 analytics enables dynamic waterfall reordering that no static SDK can match
- The same worker endpoint can serve rewarded, interstitial, and banner ad types with configurable frequency caps
For a Cocos Creator game like CCFish, every kilobyte of binary size saved goes directly to faster load times and better app store conversion rates. Moving ad logic server-side is both a monetization win and a product quality improvement.
Implementation Details for Cocos Creator
Integrating the server-side ad mediation into CCFish's Cocos Creator client required minimal code changes. The existing game loop already dispatched network requests for leaderboard scores and player data synchronization. Adding an ad request to the Cloudflare Worker endpoint was a 40-line TypeScript module that:
1. Captures the ad placement trigger (level complete, score milestone, daily login streak)
2. Sends a POST request to the Worker endpoint with player context
3. Receives the ad offer JSON (network_url, ad_type, eCPM bid, duration_seconds)
4. Passes the ad URL to Cocos Creator's WebView component for rendering
The WebView approach avoids native SDK dependencies entirely. Because CCFish targets iOS, Android, and Telegram Mini Apps from a single Cocos Creator codebase, WebView-based ad rendering provides cross-platform compatibility that SDK-level integration cannot match.
Latency Budget and Player Experience
A critical concern with server-side ad mediation is latency. Each ad request traverses: CCFish client -> Cloudflare Worker -> ad network API -> response back to player. To stay under the 200ms budget, CCFish implemented three optimizations:
1. Parallel network calls: The Worker fires all ad network requests simultaneously, taking the fastest response that meets the minimum eCPM threshold
2. Regional KV caching: Ad responses are cached per geo-region in Cloudflare KV with a 30-second TTL for sub-50ms cache hits
3. Fallback waterfall: If no network responds within 150ms, the Worker returns a cached default ad placement from the last successful response
Production data shows median ad request latency of 112ms (P50) and 187ms (P95), well within the acceptable range for rewarded video placements.