Short Answer

CCFish's real-time multiplayer tournament mode drove **40% longer session times** and a **22% increase in IAP conversion** within 30 days of global launch. Built on Cloudflare Durable Objects for real-time state and D1 for persistent leaderboards, the feature turned a single-player fishing game into a competitive social platform.

---

The Problem

CCFish launched strong: beautiful underwater environments, 200+ fish species, and a satisfying progression loop. But after players completed the main campaign — typically around day 14 — retention dropped sharply. D7 retention hovered at 38%. D30 was below 10%.

The root cause was clear from player surveys fielded in Q3 2025. When asked "What single feature would bring you back to CCFish?", **68% of respondents answered "real-time tournaments"** or "competing against friends." The game had strong single-player mechanics but zero social or competitive hooks. Fishing alone is peaceful — but peaceful doesn't retain.

```

Player survey results (n=4,200)

Q: "What would make you play CCFish more?"

Rank | Feature Requested | % of Responses

-----|---------------------------|----------------

1 | Real-time tournaments | 68%

2 | Friend leaderboards | 52%

3 | Guilds / clubs | 41%

4 | Chat system | 29%

5 | More campaign content | 22%

```

---

The Solution

We built a real-time multiplayer tournament system with three core components:

1. **Matchmaking Service** — Cloudflare Durable Objects that maintain live WebSocket connections for each active tournament lobby

2. **Leaderboard Engine** — Cloudflare D1 with materialized views that update on every tournament round completion

3. **Prize Pool System** — 5% of all IAP revenue auto-allocated to tournament prize pools, distributed top-10% of finishers

Tournament Flow

```

Player taps "Enter Tournament" login

Matchmaking pool (15s window — optimized from 30s)

Durable Object created / joined for that lobby

3-minute tournament round (catch biggest total fish weight)

Scores pushed via WebSocket → D1 materialized leaderboard

Top 10 players advance to next round (3 rounds total)

Prizes auto-distributed via in-game mail system

```

---

Architecture Overview

Cloudflare Workers + Durable Objects

Each tournament lobby is a Durable Object that holds the authoritative game state. Players connect via WebSocket from the Cocos Creator client. The DO broadcasts position updates, catch events, and the 10-second countdown clock.

```sql

-- D1 schema: tournament state

CREATE TABLE tournaments (

id TEXT PRIMARY KEY,

status TEXT NOT NULL DEFAULT 'pending', -- pending | running | completed

entry_fee INTEGER NOT NULL DEFAULT 99, -- cents

prize_pool INTEGER NOT NULL DEFAULT 0, -- cents

max_players INTEGER NOT NULL DEFAULT 16,

created_at TEXT NOT NULL DEFAULT (datetime('now')),

started_at TEXT,

completed_at TEXT

);

CREATE TABLE tournament_players (

tournament_id TEXT NOT NULL,

player_id TEXT NOT NULL,

score INTEGER NOT NULL DEFAULT 0,

rank INTEGER,

prize_cents INTEGER DEFAULT 0,

joined_at TEXT NOT NULL DEFAULT (datetime('now')),

PRIMARY KEY (tournament_id, player_id),

FOREIGN KEY (tournament_id) REFERENCES tournaments(id)

);

-- Materialized view for live leaderboard

CREATE VIEW leaderboard AS

SELECT tournament_id, player_id, score,

RANK() OVER (PARTITION BY tournament_id ORDER BY score DESC) as rank

FROM tournament_players

WHERE tournament_id = ?;

```

Client-Side Integration

The Cocos Creator client uses a lightweight WebSocket wrapper that reconnects with exponential backoff:

```javascript

// Client: tournament WebSocket manager

class TournamentWS {

constructor(tournamentId, playerId) {

this.url = `wss://api.ccfish.game/tournament/${tournamentId}?player=${playerId}`;

this.reconnectAttempts = 0;

this.maxBackoff = 30000; // 30s cap

}

connect() {

this.ws = new WebSocket(this.url);

this.ws.onopen = () => {

this.reconnectAttempts = 0;

console.log('Tournament WS connected');

};

this.ws.onmessage = (e) => this.handleMessage(JSON.parse(e.data));

this.ws.onclose = () => this.scheduleReconnect();

}

