Building a Daily Reward System in Under 500 Lines
A daily reward system is one of the simplest retention tools to build and one of the easiest to get wrong. Here is the clean version: data model, streak logic, and edge cases.

A daily reward system needs four things: a way to know when the player last claimed, a reward table that maps days to rewards, streak logic that handles gaps gracefully, and a display that shows what is available and what is coming. All of this fits comfortably in under 500 lines if the architecture is clean.
Why this matters
Daily rewards are the most common retention mechanic in mobile games, and the implementation quality varies enormously. A poorly built version produces timezone bugs, clock manipulation exploits, streak confusion, and player frustration.
A clean version takes roughly the same development time as a messy one. The difference is in the planning, not the effort.
The mechanic itself is covered in Three Retention Mechanics Worth Stealing. This post is about how to build it.
The data model
Three fields, stored per player.
lastClaimDate. The calendar date of the most recent claim, stored as a date string in a consistent timezone. Not a timestamp, because the question is "which day" not "what time."
currentStreak. The number of consecutive days the player has claimed. Resets or softens on a gap, depending on your design choice.
totalClaims. The lifetime number of claims. Useful for analytics and for milestone rewards that do not depend on streaks.
The data structure is simple: a date string for the last claim, an integer for the current streak, and an integer for total claims. Three fields, nothing else.
Keep the data model small. Every field you add is a field you must validate, migrate, and defend against clock manipulation.
The reward table
A static table mapping streak day to reward. The table cycles, so day eight gives the day one reward again, or starts a higher tier.
| Streak day | Reward | Notes |
|---|---|---|
| 1 | 50 coins | Low, easy, immediate |
| 2 | 75 coins | Small increase |
| 3 | 100 coins | Noticeable step |
| 4 | 150 coins | Midweek bump |
| 5 | 200 coins | Approaching the milestone |
| 6 | 300 coins | Strong incentive to complete |
| 7 | Rare item or 500 coins | The weekly milestone |
Two design rules for the table.
- Escalate gradually. The day seven reward should be meaningfully better than day one, but not so large that daily play feels mandatory rather than rewarding.
- The milestone reward should feel special. A unique item, a larger currency amount, or an unlock that is only available through the streak. This is what makes the streak worth protecting.
The table is static data, not code. Store it as configuration so designers can tune it without a code change.
The claim logic
The core function runs on game launch and when the player taps the claim button.
Step one: determine today's date in the game's reference timezone. Always use server time or a consistent reference. Device time is unreliable and manipulable.
Step two: compare today to lastClaimDate.
Three possible results.
- Same day. Already claimed today. Show the claimed state and the next reward.
- Next consecutive day. Increment the streak, give the reward, update lastClaimDate.
- Gap of two or more days. The streak is broken. Apply your gap policy (reset or soften), give the day one reward, update lastClaimDate.
Step three: update the data model and save it.
The logic is a single function: check if today equals the last claim date (already claimed), check if today is the day after the last claim (consecutive, increment streak), otherwise reset the streak. Then look up the reward from the table using the streak day modulo seven, update the three fields, and save.
That is the complete claim logic. The rest is display.
Handling edge cases
Four edge cases that produce bugs if not handled.
Timezone boundaries. A player who plays at 11:55 PM and again at 12:05 AM should get two claims, not one. Use a fixed reference timezone for the date calculation, not the device's local time.
Clock manipulation. If you use device time, players can advance the clock to claim future rewards. Use server time for the date check, or validate the claim server-side.
First-time players. A player with no lastClaimDate is on streak day one. Handle the null case explicitly rather than letting it fall through.
Long absences. A player returning after weeks should see a welcoming state, not a punishment. Show what they can earn today rather than what they lost. The principle here matches the retention approach in Seasons, Events and Streaks: never punish a returning player.
The soft reset
The most important design decision in the system.
A hard reset drops the streak to one after any missed day. A soft reset preserves part of the streak or allows a forgiveness window.
Three soft reset options.
- One free miss. The streak survives one gap but resets on two consecutive missed days.
- Partial reset. The streak drops by half instead of resetting to one. A player on day six drops to day three rather than day one.
- Recovery token. The player can spend a small amount of currency to restore a broken streak. This adds a monetization touchpoint without punishing free players.
Soft resets retain more players than hard resets. The data is consistent across genres. A player who lost a six-day streak to a hard reset on day seven frequently stops engaging with the system entirely. A partial reset keeps them invested.
The display
What the player sees matters as much as the logic.
- Show today's reward prominently. It should be obvious what they get right now.
- Show the upcoming rewards. Seeing tomorrow's reward and the milestone creates anticipation.
- Mark claimed days visually. A row or calendar with claimed days filled in gives the streak a visible shape.
- Show the streak count. "Day 4 of 7" is motivating. The number alone is less so.
- Animate the claim. Coins falling, a box opening, a stamp landing. The claim moment should feel good, per Why Juice Sells.
Architecture for under 500 lines
Keeping the system small requires clean separation.
Data layer: 30 to 50 lines. The three-field model, load, save, and validation.
Claim logic: 40 to 60 lines. The function described above, plus gap policy and edge case handling.
Reward table: 20 to 30 lines. Static configuration, lookup by streak day, cycling logic.
Display controller: 100 to 150 lines. UI state management, animation triggers, and the calendar view.
Display views: 150 to 200 lines. The visual elements, layouts, and animations.
Total: 340 to 490 lines. Well under 500, with room for comments and spacing.
The key to keeping it small is resisting the urge to add features before the base system is running. Achievements, bonus wheels, and premium tracks can come later and should each be separate modules.
What we would do
Build the three-field data model and the claim function first. Test it with unit tests covering same-day, consecutive, gap, null, and timezone boundary cases before building the display.
Use server time for the date reference and store the reward table as static configuration. Both decisions prevent entire categories of bugs.
Then implement a soft reset, specifically the one-free-miss variant. It is the simplest to build and it produces the best retention outcome. Add the recovery token later if the data supports monetizing it.
The short version
- Three fields per player: lastClaimDate, currentStreak, totalClaims.
- The reward table is static data, not code. Escalate gradually with a meaningful milestone at day seven.
- Use server time, not device time, for the date calculation.
- Handle four edge cases: timezone boundaries, clock manipulation, first-time players, and long absences.
- Soft resets retain more players than hard resets. Start with one free miss.
- Show today's reward, the upcoming rewards, and the streak progress visually.
Build the claim function and test the edge cases this week. If you want a retention system designed and built into your game, get in touch.
Related reading: Three Retention Mechanics Worth Stealing, Seasons, Events and Streaks, and Why Juice Sells.
Got a game idea? We build it.
You bring the concept. We design, build, test and launch it, and you own 100% of the finished game.
Share Your Game Idea →