CCFish runs its entire in-app purchase monetization system through feature flags resolved on Cloudflare Workers at the edge. Every price point, discount tier, bundle offer, and rewarded video frequency is controlled by a server-side feature flag, not a hard-coded constant in the Cocos Creator binary. This architecture lets CCFish run continuous A/B tests on pricing and offers — segmenting players by country, level, session count, lifetime value, and dozens of other attributes — without ever submitting a new build for app review. The result: a 31% uplift in IAP conversion rate across tested segments, a 4x faster iteration cycle for pricing experiments, and a monetization system that adapts to every player in real time.
The Problem — Static Pricing Leaves Money on the Table
Most mobile games ship with hard-coded IAP price tables compiled into the binary. A $2.99 starter pack, a $9.99 fish bundle, a $49.99 whale bundle — these can only change with a new release. This creates three problems:
**One price fits nobody.** A player in Vietnam has different purchasing power than one in the US. A day-one player has different willingness to pay than a day-90 player. Static pricing ignores all these signals.
**Experiments cost weeks.** Testing $1.99 vs. $2.99 means forking the codebase, building two variants, submitting for review, running the test for days, then rebuilding if the winner changes.
**No player-level segmentation.** Static pricing can't differentiate between a whale and a free user who might convert. Showing different offers to different segments means another review cycle.
The Solution — Feature Flag–Driven Monetization
The insight: treat every IAP price, discount, and offer configuration as a feature flag resolved at request time. The game client never knows the actual price. When the player opens the shop, the client sends a request to a Cloudflare Worker, which:
1. Reads the player's identity and session context
2. Evaluates all active feature flags against that player's segment
3. Resolves the final price, offer text, and bundle contents
4. Returns the IAP configuration to the client
The client is a dumb renderer; the edge is the decision engine.
```typescript
interface IAPFeatureFlag {
flagKey: string;
status: "enabled" | "disabled" | "gradual_rollout";
targeting: TargetingRule[];
variants: Variant[];
}
interface TargetingRule {
attribute: string; // "country" | "level" | "session_count" | "lifetime_value"
operator: "equals" | "in" | "greater_than" | "between";
value: string | string[] | number | [number, number];
}
interface Variant {
id: string; // "control" | "variant_a"
weight: number; // traffic allocation (0-100)
priceConfig: {
price: number;
currency: string;
discount: number;
offerText: string;
bundleContents: string[];
};
}
```
Architecture — Resolving IAP Configs at the Edge
```typescript
// Cloudflare Worker: IAP feature flag resolver
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
if (url.pathname === "/api/v1/iap/offers") {
const player = await parsePlayerContext(request);
const flags = await env.KV.get("ff:active-iap-flags", "json") as IAPFeatureFlag[];
const resolved = flags.map(flag => resolveFlag(flag, player));
const active = resolved.filter(o => o.enabled);
return Response.json({
offers: active.map(o => ({
id: o.variant.id, price: o.variant.priceConfig.price,
discount: o.variant.priceConfig.discount,
offerText: o.variant.priceConfig.offerText,
})),
playerSegment: player.segment,
});
}
return new Response("Not found", { status: 404 });
},
};
function resolveFlag(flag: IAPFeatureFlag, player: PlayerContext): ResolvedVariant {
if (flag.status === "disabled") return { enabled: false };
if (!flag.targeting.every(r => evaluateRule(r, player))) return { enabled: false };
// Deterministic assignment via hash of player ID + flag key
const bucket = Math.abs(hashCode(`${flag.flagKey}:${player.id}`)) % 100;
let cumulative = 0;
for (const v of flag.variants) {
cumulative += v.weight;
if (bucket < cumulative) return { enabled: true, variant: v };
}
return { enabled: false };
}
```
**Data flow:** The client requests IAP offers at shop open time. The Worker fetches active flags from KV, fetches player context from D1, evaluates targeting rules, and returns the resolved config as JSON.
Implementation — Feature Flag Categories
CCFish runs feature flags in four categories:
1. Dynamic IAP Pricing Flags
```json
{
"flagKey": "starter-pack-price-v3",
"targeting": [
{ "attribute": "country", "operator": "in", "value": ["US", "CA", "GB", "AU"] },
{ "attribute": "level", "operator": "between", "value": [1, 15] },
{ "attribute": "session_count", "operator": "greater_than", "value": 3 }
],
"variants": [
{ "id": "control", "weight": 50, "priceConfig": { "price": 2.99, "discount": 0, "offerText": "Starter Pack", "bundleContents": ["gold_500", "lives_5"] } },
{ "id": "variant_a", "weight": 25, "priceConfig": { "price": 1.99, "discount": 33, "offerText": "Limited Time Starter Pack", "bundleContents": ["gold_500", "lives_10"] } },
{ "id": "variant_b", "weight": 25, "priceConfig": { "price": 3.99, "discount": 0, "offerText": "Premium Starter Pack", "bundleContents": ["gold_1000", "lives_10", "rare_lure_1"] } }
]
}
```
2. Seasonal Offer Flags
Triggered by inactivity. If a player hasn't logged in for 7+ days, a "Come Back" flag activates:
```json
{
"flagKey": "comeback-offer-may",
"targeting": [
{ "attribute": "days_since_last_session", "operator": "greater_than", "value": 7 },
{ "attribute": "lifetime_value", "operator": "between", "value": [0, 50] }
],
"variants": [
{ "id": "control", "weight": 50, "priceConfig": { "price": 4.99, "discount": 50, "offerText": "Welcome Back Bundle", "bundleContents": ["gold_2000", "lives_20"] } },
{ "id": "variant_a", "weight": 50, "priceConfig": { "price": 6.99, "discount": 30, "offerText": "Champion's Return", "bundleContents": ["gold_3000", "lives_30", "exclusive_skin_1"] } }
]
}
```
3. Rewarded Video Frequency Flags
Controls ad frequency per segment to optimize ad vs. IAP revenue:
```json
{
"flagKey": "rewarded-video-frequency-v2",
"targeting": [
{ "attribute": "player_segment", "operator": "in", "value": ["high_intent_free", "medium_engagement"] },
{ "attribute": "iap_purchase_count", "operator": "equals", "value": 0 }
],
"variants": [
{ "id": "control", "weight": 50, "priceConfig": { "maxDailyRewards": 10 } },
{ "id": "variant_a", "weight": 50, "priceConfig": { "maxDailyRewards": 15 } }
]
}
```
4. Player Segmentation Flags
These assign players to behavioral segments other flags reference:
| Segment | Criteria | Flag Behavior |
|---------|----------|---------------|
| New Player | Level < 5, sessions < 10 | Show starter packs only |
| Engaged Free | Level 5–20, no purchases | Show rewarded video upsells |
| High Intent | Spent > 30s on shop page | Show premium bundles with countdown timers |
| Whale | LTV > $100 | Show VIP bundles, hide discounts |
| Churn Risk | 5+ days inactive | Show aggressive comeback offers |
Results — Measurable Monetization Impact
After deploying this system across 15 countries over 60 days:
- **31% uplift** in IAP conversion rate for tested segments
- **18% increase** in average revenue per paying user (ARPPU)
- **4x faster** iteration cycle (hours instead of 2–4 weeks)
- **12% improvement** in rewarded video completion rate
- **Zero app store rejections** related to pricing changes
- **47 active feature flags** with 23 concurrent A/B tests at peak
Case Study: Starter Pack Price Test
| Variant | Price | Bundle | Conversion | Rev/Player |
|---------|-------|--------|-----------|-------|
| Control | $2.99 | 500 gold, 5 lives | 4.2% | $0.126 |
| Variant A | $1.99 | 500 gold, 10 lives | **6.8%** | $0.135 |
| Variant B | $3.99 | 1000 gold, 10 lives, rare lure | 3.9% | **$0.156** |
Variant A won on conversion (6.8% vs. 4.2%), but Variant B won on revenue per player ($0.156). By splitting targeting — showing Variant A to price-sensitive segments and Variant B to high-LTV segments — CCFish captured the best of both, boosting overall revenue by 23% from this single test in under 48 hours.
Key Takeaways
1. **Feature flags are a monetization lever, not just a dev tool.** Treating IAP pricing as a runtime-resolved flag unlocks dynamic pricing, segmentation, and continuous testing without app store friction.
2. **Cloudflare Workers are the right place for this logic.** Flag resolution at the edge means sub-50ms response times, global distribution, and no infrastructure to manage.
3. **Deterministic assignment matters.** Hash-based bucket assignment (player ID + flag key) ensures consistent pricing per session. Non-deterministic pricing confuses players and erodes trust.
4. **Segment first, optimize second.** Player segmentation is more powerful than A/B testing alone. Knowing who the player is lets you tailor every offer to their context.
5. **Measure the right metrics.** Track conversion rate, revenue per player, and retention — not just short-term revenue. A cheaper pack might convert more but cannibalize future purchases.
6. **Feature flags replace app store submissions for monetization changes.** Every pricing experiment that would have taken a week now takes an hour. The velocity gain compounds across dozens of experiments per quarter.
CCFish's feature flag architecture proves that when a mobile game moves IAP logic to the edge, it's not just a technical improvement — it's a revenue optimization engine that never stops learning.