Leaderboards
Updated: Mar 3, 2026
Copy for LLM
Leaderboards are one of the most effective retention tools
This guide covers what leaderboards are, the different types available, the full SDK API, how to create and manage leaderboards, how to display leaderboard data in your game, score formatting, and best practices for maximizing retention impact.
Why Leaderboards Matter for Retention
Leaderboards work because they tap into fundamental human motivations:
- Competition: Players want to be the best, or at least better than their friends. Seeing a friend’s name one spot above them on a leaderboard is a powerful motivator to play “just one more round.”
- Social comparison: Even players who are not intensely competitive enjoy seeing where they stand relative to others. It provides context for their own performance.
- Goal setting: Leaderboards provide implicit goals. “I need 200 more points to pass Sarah” is a concrete, motivating target that the player sets for themselves.
- Social proof: A leaderboard full of friends signals that the game is worth playing. It reinforces the player’s investment in the game.
Data consistently shows that players who engage with leaderboards have higher retention rates than those who do not. Friend-based leaderboards are particularly effective because the names on the board are people the player knows and cares about.
Types of Leaderboards
The Instant Games SDK supports several types of leaderboards, each serving different purposes.
Global Leaderboards
Global leaderboards rank all players of your game across the entire platform. They are useful for:
- Showcasing the absolute best players
- Providing a sense of scale (“1 million players have submitted scores”)
- Giving highly competitive players a long-term goal
However, global leaderboards are less effective for retention than friend-based leaderboards because most players will never reach the top and may feel discouraged by the gap between their score and the leaders.
Friend-Based Leaderboards
Friend-based leaderboards rank a player against only their Facebook friends who also play the game. These are the most powerful leaderboard type for retention because:
- Every name is someone the player knows personally
- The scores are achievable -- the gap between the player and the next rank is usually small
- Beating a friend feels personal and rewarding
- Friends can see that their score was surpassed, creating a back-and-forth dynamic
Contextual Leaderboards
Contextual leaderboards are scoped to a specific game context, such as a Messenger conversation thread or a group. They rank only the players within that context. Contextual leaderboards are useful for:
- Messenger-based games where a group of friends are playing together
- Tournament-like scenarios within a specific group
- Creating intimate, small-group competition
SDK API Reference
Getting a Leaderboard
Use
FBInstant.getLeaderboardAsync() to retrieve a leaderboard by name. The leaderboard must first be configured in the App Dashboard.async function getLeaderboard() { try { const leaderboard = await FBInstant.getLeaderboardAsync('weekly_high_score'); console.log('Leaderboard name:', leaderboard.getName()); console.log('Context ID:', leaderboard.getContextID()); return leaderboard; } catch (error) { console.error('Failed to get leaderboard:', error); return null; } }
Leaderboard Object Methods
| Method | Return Type | Description |
|---|---|---|
getName() | string | The name of the leaderboard. |
getContextID() | string \| null | The context ID associated with the leaderboard, if it is a contextual leaderboard. Returns null for global leaderboards. |
getEntryCountAsync() | Promise<number> | Returns the total number of entries in the leaderboard. |
setScoreAsync(score, extraData?) | Promise<LeaderboardEntry> | Sets the player’s score on the leaderboard. |
getPlayerEntryAsync() | Promise<LeaderboardEntry \| null> | Returns the current player’s leaderboard entry, or null if they have no entry. |
getEntriesAsync(count, offset) | Promise<Array<LeaderboardEntry>> | Returns a list of leaderboard entries, sorted by score. |
getConnectedPlayerEntriesAsync(count, offset) | Promise<Array<LeaderboardEntry>> | Returns leaderboard entries for the current player’s connected friends. |
Setting a Score
Use
setScoreAsync() to submit a player’s score to a leaderboard. The platform keeps only the player’s best score -- if the new score is lower than the existing one, the existing score is preserved.async function submitScore(score) { try { const leaderboard = await FBInstant.getLeaderboardAsync('main_score'); const entry = await leaderboard.setScoreAsync(score); console.log('Score set! New rank:', entry.getRank()); console.log('Score:', entry.getScore()); return entry; } catch (error) { console.error('Failed to set score:', error); return null; } }
Including Extra Data
You can attach additional metadata to a score entry using the optional
extraData parameter. This is a string (up to 2KB) that can contain any information you want to display alongside the score, such as the level where the score was achieved or the player’s avatar configuration.async function submitScoreWithDetails(score, level, character) { try { const leaderboard = await FBInstant.getLeaderboardAsync('main_score'); const extraData = JSON.stringify({ level: level, character: character, timestamp: Date.now(), }); const entry = await leaderboard.setScoreAsync(score, extraData); console.log('Score submitted with extra data'); return entry; } catch (error) { console.error('Failed to submit score:', error); return null; } }
Getting the Player’s Entry
Use
getPlayerEntryAsync() to check the current player’s existing leaderboard entry.async function getMyEntry() { try { const leaderboard = await FBInstant.getLeaderboardAsync('main_score'); const entry = await leaderboard.getPlayerEntryAsync(); if (entry) { console.log('My rank:', entry.getRank()); console.log('My score:', entry.getScore()); console.log('Extra data:', entry.getExtraData()); } else { console.log('No score submitted yet'); } return entry; } catch (error) { console.error('Failed to get player entry:', error); return null; } }
Getting Leaderboard Entries
Use
getEntriesAsync() to retrieve a ranked list of entries from the leaderboard. This returns the global top entries.async function getTopScores() { try { const leaderboard = await FBInstant.getLeaderboardAsync('main_score'); const entries = await leaderboard.getEntriesAsync(10, 0); // Top 10, starting at rank 1 entries.forEach(entry => { console.log( `#${entry.getRank()} ${entry.getPlayer().getName()}: ${entry.getScore()}` ); }); return entries; } catch (error) { console.error('Failed to get entries:', error); return []; } }
Parameters:
count(number): The maximum number of entries to return (up to 100).offset(number): The starting position (0-indexed). Use this for pagination.
Getting Friend Entries
Use
getConnectedPlayerEntriesAsync() to retrieve leaderboard entries for the current player’s connected friends. This is the API you will use most often, as friend-based leaderboards are the most effective for retention.async function getFriendScores() { try { const leaderboard = await FBInstant.getLeaderboardAsync('main_score'); const friendEntries = await leaderboard.getConnectedPlayerEntriesAsync(20, 0); friendEntries.forEach(entry => { const player = entry.getPlayer(); console.log( `#${entry.getRank()} ${player.getName()}: ${entry.getScore()}` ); }); return friendEntries; } catch (error) { console.error('Failed to get friend entries:', error); return []; } }
LeaderboardEntry Object Methods
Each entry returned by the leaderboard APIs is a
LeaderboardEntry object with the following methods:| Method | Return Type | Description |
|---|---|---|
getScore() | number | The score value for this entry. |
getFormattedScore() | string | The score formatted according to the leaderboard’s score format configuration. |
getTimestamp() | number | The Unix timestamp of when the score was last updated. |
getRank() | number | The player’s rank on the leaderboard (1-indexed). |
getExtraData() | string \| null | The extra data string associated with this entry, or null if none was provided. |
getPlayer() | LeaderboardPlayer | The player associated with this entry. Has getName(), getPhoto(), and getID() methods. |
Creating and Managing Leaderboards
Setting Up in the App Dashboard
To create a leaderboard:
- Open the App Dashboard.
- Select your app and navigate to Instant Games > Details.
- Find the Leaderboards section.
- Click Create Leaderboard and provide:
- Name: A unique identifier for the leaderboard (e.g.,
main_score,weekly_best,level_10_time). This is the name you will use ingetLeaderboardAsync(). - Sort order: Whether higher or lower scores are better (ascending or descending).
- Score format: How scores should be displayed (numeric, time, etc.).
- Name: A unique identifier for the leaderboard (e.g.,
Contextual Leaderboards
To create a contextual leaderboard (scoped to a specific game context), append the context ID to the leaderboard name using a period separator:
async function getContextualLeaderboard() { const contextId = FBInstant.context.getID(); if (contextId) { try { const leaderboard = await FBInstant.getLeaderboardAsync( `weekly_score.${contextId}` ); return leaderboard; } catch (error) { console.error('Failed to get contextual leaderboard:', error); return null; } } return null; }
Contextual leaderboards are automatically scoped to the players within that context, making them ideal for Messenger group games or conversation-specific competitions.
Score Formatting
The score format you configure in the App Dashboard determines how
getFormattedScore() displays scores. Common formats include:- Numeric: Displays the raw score number (e.g.,
1,234) - Time: Displays the score as a time value (e.g.,
2:05.3for a score of 125300 milliseconds)
Choose the format that makes the most sense for your game. For most games, numeric formatting works well. For racing games or time-based challenges, time formatting is more intuitive.
Displaying Leaderboard UI
The Instant Games platform does not provide a built-in leaderboard UI -- you build your own. This gives you full control over the visual design and user experience. Here is an example of rendering a friend leaderboard:
async function renderFriendLeaderboard() { const leaderboard = await FBInstant.getLeaderboardAsync('main_score'); const friendEntries = await leaderboard.getConnectedPlayerEntriesAsync(20, 0); const myEntry = await leaderboard.getPlayerEntryAsync(); const container = document.getElementById('leaderboard'); container.innerHTML = ''; // Render header const header = document.createElement('h2'); header.textContent = 'Friends Leaderboard'; container.appendChild(header); if (friendEntries.length === 0) { const emptyMessage = document.createElement('p'); emptyMessage.textContent = 'No friends have played yet. Invite them!'; container.appendChild(emptyMessage); return; } // Render each entry friendEntries.forEach(entry => { const player = entry.getPlayer(); const isCurrentPlayer = myEntry && player.getID() === FBInstant.player.getID(); const row = document.createElement('div'); row.className = `leaderboard-row ${isCurrentPlayer ? 'current-player' : ''}`; row.innerHTML = ` <span class="rank">#${entry.getRank()}</span> <img src="${player.getPhoto()}" alt="${player.getName()}" class="avatar" /> <span class="name">${player.getName()}</span> <span class="score">${entry.getFormattedScore()}</span> `; container.appendChild(row); }); // If the current player is not in the visible list, show their entry separately if (myEntry) { const isVisible = friendEntries.some( entry => entry.getPlayer().getID() === FBInstant.player.getID() ); if (!isVisible) { const separator = document.createElement('div'); separator.className = 'leaderboard-separator'; separator.textContent = '...'; container.appendChild(separator); const myRow = document.createElement('div'); myRow.className = 'leaderboard-row current-player'; myRow.innerHTML = ` <span class="rank">#${myEntry.getRank()}</span> <img src="${FBInstant.player.getPhoto()}" alt="You" class="avatar" /> <span class="name">You</span> <span class="score">${myEntry.getFormattedScore()}</span> `; container.appendChild(myRow); } } }
Best Practices
Show Friends Prominently
The default view of your leaderboard should always be the friend-based leaderboard, not the global one. Friend names and photos create personal, emotional connections that drive engagement. Global leaderboards can be available as a secondary tab for players who want to see them.
Always Show the Current Player
Regardless of where the player ranks, always show their own entry on the leaderboard screen. If they are not in the top visible entries, show their entry at the bottom with a separator (e.g., “...”) to indicate their actual position. A player who cannot find themselves on the leaderboard will feel disconnected.
Highlight Nearby Competitors
When possible, show the players immediately above and below the current player on the leaderboard. This gives the player a clear, achievable next target and a sense of who is gaining on them from below.
Update Scores Frequently
Submit scores to the leaderboard at every natural scoring moment -- at the end of each game session, each level, or each round. Do not wait until the player closes the game. Frequent updates keep the leaderboard current and increase the chances that a friend will see a score change that motivates them to play.
async function onRoundComplete(roundScore, totalScore) { // Submit the total score at the end of every round try { const leaderboard = await FBInstant.getLeaderboardAsync('main_score'); await leaderboard.setScoreAsync(totalScore); } catch (error) { console.error('Failed to update leaderboard:', error); } }
Use Multiple Leaderboards
Do not limit yourself to a single leaderboard. Consider creating leaderboards for different metrics:
- Overall high score -- The primary competitive metric
- Weekly high score -- Resets weekly, giving all players a fresh start and a reason to come back
- Level-specific scores -- Best score on each level or mode
- Total games played -- Rewards dedication, not just skill
- Longest streak -- Tracks consecutive days of play
Multiple leaderboards give more players a chance to shine and provide more reasons to return.
Celebrate Score Milestones
When a player surpasses a friend’s score, make it a moment. Show a special animation, play a sound, and offer to share the achievement. “You just passed Sarah’s score!” is a powerful motivator for both the current player (who feels accomplished) and Sarah (who will want to reclaim her position when she hears about it).
async function checkForScoreBeat(newScore) { const leaderboard = await FBInstant.getLeaderboardAsync('main_score'); const friendEntries = await leaderboard.getConnectedPlayerEntriesAsync(100, 0); const myCurrentEntry = await leaderboard.getPlayerEntryAsync(); const myCurrentRank = myCurrentEntry ? myCurrentEntry.getRank() : Infinity; // Find friends whose scores are between the old rank and new score const beatenFriends = friendEntries.filter(entry => { return entry.getScore() < newScore && entry.getRank() < myCurrentRank; }); if (beatenFriends.length > 0) { const topBeaten = beatenFriends[0]; showCelebration( `You just passed ${topBeaten.getPlayer().getName()}!` ); } }
Reset Leaderboards Periodically
Permanent, all-time leaderboards can become discouraging for new players who feel they can never catch up. Consider implementing time-based leaderboards (daily, weekly, monthly) that reset periodically. This gives every player a fresh start and creates recurring engagement peaks at the beginning of each period.
Show the Leaderboard on the Main Screen
Do not hide your leaderboard behind multiple menu layers. Show a compact version of the friend leaderboard directly on your main menu or home screen. The more often a player sees their friends’ scores, the more motivated they are to play.
Next Steps
- Tournaments -- Create time-limited competitive events.
- Play With Friends -- Retrieve and display connected friends.
- Custom Updates -- Notify friends when their score is beaten.
- Building Social Games -- Strategic guide to social game design.