What you get
| Limit | Value |
|---|---|
| Leaderboards per game | Up to 10,000 |
| Entries per player | One per leaderboard |
| Players per leaderboard | Unlimited |
| Score | One 32-bit integer, plus up to 64 extra integers of your own data (not sorted by Steam) |
| Update speed | Rankings are readable immediately after a score is uploaded |
1. Create the leaderboard
In App Admin, go to Stats & Achievements → Leaderboards. (You can also create them from code with FindOrCreateLeaderboard, but defining them in Steamworks keeps settings in one place.)
| Field | What to set |
|---|---|
| Name | The internal name your code looks up, e.g. fastest_run. |
| Community Name | The public name. Leave it empty and the board won't appear on your community hub. |
| Sort Method | Descending for high scores, Ascending for times and positions. |
| Display Type | Numeric, Seconds or Milliseconds. Only affects how the hub formats the score. |
| Writes | Trusted means only your server can submit scores through the Web API. See below. |
| Reads | Friends limits the game to reading friends' scores. |
2. Upload a score
Look up the board once, keep the handle, then upload. This example uses Steamworks.NET in Unity; the C++ API has the same calls on ISteamUserStats.
using Steamworks;
using UnityEngine;
public class Leaderboard : MonoBehaviour
{
SteamLeaderboard_t board;
CallResult<LeaderboardFindResult_t> onFind;
CallResult<LeaderboardScoreUploaded_t> onUpload;
void Start()
{
onFind = CallResult<LeaderboardFindResult_t>.Create(OnFound);
onUpload = CallResult<LeaderboardScoreUploaded_t>.Create(OnUploaded);
onFind.Set(SteamUserStats.FindLeaderboard("fastest_run"));
}
void OnFound(LeaderboardFindResult_t r, bool ioFailure)
{
if (!ioFailure && r.m_bLeaderboardFound != 0) board = r.m_hSteamLeaderboard;
}
public void Submit(int score)
{
var call = SteamUserStats.UploadLeaderboardScore(board,
ELeaderboardUploadScoreMethod.k_ELeaderboardUploadScoreMethodKeepBest,
score, null, 0);
onUpload.Set(call);
}
void OnUploaded(LeaderboardScoreUploaded_t r, bool ioFailure)
{
if (!ioFailure && r.m_bSuccess != 0)
Debug.Log("New global rank: " + r.m_nGlobalRankNew);
}
}
| Upload method | Use it when |
|---|---|
KeepBest | Personal bests. Steam keeps the better of old and new scores. |
ForceUpdate | The latest result should always replace the old one, e.g. a current-season rating. |
3. Show the rankings
Call DownloadLeaderboardEntries with the handle, a request type and a range, then read each entry with GetDownloadedLeaderboardEntry. Read everything you need straight away, because the downloaded data is freed once you've gone through the entries.
| Request type | Shows |
|---|---|
Global | A range of ranks, e.g. 1–10 |
GlobalAroundUser | Entries around the player's own rank, e.g. 5 above and 5 below |
Friends | Only the player's friends |
Each entry gives you the player's Steam ID, global rank and score. Use SteamFriends.GetFriendPersonaName for display names.
4. Attach replays or ghosts (optional)
After uploading a score, call AttachLeaderboardUGC with a file shared through Steam Cloud, such as a replay or a ghost to race against. Other players can download it with the entry, and it stays available even if the original cloud file is later changed or deleted. See the Cloud guide for the storage side.
Cheating and trusted writes
By default the game client submits scores, so anyone who edits memory or intercepts the call can post whatever they like. For casual or friends-only boards that's usually acceptable. For anything competitive or prize-bearing:
Clients can no longer submit scores at all.
Your server validates the run, then posts the score with the SetLeaderboardScore Web API using your publisher key. The key never goes in the game.