GAMIFICATION GUIDES

How to Build a Leaderboards Feature

Author
Charlie Hopkins-BrinicombeCharlie Hopkins-Brinicombe

Your product manager wants leaderboards. You estimate three weeks. Six weeks later, you're still debugging edge cases around time zones and optimizing queries that timeout at scale.

Leaderboards look simple. Display a sorted list of users and their scores. But production leaderboards require handling concurrent updates, efficient ranking algorithms, time-based resets, and global scale. Most teams underestimate the complexity until they're deep in implementation.

Trophy solves these problems through purpose-built leaderboard infrastructure that integrates in 1 day to 1 week. The complete implementation guide walks through the full process. But understanding what building from scratch actually involves helps you make informed build versus buy decisions.

Key Points

  • Technical challenges that make leaderboards harder than they appear
  • Architecture patterns for scalable leaderboard implementation
  • Time and cost estimates for building versus using a platform
  • Integration patterns with Trophy for rapid implementation
  • Code examples for common leaderboard scenarios

The Technical Reality

Before starting implementation, understand what you're actually building.

Real-time ranking computation doesn't scale naively. Sorting millions of users on every score update kills database performance. You need incremental ranking algorithms, precomputed rankings, or approximate methods. Implementing these correctly takes weeks.

Concurrent update handling creates race conditions. Two users updating scores simultaneously can corrupt rankings if not handled atomically. You need proper transaction isolation or event-based processing. Getting this wrong creates subtle bugs that surface under load.

Time-based resets for daily, weekly, or monthly leaderboards require accurate timekeeping across time zones. When does a daily leaderboard end globally? Trophy handles time zones automatically, but building this yourself means implementing per-user timezone logic and handling daylight saving transitions.

Query optimization becomes critical at scale. Fetching top 100 users is fast. Finding a specific user's rank among millions is slow without proper indexing. Getting both rankings and nearby competitors in one query requires careful optimization.

Data consistency between score updates and rankings needs attention. Eventually consistent systems might show stale rankings. Strongly consistent systems sacrifice availability. Choosing the right consistency model matters.

Building production-ready leaderboards from scratch typically takes 3-6 months including all these considerations. Trophy's infrastructure handles them, reducing implementation to 1 day to 1 week of integration work.

Architecture Patterns

If you're building in-house, these patterns help avoid common pitfalls.

Event-based score updates separate writes from ranking computation. User actions create score events. A separate process computes rankings asynchronously. This pattern scales better than synchronous ranking updates but adds complexity.

Sorted sets in Redis provide efficient ranking operations. Redis ZADD and ZRANK commands handle concurrent updates and ranking queries efficiently. But you still need to handle persistence, time-based resets, and integration with your application data.

Precomputed materialized views in your database work for smaller scale. Create a rankings table updated via triggers or batch jobs. Query this table for leaderboards. This pattern is simpler but doesn't scale as well as Redis-based approaches.

Approximate counting using HyperLogLog or similar algorithms works when exact rankings aren't critical. Users outside top 1,000 might see approximate ranks like "~50,000" which is sufficient for most use cases.

Trophy uses event-based architecture with Redis-backed ranking computation, materialized in PostgreSQL for durability. This combination provides both performance and reliability without you needing to implement it.

Implementation Estimate

Here's a realistic timeline for building leaderboards in-house with a competent backend engineer:

Week 1-2: Basic implementation. Score tracking, simple ranking logic, API endpoints. Everything works in development with small data volumes.

Week 3-4: Performance optimization. Query optimization, caching, handling concurrent updates properly. Making it work at scale reveals the real challenges.

Week 5-6: Time-based resets. Implementing daily/weekly/monthly leaderboards with proper time zone handling. This is harder than it looks.

Week 7-8: Edge cases and testing. Race conditions, consistency guarantees, handling database failures gracefully. QA finds issues you didn't anticipate.

Ongoing: Maintenance and evolution. As usage grows, performance degrades. New features require system evolution. This maintenance burden continues indefinitely.

That's 8+ weeks of engineering time plus ongoing maintenance. At typical fully-loaded costs for a backend engineer, this represents significant development investment, plus opportunity cost of features not built.

Trophy's pricing is based on monthly active users. The cost comparison depends on your specific usage and engineering costs, but for many teams, platform costs become competitive with in-house development when factoring in both initial build time and ongoing maintenance.

Building with Trophy

Trophy's integration is significantly faster because the infrastructure already exists. Here's what implementation actually looks like.

Step 1: Set Up Metrics

Leaderboards rank users based on metrics. First, define what you want to track. In Trophy's dashboard, create a metric for the action you want to rank users by.