scheduleReconnect() {

const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), this.maxBackoff);

setTimeout(() => {

this.reconnectAttempts++;

this.connect();

}, delay);

}

sendScore(score) {

this.ws.send(JSON.stringify({ type: 'score_update', score }));

}

}

```

---

Implementation

Soft Launch in the Philippines

We soft-launched tournament mode in the Philippines for two weeks. Why Philippines? High IAP conversion rate (12.3% vs 6.1% global average), a competitive mobile gaming culture, and a manageable user base for load testing.

A/B Test: Entry Fees

We tested three entry fee tiers:

| Tier | Fee | Sign-ups | Avg Sessions/Player | IAP Conv. Lift | Notes |

|---------|----------|----------|--------------------|---------------|-------|

| Free | $0.00 | 4,200 | 3.2 | +5% | High volume, low engagement |

| Low | $0.99 | 3,100 | 5.8 | +18% | Best balance |

| Medium | $1.99 | 1,800 | 6.1 | +22% | Highest per-player value, lower volume |

| High | $2.99 | 600 | 5.3 | +28% | Niche whales only |

**Winner: $0.99 tier.** It had the best volume-to-engagement ratio and drove an 18% IAP conversion lift with 3,100 sign-ups.

Matchmaking Window Optimization

Initial matchmaking waited up to 30 seconds to fill a 16-player lobby. Fill rate was 91%, but 30s felt sluggish. We A/B tested:

- **30s window** → 91% fill rate, 23% drop-off during wait

- **15s window** → 78% fill rate, 8% drop-off, but tournaments started 2x faster

- **10s window** → 62% fill rate, 5% drop-off, too many half-empty lobbies

We shipped **15s** as the default. The 78% fill rate was acceptable because partially-filled lobbies scaled prizes proportionally, and faster start times improved the overall experience.

```

Config diff: matchmaking window optimization

-matchmaking_window_ms: 30000

+matchmaking_window_ms: 15000

```

---

Results

30-Day Post-Launch Metrics

| Metric | Pre-Tournament | Post-Tournament | Change |

|---------------------------------|---------------|-----------------|-------|

| Avg session time | 12.4 min | 17.4 min | **+40%** |

| IAP conversion rate | 6.1% | 7.4% | **+22%** |

| D7 retention | 38% | 44% | **+15%** |

| D30 retention | 9% | 14% | **+56%** |

| ARPU (tournament players) | — | $4.50 | — |

| ARPU (non-tournament players) | $1.20 | $1.20 | No change |

| Daily active users | 28,400 | 41,200 | **+45%** |

| Avg tournaments per day | — | 1,840 | — |

| Total prizes awarded | — | $14,200 | — |

What Surprised Us

1. **Whale retention was already high.** The 3x ARPU gap between tournament and non-tournament players ($4.50 vs $1.20) made us worried tournament players were just existing whales. But 62% of tournament sign-ups were new IAP payers. The mode *converted* non-spenders.

2. **Social sharing went viral.** We didn't build any share mechanic — players just started recording their tournament wins and posting them to TikTok. User-generated content around tournaments grew 340% in month one.

3. **Prize pool economics worked.** At 5% of IAP revenue allocated to prizes, the system was net-positive by week two. Players spent more chasing the pot than the pot cost us.

---

Key Takeaways

1. **Competitive hooks are retention engines.** A single tournament mode lifted D30 retention by 56%. When single-player campaigns plateau, give players a reason to compete.

2. **Start with player data, not gut feelings.** The #1 requested feature from surveys (tournaments) became our highest-impact launch. The data was right there.

3. **Entry fees are a lever, not a revenue tool.** $0.99 entry fees drove 3x more total engagement than free entry. A small barrier to entry increased commitment without chilling adoption.

4. **Faster matchmaking beats fuller lobbies.** 15s windows with 78% fill rates outperformed 30s with 91% fill. Speed is a feature.

5. **Durable Objects for real-time, D1 for persistence.** This combination handled 1,840 concurrent tournaments/day with zero downtime and sub-100ms state sync latency.

---

*CCFish tournament mode is available now on iOS and Android. Enter your first tournament for $0.99 — or test the waters in free-entry events every weekend.*