Implementing Battle Pass Mechanics for Mobile Games
Battle Pass is one of technically most comprehensive monetization elements. It's not just "show reward list" — it's a seasonal system with progression, two tracks, timer, IAP purchase and cross-device progress sync.
Data Architecture
Battle Pass model on server includes minimum three entities:
Season — current season with start/end dates, list of levels (50–100) with free and premium track rewards.
PlayerSeasonProgress — specific player progress: current level, accumulated XP, isPremium flag, claimedRewards list.
SeasonXPTransaction — log of XP grants: source (level_complete, daily_quest, mission), amount, timestamp. Needed for audit and anti-cheat.
struct BattlePassLevel: Codable {
let level: Int
let xpRequired: Int
let freeReward: Reward?
let premiumReward: Reward?
}
struct PlayerSeasonProgress: Codable {
let seasonId: String
let currentLevel: Int
let currentXP: Int
let isPremium: Bool
let claimedRewards: [String] // "level_\(n)_free", "level_\(n)_premium"
}
XP Progression and Balancing
Key question: how much XP per level? Flat (same for each) or scaling (increasing cost)?
Flat XP is simpler but creates situation where hardcore player completes entire Battle Pass first week and loses motivation to pay. Scaling XP maintains interest but can become too aggressive.
Linear scaling with plateau works well: first 20 levels cheap, levels 21–80 grow evenly, 81–100 fixed high cost for "perfectionists". Casual player without skip-levels reaches 70–75 level by season end — this is right balance.
Design XP table in spreadsheet: set expected XP for different activities (level complete, daily quest, event) and calculate how many days casual player needs for each Battle Pass level.
IAP: Purchasing Battle Pass
Battle Pass is sold as non-consumable or auto-renewable subscription — depends on model:
- One-time purchase per season (non-consumable) — simpler for player, easier to implement
- Subscription with auto-renew — stable revenue but requires proper management via StoreKit 2
On iOS with StoreKit 2:
let products = try await Product.products(for: ["battle_pass_season_1"])
guard let battlePass = products.first else { return }
let result = try await battlePass.purchase()
switch result {
case .success(let verification):
let transaction = try verification.payloadValue
await transaction.finish()
await unlockPremiumTrack(for: transaction.id)
case .pending: // awaits confirmation (e.g., Ask to Buy)
break
case .userCancelled:
break
}
Important: server-side transaction validation is mandatory for premium content. Client sends transactionId, server verifies via App Store Server API or Google Play Developer API.
Skip Levels and Gifting
Skip levels (skip levels for hard currency) — additional revenue source. Usually 1 level = 100–150 gems, 10-level pack with small discount. Technically: consumable IAP or gem wallet deduction with server verification.
Gift Battle Pass to friend — feature often requested but rarely implemented. Requires platform Gift Purchase support: iOS supports via StoreKit, Android — partially via Google Play Gifting API (beta since 2023).
Battle Pass UI
Standard UI — horizontal scroll with levels, current level in center, free/premium track rewards above/below. "Claim" button active only for earned unclaimed rewards.
Key UI states for each level:
- Locked (not yet reached)
- Earned, not claimed (reached, reward not taken)
- Claimed (taken)
- Premium locked (only for premium, not purchased)
Reward claim animation — full-screen with particles. This retention moment: player should feel satisfaction from progress.
Seasonal Timer and Season End
Countdown timer creates urgency. Shows in main menu and Battle Pass screen. 3 days before end — push notification: "3 days left, you're X levels away".
On season end: progress archived, unclaimed rewards burn (with 7-day warning), next season launches automatically. Previous season data stored for history in profile.
Timeline and Stages
- Server data model: Season, PlayerProgress, XPLog
- API endpoints: get season, claim reward, add XP, purchase premium
- IAP integration: StoreKit 2 / Google Play Billing 6
- Server transaction verification
- Client UI: level list, reward claiming, timer
- Push notifications 7/3/1 day before season end
- Analytics: events for each earned/claimed reward
Basic implementation (no subscription, no skip levels) — 5 days. Full system with subscription, skip levels, gifting and analytics — 2–3 weeks.