For example, if you're building a fitness app leaderboard ranking by workouts completed, create a workouts_completed metric. Trophy's dashboard makes this a form-fill operation taking seconds.

Step 2: Track Events

Send events to Trophy when users perform tracked actions. Here's an example using Trophy's API:

import { TrophyApiClient } from '@trophyso/node';

const trophy = new TrophyApiClient({ apiKey: process.env.TROPHY_API_KEY });

// When user completes a workout
async function handleWorkoutComplete(userId: string) {
  const response = await trophy.metrics.event("workouts_completed", {
  user: {
    id: "18",
    email: "[email protected]",
    tz: "Europe/London",
  },
  value: 1, // 1 workout completed
});
  
  // Response includes updated leaderboard positions if user is ranked
  console.log(response.leaderboards);
}

Trophy processes events in milliseconds and updates leaderboard rankings automatically. The response includes the user's updated leaderboard positions, which you can use to show real-time feedback.

Step 3: Create Leaderboard

In Trophy's dashboard, create a leaderboard configuration:

  • Choose the type of leaderboard (e.g "Metric").
  • Choose the metric to rank by (e.g., workouts_completed)
  • Set the time window (e.g. every 3 days, every 6 months or perpetual)
  • Configure maximum participants (up to 1,000)
  • Set start/end dates if time-limited

Trophy handles all ranking computation, time zone processing, and data storage. No code required for the leaderboard logic itself.

Step 4: Display Rankings

Fetch leaderboard data to display in your app:

// Get top 10 users on a leaderboard
async function getLeaderboard(leaderboardKey: string) {
  const leaderbooard = await trophy.leaderboards.get("weekly-words", {
    offset: 0,
    limit: 10,
    run: "2025-01-15" // The specific week to get rankings for
  });
  
  return leaderboard.rankings.map(ranking => ({
    userId: ranking.userId,
    rank: ranking.rank,
    value: ranking.value
  }));
}

The leaderboard API documentation covers all query options including querying historical rankings for previous leaderboard runs.

Step 5: Show Position Changes

Trophy tracks rank changes, making it easy to show users when they move up or down:

// The metric event response includes leaderboard changes
async function handleWorkoutComplete(userId: string) {
  const response = await trophy.metrics.event('workouts_completed', {
    user: {
      id: "user-id"
    },
    value: 1
  });
  
  // Check if user moved up in rankings
  const leaderboard = response.leaderboards['weekly_workout_leaderboard'];
  if (leaderboard && leaderboard.rank < leaderboard.previousRank) {
    const positionsGained = leaderboard.previousRank - leaderboard.rank;
    showNotification(`You moved up ${positionsGained} positions!`);
  }
}

This real-time feedback creates engaging user experiences without complex rank tracking logic on your side.

Time-Based Leaderboards

Time-based leaderboards that reset daily, weekly, or monthly require careful handling of time zones and reset logic. Trophy manages this automatically.

When you create a leaderboard with a time window (e.g., "every 7 days"), Trophy:

  • Tracks user scores within the current time period
  • Resets scores at period boundaries
  • Handles time zones so all users get fair competition windows
  • Finalizes rankings after all time zones complete the period
  • Archives past period results for historical reference

Your code stays simple. Just send events and fetch rankings. Trophy handles the complexity of time-based competition.

// Create events - Trophy handles which period they belong to
const response = await trophy.metrics.event('workouts_completed', {
  user: {
    id: "user-id"
  },
  value: 1
});

// Fetch current week's leaderboard
const currentWeek = await trophy.leaderboards.get('weekly_workout_leaderboard');

// Fetch specific past week using the 'run' parameter
const lastWeek = await trophy.leaderboards.get('weekly_workout_leaderboard', {
  run: '2025-10-10' // Start date of the period
});

Historical leaderboard data persists automatically. You can display past winners or track user improvement over time without additional database design.

Filtered and Segmented Leaderboards

Many products need multiple leaderboard views. Friends only. Same region. Same skill level. Trophy supports this through user attributes.

First, set user attributes when identifying users:

await trophy.users.identify("user-id", {
  name: "Joe Bloggs",
  attributes: {
    region: 'north_america',
    skill_level: 'intermediate'
  }
});

Then create filtered leaderboards in Trophy's dashboard using these attributes. The same metric events feed multiple leaderboards, but each leaderboard only ranks users matching its filters.

This enables sophisticated leaderboard structures without complex query logic:

  • Global leaderboard (all users)
  • Regional leaderboards (filtered by region)
  • Skill-level leaderboards (filtered by skill_level)
  • Friend leaderboards (filtered by custom friend relationships)

Trophy's user attributes system makes segmentation straightforward.

Performance Considerations

