Leaderboard Manager - ArtyProf/steamworks-ffi-node GitHub Wiki
Complete reference for all leaderboard-related functionality in Steamworks FFI.
The SteamLeaderboardManager provides 100% coverage of the Steamworks Leaderboard API with 7 functions organized into logical categories. Leaderboards allow you to rank players globally, display scores, and attach user-generated content to entries.
| Category | Functions | Description |
|---|---|---|
| Leaderboard Management | 3 | Find, create, and get leaderboard info |
| Score Operations | 1 | Upload scores with optional details |
| Entry Download | 2 | Download leaderboard entries (global, friends, users) |
| UGC Integration | 1 | Attach user-generated content to entries |
Functions for finding, creating, and retrieving leaderboard information.
Find or create a leaderboard with specified settings.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_FindOrCreateLeaderboard()- Find or create leaderboard -
SteamAPI_ISteamUserStats_GetLeaderboardName()- Get leaderboard name -
SteamAPI_ISteamUserStats_GetLeaderboardEntryCount()- Get entry count -
SteamAPI_ISteamUserStats_GetLeaderboardSortMethod()- Get sort method -
SteamAPI_ISteamUserStats_GetLeaderboardDisplayType()- Get display type
Parameters:
-
name: string- Unique leaderboard name (must match Steamworks Partner configuration) -
sortMethod: LeaderboardSortMethod- How to sort scores-
LeaderboardSortMethod.Ascending- Lower scores are better (e.g., time trials, golf) -
LeaderboardSortMethod.Descending- Higher scores are better (e.g., high scores, points)
-
-
displayType: LeaderboardDisplayType- How to display scores-
LeaderboardDisplayType.Numeric- Display as numbers -
LeaderboardDisplayType.TimeSeconds- Display as time in seconds -
LeaderboardDisplayType.TimeMilliseconds- Display as time in milliseconds
-
Returns: Promise<LeaderboardInfo | null> - Leaderboard info object, or null if failed
Type:
interface LeaderboardInfo {
handle: bigint; // Internal leaderboard handle
name: string; // Leaderboard name
entryCount: number; // Total number of entries
sortMethod: LeaderboardSortMethod; // Sort direction
displayType: LeaderboardDisplayType; // Display format
}
enum LeaderboardSortMethod {
Ascending = 1, // Lower is better (time trials, golf)
Descending = 2 // Higher is better (high scores, points)
}
enum LeaderboardDisplayType {
Numeric = 1, // Regular number (e.g., 1000)
TimeSeconds = 2, // Time in seconds (e.g., 65.432)
TimeMilliseconds = 3 // Time in milliseconds (e.g., 65432)
}Example:
import SteamworksSDK, { LeaderboardSortMethod, LeaderboardDisplayType } from 'steamworks-ffi-node';
const steam = SteamworksSDK.getInstance();
steam.init({ appId: YOUR_APP_ID });
// High score leaderboard (higher is better)
const highScores = await steam.leaderboards.findOrCreateLeaderboard(
'HighScores',
LeaderboardSortMethod.Descending,
LeaderboardDisplayType.Numeric
);
if (highScores) {
console.log(`Leaderboard: ${highScores.name}`);
console.log(`Total entries: ${highScores.entryCount}`);
console.log(`Handle: ${highScores.handle}`);
}
// Speed run leaderboard (lower time is better)
const speedRun = await steam.leaderboards.findOrCreateLeaderboard(
'SpeedRun_Level1',
LeaderboardSortMethod.Ascending,
LeaderboardDisplayType.TimeMilliseconds
);
steam.shutdown();Notes:
- Creates the leaderboard if it doesn't exist
- Leaderboard settings are fixed once created
- Use consistent names across your game
- Waits up to 2 seconds for Steam server response
Find an existing leaderboard without creating it.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_FindLeaderboard()- Find existing leaderboard -
SteamAPI_ISteamUserStats_GetLeaderboardName()- Get leaderboard name -
SteamAPI_ISteamUserStats_GetLeaderboardEntryCount()- Get entry count -
SteamAPI_ISteamUserStats_GetLeaderboardSortMethod()- Get sort method -
SteamAPI_ISteamUserStats_GetLeaderboardDisplayType()- Get display type
Parameters:
-
name: string- Leaderboard name to find
Returns: Promise<LeaderboardInfo | null> - Leaderboard info if found, null otherwise
Example:
const leaderboard = await steam.leaderboards.findLeaderboard('HighScores');
if (leaderboard) {
console.log(`Found leaderboard with ${leaderboard.entryCount} entries`);
} else {
console.log('Leaderboard does not exist');
}Notes:
- Returns null if leaderboard doesn't exist
- Use this to check if a leaderboard exists before uploading
- Waits up to 2 seconds for Steam server response
Get detailed information about a leaderboard.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_GetLeaderboardName()- Get leaderboard name -
SteamAPI_ISteamUserStats_GetLeaderboardEntryCount()- Get entry count -
SteamAPI_ISteamUserStats_GetLeaderboardSortMethod()- Get sort method -
SteamAPI_ISteamUserStats_GetLeaderboardDisplayType()- Get display type
Parameters:
-
handle: bigint- Leaderboard handle fromfindLeaderboard()orfindOrCreateLeaderboard()
Returns: Promise<LeaderboardInfo | null> - Leaderboard info object, or null if invalid
Example:
const leaderboard = await steam.leaderboards.findLeaderboard('HighScores');
if (leaderboard) {
const info = await steam.leaderboards.getLeaderboardInfo(leaderboard.handle);
console.log(`${info.name}: ${info.entryCount} entries`);
console.log(`Sort: ${info.sortMethod === 1 ? 'Descending' : 'Ascending'}`);
}Functions for uploading and managing leaderboard scores.
Upload a score to a leaderboard with optional additional data.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_UploadLeaderboardScore()- Upload score to Steam
Parameters:
-
handle: bigint- Leaderboard handle -
score: number- The score value (integer) -
uploadMethod: LeaderboardUploadScoreMethod- How to handle the upload-
LeaderboardUploadScoreMethod.KeepBest- Only update if new score is better -
LeaderboardUploadScoreMethod.ForceUpdate- Always update regardless
-
-
scoreDetails?: number[]- Optional array of up to 64 int32 values for additional data
Returns: Promise<LeaderboardScoreUploadResult | null> - Upload result, or null if failed
Type:
interface LeaderboardScoreUploadResult {
success: boolean; // Whether upload succeeded
leaderboardHandle: bigint; // Handle to the leaderboard
score: number; // The score that was uploaded
scoreChanged: boolean; // Whether the score changed
globalRankNew: number; // New global rank (1 = best)
globalRankPrevious: number; // Previous global rank
}
enum LeaderboardUploadScoreMethod {
KeepBest = 1, // Only update if better
ForceUpdate = 2 // Always update
}Example:
import { LeaderboardUploadScoreMethod } from 'steamworks-ffi-node';
const leaderboard = await steam.leaderboards.findOrCreateLeaderboard(
'HighScores',
LeaderboardSortMethod.Descending,
LeaderboardDisplayType.Numeric
);
// Simple score upload (only if better)
const result = await steam.leaderboards.uploadLeaderboardScore(
leaderboard.handle,
1000,
LeaderboardUploadScoreMethod.KeepBest
);
if (result?.scoreChanged) {
console.log(`New rank: ${result.globalRankNew}`);
console.log(`Previous rank: ${result.globalRankPrevious}`);
}
// Upload with additional details (e.g., time, deaths, collectibles)
const detailedResult = await steam.leaderboards.uploadLeaderboardScore(
leaderboard.handle,
1000,
LeaderboardUploadScoreMethod.KeepBest,
[120, 5, 15] // time: 120s, deaths: 5, collectibles: 15
);
// Force update (for testing or when score might be worse)
await steam.leaderboards.uploadLeaderboardScore(
leaderboard.handle,
500,
LeaderboardUploadScoreMethod.ForceUpdate
);Notes:
-
KeepBestrespects the leaderboard's sort method (ascending/descending) - Details array can store up to 64 int32 values (e.g., sub-scores, metadata)
- Details are retrieved when downloading entries
- Waits up to 3 seconds for Steam server response
Functions for downloading and viewing leaderboard entries.
Download leaderboard entries based on various criteria.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_DownloadLeaderboardEntries()- Request entries from Steam
Parameters:
-
handle: bigint- Leaderboard handle -
dataRequest: LeaderboardDataRequest- Type of entries to download-
LeaderboardDataRequest.Global- Get global entries by rank -
LeaderboardDataRequest.GlobalAroundUser- Get entries around current user -
LeaderboardDataRequest.Friends- Get entries for friends only -
LeaderboardDataRequest.Users- Get entries for specific users (usedownloadLeaderboardEntriesForUsersinstead)
-
-
rangeStart: number- Starting index/offset (1-based for Global, offset for AroundUser) -
rangeEnd: number- Ending index/offset
Returns: Promise<LeaderboardEntry[]> - Array of leaderboard entries
Type:
interface LeaderboardEntry {
steamId: string; // Steam ID of the player
globalRank: number; // Global rank (1 = best)
score: number; // The score value
details: number[]; // Additional score details (up to 64 int32)
ugcHandle: bigint; // UGC content handle (0 if none)
}
enum LeaderboardDataRequest {
Global = 0, // Get top scores globally
GlobalAroundUser = 1, // Get scores around current user
Friends = 2, // Get friend scores only
Users = 3 // For specific users (internal use)
}Example:
import { LeaderboardDataRequest } from 'steamworks-ffi-node';
const leaderboard = await steam.leaderboards.findLeaderboard('HighScores');
// Get top 10 global scores
const top10 = await steam.leaderboards.downloadLeaderboardEntries(
leaderboard.handle,
LeaderboardDataRequest.Global,
1, // Start at rank 1 (1-indexed)
10 // End at rank 10
);
console.log('Top 10 Players:');
top10.forEach(entry => {
console.log(`${entry.globalRank}. ${entry.steamId}: ${entry.score}`);
if (entry.details.length > 0) {
console.log(` Details: ${entry.details.join(', ')}`);
}
});
// Get scores around current user (5 above, 5 below)
const aroundUser = await steam.leaderboards.downloadLeaderboardEntries(
leaderboard.handle,
LeaderboardDataRequest.GlobalAroundUser,
-5, // 5 entries above user
5 // 5 entries below user
);
console.log('Scores around you:');
aroundUser.forEach(entry => {
console.log(`Rank ${entry.globalRank}: ${entry.score}`);
});
// Get all friend scores
const friends = await steam.leaderboards.downloadLeaderboardEntries(
leaderboard.handle,
LeaderboardDataRequest.Friends,
0, // Ignored for Friends request
0 // Ignored for Friends request
);
console.log(`${friends.length} friends on leaderboard`);Notes:
- Global request: rangeStart and rangeEnd are 1-based ranks (1 = first place)
- GlobalAroundUser: negative values for entries above, positive for below
- Friends: rangeStart and rangeEnd are ignored
- Maximum 100 entries per request
- Waits up to 3 seconds for Steam server response
Download leaderboard entries for specific Steam users.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_DownloadLeaderboardEntriesForUsers()- Request specific user entries
Parameters:
-
handle: bigint- Leaderboard handle -
steamIds: string[]- Array of Steam ID strings (max 100)
Returns: Promise<LeaderboardEntry[]> - Array of leaderboard entries for specified users
Example:
// Get entries for specific players
const entries = await steam.leaderboards.downloadLeaderboardEntriesForUsers(
leaderboard.handle,
[
'76561198000000000',
'76561198000000001',
'76561198000000002'
]
);
console.log('Player Scores:');
entries.forEach(entry => {
console.log(`${entry.steamId}: ${entry.score} (Rank: ${entry.globalRank})`);
});
// Compare with a specific friend
const friendSteamId = '76561198000000000';
const friendEntries = await steam.leaderboards.downloadLeaderboardEntriesForUsers(
leaderboard.handle,
[friendSteamId]
);
if (friendEntries.length > 0) {
const friend = friendEntries[0];
console.log(`Friend rank: ${friend.globalRank}`);
console.log(`Friend score: ${friend.score}`);
}Notes:
- Maximum 100 Steam IDs per request
- Only returns entries for users who have scores
- Empty array if no users have submitted scores
- Waits up to 3 seconds for Steam server response
Functions for attaching user-generated content to leaderboard entries.
Attach user-generated content (like replays or screenshots) to the current user's leaderboard entry.
Steamworks SDK Functions:
-
SteamAPI_ISteamUserStats_AttachLeaderboardUGC()- Attach UGC to entry
Parameters:
-
handle: bigint- Leaderboard handle -
ugcHandle: bigint- Handle to shared UGC content (fromISteamRemoteStorage::FileShare())
Returns: Promise<boolean> - true if successfully attached
Example:
// Note: You need to share a file first using ISteamRemoteStorage
// This example assumes you have a UGC handle from FileShare()
const ugcHandle = BigInt('123456789'); // From ISteamRemoteStorage.FileShare()
const success = await steam.leaderboards.attachLeaderboardUGC(
leaderboard.handle,
ugcHandle
);
if (success) {
console.log('UGC attached to leaderboard entry');
console.log('Other players can now download your replay/screenshot');
}Notes:
- UGC must first be shared using
ISteamRemoteStorage::FileShare() - Only one UGC item per leaderboard entry
- Attaching new UGC replaces previous UGC
- Common uses: replays, screenshots, custom levels, ghost data
- UGC is attached to your current score entry
- Waits up to 3 seconds for Steam server response
Leaderboards must be configured in the Steamworks Partner portal before use.
Steps:
- Log in to Steamworks Partner
- Select your app
- Go to Stats & Achievements → Leaderboards
- Click Add New Leaderboard
- Configure:
-
Name: Exact string used in
findOrCreateLeaderboard()(e.g., "HighScores") - Community Name: Display name shown to players
- Sort Method: Ascending (lower is better) or Descending (higher is better)
- Display Type: Numeric, Time (Seconds), or Time (Milliseconds)
- Writes: Who can write (Trusted only, or Players)
- Reads: Who can read (Friends only, or Public)
-
Name: Exact string used in
- Save and publish changes
Important:
- Leaderboard names are case-sensitive
- Names must match exactly between code and Partner portal
- Settings cannot be changed after creation
- Test in Spacewar (AppID 480) before production
Complete type definitions for leaderboard functionality.
// Enums
enum LeaderboardSortMethod {
Ascending = 1, // Lower scores are better (time trials)
Descending = 2 // Higher scores are better (high scores)
}
enum LeaderboardDisplayType {
Numeric = 1, // Display as number (1000)
TimeSeconds = 2, // Display as seconds (65.432)
TimeMilliseconds = 3 // Display as milliseconds (65432)
}
enum LeaderboardDataRequest {
Global = 0, // Get global top scores
GlobalAroundUser = 1, // Get scores around current user
Friends = 2, // Get friend scores only
Users = 3 // For specific users (internal use)
}
enum LeaderboardUploadScoreMethod {
KeepBest = 1, // Only update if new score is better
ForceUpdate = 2 // Always update the score
}
// Interfaces
interface LeaderboardInfo {
handle: bigint; // Internal leaderboard handle
name: string; // Leaderboard name
entryCount: number; // Total number of entries
sortMethod: LeaderboardSortMethod; // Sort direction
displayType: LeaderboardDisplayType; // Display format
}
interface LeaderboardEntry {
steamId: string; // Steam ID of the player (64-bit as string)
globalRank: number; // Global rank (1 = best)
score: number; // The score value
details: number[]; // Additional score details (up to 64 int32)
ugcHandle: bigint; // UGC content handle (0 if none)
}
interface LeaderboardScoreUploadResult {
success: boolean; // Whether upload succeeded
leaderboardHandle: bigint; // Handle to the leaderboard
score: number; // The score that was uploaded
scoreChanged: boolean; // Whether the score changed
globalRankNew: number; // New global rank (1 = best)
globalRankPrevious: number; // Previous global rank (0 if first time)
}import Steam, {
LeaderboardSortMethod,
LeaderboardDisplayType,
LeaderboardUploadScoreMethod,
LeaderboardDataRequest
} from 'steamworks-ffi-node';
const steam = SteamworksSDK.getInstance();
async function highScoreExample() {
// Initialize Steam
if (!steam.init({ appId: YOUR_APP_ID })) {
console.error('Failed to initialize Steam');
return;
}
// Find or create high score leaderboard
const leaderboard = await steam.leaderboards.findOrCreateLeaderboard(
'HighScores',
LeaderboardSortMethod.Descending, // Higher is better
LeaderboardDisplayType.Numeric
);
if (!leaderboard) {
console.error('Failed to get leaderboard');
steam.shutdown();
return;
}
console.log(`Leaderboard: ${leaderboard.name}`);
console.log(`Total entries: ${leaderboard.entryCount}`);
// Upload player's score (only if it's better)
const playerScore = 1500;
const result = await steam.leaderboards.uploadLeaderboardScore(
leaderboard.handle,
playerScore,
LeaderboardUploadScoreMethod.KeepBest
);
if (result?.scoreChanged) {
console.log(`Score updated! New rank: ${result.globalRankNew}`);
if (result.globalRankPrevious > 0) {
console.log(`Previous rank: ${result.globalRankPrevious}`);
}
} else {
console.log('Score not updated (existing score is better)');
}
// Download top 10 scores
const topScores = await steam.leaderboards.downloadLeaderboardEntries(
leaderboard.handle,
LeaderboardDataRequest.Global,
1,
10
);
console.log('\nTop 10 High Scores:');
topScores.forEach((entry, index) => {
console.log(`${index + 1}. Rank ${entry.globalRank}: ${entry.score} points`);
});
// Download scores around current user
const nearby = await steam.leaderboards.downloadLeaderboardEntries(
leaderboard.handle,
LeaderboardDataRequest.GlobalAroundUser,
-3, // 3 above
3 // 3 below
);
console.log('\nScores around you:');
nearby.forEach(entry => {
console.log(`Rank ${entry.globalRank}: ${entry.score} points`);
});
steam.shutdown();
}
highScoreExample();import Steam, {
LeaderboardSortMethod,
LeaderboardDisplayType,
LeaderboardUploadScoreMethod,
LeaderboardDataRequest
} from 'steamworks-ffi-node';
const steam = SteamworksSDK.getInstance();
async function speedRunExample() {
steam.init({ appId: YOUR_APP_ID });
// Create speed run leaderboard (lower time is better)
const leaderboard = await steam.leaderboards.findOrCreateLeaderboard(
'Level1_SpeedRun',
LeaderboardSortMethod.Ascending, // Lower is better
LeaderboardDisplayType.TimeMilliseconds
);
if (!leaderboard) return;
// Complete level and record stats
const timeInMilliseconds = 65432; // 65.432 seconds
const deathCount = 3;
const checkpointsUsed = 2;
const secretsFound = 5;
// Upload time with detailed stats
const result = await steam.leaderboards.uploadLeaderboardScore(
leaderboard.handle,
timeInMilliseconds,
LeaderboardUploadScoreMethod.KeepBest,
[deathCount, checkpointsUsed, secretsFound] // Additional details
);
if (result?.scoreChanged) {
console.log(`New best time: ${timeInMilliseconds}ms`);
console.log(`World rank: ${result.globalRankNew}`);
}
// View top times with details
const topRuns = await steam.leaderboards.downloadLeaderboardEntries(
leaderboard.handle,
LeaderboardDataRequest.Global,
1,
10
);
console.log('\nTop 10 Speed Runs:');
topRuns.forEach(entry => {
const time = entry.score / 1000; // Convert to seconds
console.log(`Rank ${entry.globalRank}: ${time.toFixed(3)}s`);
if (entry.details.length >= 3) {
console.log(` Deaths: ${entry.details[0]}`);
console.log(` Checkpoints: ${entry.details[1]}`);
console.log(` Secrets: ${entry.details[2]}`);
}
});
steam.shutdown();
}
speedRunExample();import Steam, {
LeaderboardDataRequest,
LeaderboardSortMethod,
LeaderboardDisplayType
} from 'steamworks-ffi-node';
const steam = SteamworksSDK.getInstance();
async function friendComparisonExample() {
steam.init({ appId: YOUR_APP_ID });
const leaderboard = await steam.leaderboards.findOrCreateLeaderboard(
'HighScores',
LeaderboardSortMethod.Descending,
LeaderboardDisplayType.Numeric
);
if (!leaderboard) return;
// Get all friend scores
const friendScores = await steam.leaderboards.downloadLeaderboardEntries(
leaderboard.handle,
LeaderboardDataRequest.Friends,
0,
0 // Range is ignored for Friends request
);
console.log(`${friendScores.length} friends on leaderboard:`);
// Sort by rank
friendScores.sort((a, b) => a.globalRank - b.globalRank);
friendScores.forEach(entry => {
console.log(`Rank ${entry.globalRank}: ${entry.score} points`);
});
// Compare with specific friends
const specificFriends = [
'76561198000000000',
'76561198000000001'
];
const friendEntries = await steam.leaderboards.downloadLeaderboardEntriesForUsers(
leaderboard.handle,
specificFriends
);
console.log('\nSpecific friend comparison:');
friendEntries.forEach(entry => {
console.log(`${entry.steamId}: ${entry.score} (Rank ${entry.globalRank})`);
});
steam.shutdown();
}
friendComparisonExample();// ✅ Good: Descriptive, organized names
'HighScores'
'Level1_SpeedRun'
'Daily_Challenge_2024_10_11'
'Endless_Mode_HighScore'
// ❌ Bad: Generic or unclear names
'Leaderboard1'
'test'
'lb'// ✅ Good: Only update when score is better
await steam.leaderboards.uploadLeaderboardScore(
handle,
newScore,
LeaderboardUploadScoreMethod.KeepBest
);
// ⚠️ Use with caution: Force update (for testing only)
await steam.leaderboards.uploadLeaderboardScore(
handle,
testScore,
LeaderboardUploadScoreMethod.ForceUpdate
);// ✅ Good: Store meaningful metadata
const details = [
completionTime, // How long it took
enemiesKilled, // Combat stats
secretsFound, // Exploration stats
powerupsUsed, // Strategy stats
difficultyLevel // Game settings
];
await steam.leaderboards.uploadLeaderboardScore(handle, score, method, details);
// ❌ Bad: Random or meaningless data
const details = [1, 2, 3, 4]; // What do these mean?// ✅ Good: Check for null returns
const leaderboard = await steam.leaderboards.findLeaderboard('HighScores');
if (!leaderboard) {
console.error('Leaderboard not found');
return;
}
const result = await steam.leaderboards.uploadLeaderboardScore(/*...*/);
if (!result) {
console.error('Failed to upload score');
return;
}
// ✅ Good: Handle network issues gracefully
try {
const entries = await steam.leaderboards.downloadLeaderboardEntries(/*...*/);
if (entries.length === 0) {
console.log('No entries found or network error');
}
} catch (error) {
console.error('Leaderboard error:', error);
}// ✅ Good: Cache leaderboard handles
class LeaderboardCache {
private handles = new Map<string, bigint>();
async getHandle(name: string): Promise<bigint | null> {
if (this.handles.has(name)) {
return this.handles.get(name)!;
}
const leaderboard = await steam.leaderboards.findLeaderboard(name);
if (leaderboard) {
this.handles.set(name, leaderboard.handle);
return leaderboard.handle;
}
return null;
}
}Problem: findLeaderboard() returns null
Solutions:
- Check leaderboard name spelling (case-sensitive)
- Verify leaderboard is published in Steamworks Partner
- Use
findOrCreateLeaderboard()to create if missing - Check Steam is running and user is logged in
// Try to find, fallback to create
let leaderboard = await steam.leaderboards.findLeaderboard('HighScores');
if (!leaderboard) {
leaderboard = await steam.leaderboards.findOrCreateLeaderboard(
'HighScores',
LeaderboardSortMethod.Descending,
LeaderboardDisplayType.Numeric
);
}Problem: uploadLeaderboardScore() succeeds but score doesn't change
Solutions:
- Check if using
KeepBestwith worse score - Verify sort method matches your intent (ascending vs descending)
- Check
scoreChangedin result object
const result = await steam.leaderboards.uploadLeaderboardScore(
handle,
newScore,
LeaderboardUploadScoreMethod.KeepBest
);
if (result && !result.scoreChanged) {
console.log('Score not updated - existing score is better');
console.log(`Current best: ${result.score}`);
}Problem: downloadLeaderboardEntries() returns empty array
Solutions:
- No entries exist yet (upload a score first)
- Network error (check Steam connection)
- Invalid range for Global request
- No friends have scores (for Friends request)
const entries = await steam.leaderboards.downloadLeaderboardEntries(
handle,
LeaderboardDataRequest.Global,
0,
9
);
if (entries.length === 0) {
console.log('No entries found. Upload a score first!');
await steam.leaderboards.uploadLeaderboardScore(handle, 100, KeepBest);
}Problem: Operations take too long or fail
Solutions:
- Check internet connection
- Verify Steam client is running
- Wait for callbacks to process
- Don't call operations too frequently
// Good: Wait between operations
await steam.leaderboards.uploadLeaderboardScore(/*...*/);
await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1s
const entries = await steam.leaderboards.downloadLeaderboardEntries(/*...*/);Steam provides a test game (Spacewar) for development:
// Test leaderboards without a published game
const steam = SteamworksSDK.getInstance();
steam.init({ appId: 480 }); // Spacewar
const leaderboard = await steam.leaderboards.findOrCreateLeaderboard(
'Test_HighScores',
LeaderboardSortMethod.Descending,
LeaderboardDisplayType.Numeric
);
// Upload test scores
await steam.leaderboards.uploadLeaderboardScore(
leaderboard.handle,
1000,
LeaderboardUploadScoreMethod.ForceUpdate
);
// View results
const entries = await steam.leaderboards.downloadLeaderboardEntries(
leaderboard.handle,
LeaderboardDataRequest.Global,
0,
9
);
console.log('Test scores:', entries);
steam.shutdown();To clear test data, use ForceUpdate with 0:
// Clear your score (development only)
await steam.leaderboards.uploadLeaderboardScore(
leaderboard.handle,
0,
LeaderboardUploadScoreMethod.ForceUpdate
);- Steamworks Leaderboards Documentation
- Leaderboard Web API
- Stats & Achievements
- User-Generated Content
Questions or Issues? Visit the GitHub Issues page.