How to Build a Streaks Feature

Your team decides to add a daily streak feature. Track consecutive days of user activity. Should be straightforward. Three weeks later, you're debugging why users in different time zones lose streaks unfairly, handling edge cases around daylight saving time, and dealing with race conditions when users act near midnight.
Streak tracking seems simple until you implement it. The core logic (did user act today?) hides complexity in "today." Whose today? Server time creates unfair advantages. User time zones require careful handling. Midnight boundaries need grace periods. Consistency matters because broken streaks feel like lost investment.
Trophy handles streak tracking including time zones, streak freezes, and edge cases. The complete implementation guide covers the full process. Integration takes 1 day to 1 week. But understanding what building from scratch involves helps you make informed build versus buy decisions.
Key Points
- Technical challenges that make streak tracking harder than it appears
- Time zone handling and consistency requirements
- Implementation patterns for scalable streak systems
- Integration examples with Trophy's API
- Build versus buy considerations for streak features
The Technical Reality
Before building streak tracking, understand the problems you're solving.
Time zone fairness requires per-user calculations. A user in Tokyo and a user in New York shouldn't compete on different playing fields. Server-time streaks give systematic advantages to users in certain time zones. Implementing time zone handling correctly takes weeks and ongoing maintenance as time zone rules change.
Consistency guarantees prevent race conditions. If a user acts at 11:59 PM and 12:01 AM, that's one action or two depending on timing. Concurrent requests near midnight create edge cases. Without proper handling, users might extend streaks twice for one action or lose streaks despite acting.
Streak freeze logic adds complexity. Users need forgiveness for missed days without making streaks meaningless. Tracking freeze counts, granting new freezes over time, and applying them correctly when streaks would break requires careful state management.
Historical data for streak calendars and analytics needs efficient storage and querying. Showing users their past year of activity means storing and retrieving daily status. This grows linearly with users and time.
DST transitions create days that are 23 or 25 hours long. Naive date math breaks. Users might lose streaks on spring-forward days or extend twice on fall-back days without proper handling.
Building production-ready streaks typically takes 1-2 months including edge cases and testing. Trophy's infrastructure handles these problems, reducing implementation to integration work.
Architecture Patterns
If building in-house, these patterns avoid common mistakes.
Event-based tracking separates user actions from streak computation. Store time stamped events. Compute streak status from event history rather than maintaining streak counters directly. This enables accurate historical queries and simplifies consistency.
Per-user timezone storage lets you compute streaks in user-local time. Store user timezone preferences. Convert all streak calculations to user-local time. This requires timezone libraries that handle DST correctly.
Grace periods around midnight prevent losing streaks from being minutes late. Allow actions within 3-6 hours after midnight to count for the previous day. This reduces anxiety without meaningfully weakening consistency incentives.
Eventual consistency in streak display is acceptable. Showing slightly stale streak counts for a few seconds doesn't affect user experience. Prioritize correctness over real-time updates. Trophy's architecture uses eventual consistency with fast convergence (milliseconds to seconds).
Precomputed streak state for active users improves query performance. Maintain current streak length in fast storage (Redis or similar). Recompute from event history only when needed. This pattern scales better than computing from scratch on every query.
Trophy uses event-based architecture with timezone-aware computation and cached state. This combination provides both correctness and performance without requiring you to implement it.
Implementation Estimate
Here's realistic timeline for building streaks in-house:
Week 1: Basic implementation. Track user actions. Simple consecutive-day logic. Works in development with sample data.
Week 2: Time zone handling. Per-user timezone storage. Converting calculations to local time. Handling timezone changes when users travel.
Week 3: Streak freezes. Implementing freeze grants, consumption, and limits. Making freeze logic interact correctly with streak extension.
Week 4-5: Edge cases. DST transitions. Grace periods. Race conditions near midnight. Historical data queries for calendar views.
Ongoing: Maintenance. Time zone rule updates. Bug fixes for edge cases discovered in production. Performance optimization as usage scales.
That's 5+ weeks of engineering time plus ongoing maintenance. Trophy's infrastructure eliminates this timeline, reducing implementation to 1 day to 1 week of integration work.
Building with Trophy
Trophy's integration is faster because streak infrastructure already exists. Here's what implementation looks like.
Step 1: Configure Streak Settings
In Trophy's dashboard, configure your streak frequency (daily, weekly, or monthly) and select which metrics should extend streaks.
For example, if users should maintain streaks by completing lessons, select your lessons_completed
metric. Trophy handles streak logic automatically when events arrive for that metric.
Configure streak freezes if desired: initial freeze count for new users, freeze accumulation rate, and maximum freeze count. Trophy grants and consumes freezes automatically based on your settings.
Step 2: Identify Users with Timezones
When identifying users with Trophy, include their timezone for accurate streak tracking:
import { TrophyApiClient } from '@trophyso/node';
const trophy = new TrophyApiClient(process.env.TROPHY_API_KEY);
// Identify user with timezone
await trophy.identify('user-123', {
name: 'Joe Bloggs'
tz: 'America/New_York' // User's IANA timezone identifier
});
Trophy uses this timezone for all streak calculations. If users travel, update their timezone and Trophy adjusts streak windows accordingly. This ensures fair streak tracking globally.
Step 3: Track Metric Events
Send events when users perform actions that should extend streaks:
// When user completes a lesson
await trophy.metrics.event('lessons_completed', {
user: {
id: 'user-123'
},
value: 1 // 1 lesson completed
});
Trophy processes the event and automatically:
- Determines if it extends the user's streak based on their local timezone
- Applies streak freezes if the user missed days
- Updates streak length and history
- Returns the updated streak status in the response
The response includes the user's current streak information:
const response = await trophy.metrics.event('lessons_completed', {
user: {
id: 'user-123'
},
value: 1 // 1 lesson completed
});
if (response.currentStreak?.extended) {
// User extended their streak with this action
console.log(`Streak length: ${response.currentStreak.length}`);
}
Step 4: Display Streak Information
Fetch user's streak status to display in your app:
// Get user's current streak
const streak = await trophy.users.streak('user-123');
console.log({
length: streak.length, // Current streak length (e.g., 15)
started: streak.started, // When streak started
expires: streak.expires, // When streak expires in user's timezone
freezesRemaining: streak.freezes // Number of freezes available
});
Trophy's API returns comprehensive streak data including expiration time in the user's local timezone. Use this for reminder notifications or UI that shows time until streak expires.
Step 5: Display Streak History
For calendar views showing past activity:
// Get streak with historical data
const streak = await trophy.users.streak('user-123', {
historyPeriods: 90 // Last 90 days of history
});
// streak.streakHistory contains daily activity for calendar display
streak.streakHistory.forEach(period => {
console.log(`${period.periodStart}: streak length ${period.length}`);
});
Trophy returns activity data for building calendar visualizations. The user streak API documentation covers all available fields and query options.
Handling Edge Cases
Production streak systems encounter edge cases that development testing misses. Trophy handles these automatically.
Users crossing time zones should have streaks follow them. If a user flies from California to Japan, their streak window shifts to Japan time. Trophy tracks user timezone and adjusts automatically when you update it.
Midnight action ambiguity needs clear rules. Trophy's grace period logic allows actions shortly after midnight to count for the previous day. This prevents losing streaks from being minutes late while maintaining meaningful consistency.
Daylight saving transitions create 23-hour or 25-hour days. Trophy's date math accounts for DST, ensuring users don't lose streaks on transition days due to calendar arithmetic.
Concurrent actions near midnight could double-count or create race conditions. Trophy's event processing ensures each action counts correctly for exactly one day, regardless of concurrency.
Freeze consumption timing affects user experience. Trophy applies freezes automatically when users would otherwise lose streaks, transparently maintaining their investment without manual intervention.
These edge cases take weeks to discover and fix when building in-house. Trophy's production experience means they're already handled correctly.
Streak Freeze Implementation
Streak freezes let users miss days without losing streaks. How streak freezes keep users engaged explores the psychology and strategy behind forgiveness mechanics.
Trophy's freeze system includes:
- Initial freeze grant: New users receive configured initial freezes
- Automatic accumulation: Users gain freezes over time based on your configuration
- Maximum limit: Freeze count caps at your configured maximum
- Automatic consumption: Trophy consumes freezes when users miss days
- Transparent tracking: Users see remaining freeze count in API responses
Configure these in Trophy's dashboard without code changes. Testing different freeze strategies requires updating configuration, not rewriting logic.
// Streak response includes freeze information
const streak = await trophy.getStreak('user-123');
console.log({
freezesRemaining: streak.freezes,
maxFreezes: streak.maxFreezes,
freezeAutoEarnAmount: streak.freezeAutoEarnAmount,
freezeAutoEarnInterval: streak.freezeAutoEarnInterval
});
Notification Strategy
Streak reminders help users maintain consistency without creating anxiety. Trophy's email system handles notification timing automatically.
Configure streak emails in Trophy's dashboard:
- Customize message content using a no-code email builder
- Target specific user segments if needed
Trophy sends notifications based on user timezone, ensuring reminders arrive at appropriate local times. No manual timezone handling required.
Performance Considerations
Trophy's infrastructure is built for scale, but your integration patterns affect performance.
Cache streak data for display in high-traffic areas. Streak counts don't need real-time accuracy. Cache for 30-60 seconds:
const cache = new Map();
async function getCachedStreak(userId: string) {
const cached = cache.get(userId);
if (cached && Date.now() - cached.timestamp < 60000) {
return cached.data;
}
const fresh = await trophy.users.streak(userId);
cache.set(userId, { data: fresh, timestamp: Date.now() });
return fresh;
}
Handle API errors gracefully. Network issues happen. Don't block critical user flows:
try {
const response = await trophy.metrics.event('lessons_completed', {
user: {
id: 'user-123'
},
value: 1
});
} catch (error) {
console.error('Failed to track event:', error);
}
Batch events when possible. If users perform multiple tracked actions in one session, Trophy's API handles batching efficiently.
Trophy handles backend scaling automatically. These client-side patterns optimize your application's performance without affecting Trophy's streak calculations.
Testing Strategies
Streak systems are hard to test because they depend on time. Trophy provides tools for testing without waiting days.
Test with different timezones to ensure fair handling. Create test users in various timezones and verify streak calculations work correctly for each. Trophy's timezone support means your integration code stays simple while handling global complexity.
Test across midnight boundaries by simulating actions at 11:59 PM and 12:01 AM. Verify streak extends correctly and grace periods work as expected. Trophy's APIs work consistently regardless of timing.
Test freeze consumption by having test users miss days. Verify freezes consume correctly and streaks maintain. Trophy's automatic freeze handling should work without special code paths.
Test DST transitions by simulating actions on transition days. These are the hardest edge cases. Trophy handles them, but verify your UI displays correctly during transitions.
Trophy's staging environment lets you test integration without affecting production data. The development guide includes testing strategies and example scenarios.
Build vs. Buy Decision
Here's how to think about build versus buy for streaks:
Build in-house when:
- Your streak requirements are so unusual that platforms don't support them
- You have backend engineers with capacity for 2-3 months of work plus maintenance
- Engineering control over infrastructure is critical to your business
- Scale is small enough that simple implementations work (under 1,000 users)
Use Trophy when:
- You want streaks in days, not months
- Time zone handling needs to be correct globally
- Engineering time is better spent on core features
- Maintenance burden should be minimized
Trophy's implementation guide walks through the complete integration process. Most teams complete basic streak functionality in 1-2 days, advanced features in 3-5 days. Compare this to 2-3 months building from scratch including time zones, freezes, and edge cases.
Understanding User Behavior
Trophy provides analytics showing streak distribution across your user base. Understanding what happens when users lose their streaks helps you design better forgiveness mechanics and communication strategies.
Monitor these patterns:
- Average streak length across all users
- Distribution of streak lengths (how many at 7 days, 30 days, 100+ days)
- Freeze usage patterns (immediate consumption vs. accumulation)
- Restart rates after breaks (do users return after losing streaks?)
Trophy's analytics dashboard shows these metrics. Connecting them to your retention data reveals whether streaks drive sustainable engagement or create pressure that leads to churn.
FAQ
How long does Trophy integration take for streaks?
Basic streak tracking: 1-2 days including user identification with timezones and event tracking. Advanced features like custom freeze logic or complex calendar views: 3-5 days. Compare this to 2-3 months building in-house.
What happens if Trophy's API goes down?
Design your integration to degrade gracefully. Queue events for retry. Show cached streak data. Most teams find Trophy's uptime exceeds what they'd achieve with in-house infrastructure given resource constraints. The event tracking documentation includes reliability guidance.
How do we handle users with unreliable internet?
Trophy's API is designed for reliability, but network issues happen. Implement retry logic with exponential backoff. Queue failed events locally. Trophy's idempotency support prevents duplicate processing when retrying.
Can we customize streak rules?
Trophy supports daily, weekly, and monthly streak frequencies. Grace periods are configurable. Freeze grants and limits are configurable. This covers most use cases. If you need truly custom streak logic, building in-house gives full control, but validate this need before committing to months of development.
How do we test without waiting days?
Trophy provides test environments where you can manipulate time for testing. Create test users, track events with different timestamps, and verify streak behavior without waiting. The development guide includes testing strategies.
What if we want to change streak settings later?
Trophy's dashboard configuration means changes don't require code deployments. Adjust freeze grants, streak frequency, or which metrics count toward streaks through configuration. Changes apply to future streak periods without affecting users' existing streaks.
Trophy is gamification infrastructure that retains users.
Gamification infrastructure that retains users.
Gamification APIs for web and mobile
Free up to 100 users. No CC required.
Get updates
Stay in the loop with all things gamification.