Trophy's infrastructure is built for scale, but your integration patterns affect performance.

Cache leaderboard data on your side for read-heavy scenarios. Leaderboard rankings don't need real-time accuracy for display. Cache for 30-60 seconds:

const cache = new Map();

async function getCachedLeaderboard(key: string) {
  const cached = cache.get(key);
  if (cached && Date.now() - cached.timestamp < 60000) {
    return cached.data;
  }
  
  const fresh = await trophy.leaderboards.get(key);
  cache.set(key, { data: fresh, timestamp: Date.now() });
  return fresh;
}

Fetch only needed data using Trophy's query parameters. Don't fetch all 1,000 participants if you only display top 10:

// Efficient: Only fetch top 10
const top10 = await trophy.leaderboards.get(key, { limit: 10 });

// Inefficient: Fetch everything then filter client-side
const all = await trophy.leaderboards.get(key);
const top10 = all.rankings.slice(0, 10); // Don't do this

Trophy handles backend scaling automatically. These client-side patterns optimize your application's performance.

Handling Edge Cases

Production leaderboards encounter edge cases that development testing misses. Trophy handles these automatically, but understanding them helps you design better user experiences.

Tied scores need tie-breaking logic. Trophy breaks ties using timestamps (earlier achievement ranks higher). Communicate this to users so ties feel fair rather than arbitrary.

New users entering full leaderboards need to displace the lowest-ranked user. Trophy handles this automatically when leaderboards reach their participant limit. Users must exceed the lowest score to enter.

Score corrections might require re-ranking. If you discover fraudulent activity and need to adjust scores, Trophy's event system lets you send corrective events that trigger re-ranking.

Deleted users should be removed from leaderboards. When users delete accounts, Trophy can remove them from active leaderboards while preserving historical accuracy.

These edge cases typically take weeks to discover and fix when building in-house. Trophy's production experience means they're already handled.

Build vs. Buy Decision Matrix

Here's how to think about the build versus buy decision for leaderboards specifically:

Build in-house when:

  • Your leaderboard requirements are unusual enough that platforms don't support them
  • You have backend engineers with spare capacity (rare)
  • 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 leaderboards in weeks, not months
  • Engineering time is better spent on core product features
  • You need proven infrastructure that handles scale and edge cases
  • Maintenance burden should be minimized

Most teams find that platform costs are competitive with the engineering time required to build and maintain leaderboards in-house, especially when considering opportunity cost.

Migration from Existing Systems

If you've already built leaderboards in-house but want to migrate to Trophy, here's the pattern:

Phase 1: Dual write. Send events to both your system and Trophy. Validate that Trophy's rankings match your implementation.

Phase 2: Comparison. Run both systems in parallel for a period. Compare rankings and ensure consistency.

Phase 3: Switch reads. Start fetching leaderboard data from Trophy instead of your system.

Phase 4: Decommission. Remove your leaderboard implementation after a safety period.

Trophy's event API makes this migration smooth. You can transition with minimal risk by running systems in parallel initially.

FAQ

How long does Trophy integration actually take?

For basic leaderboards: 1 day setup including authentication and event tracking implementation. A few extra days for UI development. For complex multi-leaderboard setups with segmentation, perhaps a day more Compare this to 2-3 months building from scratch.

What about vendor lock-in?

Trophy's event data is yours. Export it anytime via API. If you eventually want to move to in-house infrastructure, you can migrate your event history. But most teams find Trophy's value continues to justify the cost compared to maintenance burden.

Can Trophy handle our scale?

Trophy processes millions of events daily and supports leaderboards up to 1,000 participants. If you need larger leaderboards or higher volume, contact Trophy's team to discuss enterprise options.

What if Trophy's API goes down?

Design your integration to degrade gracefully. Queue events for retry. Show cached leaderboard data. Most teams find Trophy's uptime exceeds what they'd achieve with in-house infrastructure given resource constraints.

How do we handle real-time updates in our UI?

Trophy's APIs are fast enough for polling (every 30-60 seconds) without creating scaling issues. For true real-time updates, cache aggressively and update on user actions rather than polling. Trophy's event response includes updated rankings for immediate feedback.

Can we customize leaderboard rules?

Trophy's metrics can track any user action. Leaderboards can rank by any metric. User attributes enable filtered leaderboards. This combination covers most use cases. If you need something truly custom, building in-house might be necessary, but validate this before committing to months of development.

What's the alternative if Trophy doesn't fit?

Building in-house remains an option. Use the architecture patterns in this post. Budget 3-6 months of engineering time plus ongoing maintenance. For many teams, this investment exceeds Trophy's lifetime cost, but some requirements genuinely need custom infrastructure.


Free up to 100 users. No CC required.