# Leaderboards

**URL:** https://heroiclabs.com/docs/hiro/unreal/leaderboards/
**Keywords:** leaderboards, hiro
**Categories:** hiro, unreal, leaderboards

---


# Leaderboards

Read more about the Leaderboards system in Hiro [here](../../concepts/leaderboards/).

## Get all leaderboards

Get the leaderboards defined for the game.

```cpp
FHiroOnLeaderboardsConfigGet OnLeaderboardsConfigGet;
OnLeaderboardsConfigGet.AddDynamic(this, &AMyActor::OnLeaderboardsConfigGet);
FOnError OnError;

HiroClient->LeaderboardsConfigGet(Session, OnLeaderboardsConfigGet, OnError);

void AMyActor::OnLeaderboardsConfigGet(const FHiroLeaderboardConfigList& LeaderboardConfigList)
{
    UE_LOG(LogTemp, Log, TEXT("%s"), *LeaderboardConfigList.ToJson());
}
```

## Online Subsystem

Hiro backs Unreal Engine's standard [IOnlineLeaderboards](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Plugins/OnlineSubsystem/Interfaces/IOnlineLeaderboards) interface, so you can read and write Hiro leaderboard scores using the same code patterns you'd use with any other Online Subsystem provider. Scores are stored in Nakama and inherit all of Hiro's leaderboard features — regional scoring, friend queries, and configurable operators — without any additional setup.

This interface is separate from the Hiro client API documented above. For setup instructions, see [Online Subsystem](../getting-started/online-subsystem/).

Retrieve the interface from the subsystem after initialization:

```cpp
IOnlineLeaderboardsPtr LeaderboardsInterface = OnlineSubsystem->GetLeaderboardsInterface();
```

For setup instructions, see [Online Subsystem](../getting-started/online-subsystem/).

### Writing scores

Writing a score is a two-step operation: stage the record with `WriteLeaderboards`, then commit it to the server with `FlushLeaderboards`. Only `"score"` and `"subscore"` are valid property names.

```cpp
FOnlineLeaderboardWrite WriteObject = FOnlineLeaderboardWrite();
WriteObject.UpdateMethod = ELeaderboardUpdateMethod::Force;
WriteObject.SortMethod = ELeaderboardSort::None;
WriteObject.LeaderboardNames = { TEXT("my-leaderboard") };
WriteObject.Properties.Emplace(TEXT("score"), 100);
WriteObject.Properties.Emplace(TEXT("subscore"), 10);

LeaderboardsInterface->WriteLeaderboards(TEXT(""), *LocalUserId, WriteObject);

FDelegateHandle FlushHandle = LeaderboardsInterface->AddOnLeaderboardFlushCompleteDelegate_Handle(
    FOnLeaderboardFlushCompleteDelegate::CreateLambda([](const FName& Name, bool bWasSuccessful)
    {
        if (bWasSuccessful)
        {
            // Score submitted.
        }
    })
);
LeaderboardsInterface->FlushLeaderboards(TEXT(""));
```

Calling `WriteLeaderboards` while a flush is already in progress may cause the new value to be lost if a record for the same player and leaderboard is currently being submitted.

#### Score merging behavior

`UpdateMethod` and `SortMethod` on `FOnlineLeaderboardWrite` control how a new staged value merges with an existing cached value for the same player and leaderboard:

| Setting | Behavior |
|---|---|
| `ELeaderboardUpdateMethod::Force` or `ELeaderboardSort::None` | Always overwrites the cached value |
| `ELeaderboardSort::Ascending` | Keeps the cached value if it's lower than the new score |
| `ELeaderboardSort::Descending` | Keeps the cached value if it's higher than the new score |

### Reading scores for specific players

`ReadLeaderboards` fetches records for the given player IDs and populates the `FOnlineLeaderboardRead` object asynchronously. All player IDs must be Hiro IDs (`FUniqueNetIdHiro`).

```cpp
FOnlineLeaderboardReadPtr LeaderboardRead = MakeShared<FOnlineLeaderboardRead>();
LeaderboardRead->LeaderboardName = TEXT("my-leaderboard");
FOnlineLeaderboardReadRef LeaderboardReadRef = LeaderboardRead.ToSharedRef();

FDelegateHandle ReadHandle = LeaderboardsInterface->AddOnLeaderboardReadCompleteDelegate_Handle(
    FOnLeaderboardReadCompleteDelegate::CreateLambda([LeaderboardReadRef](bool bWasSuccessful)
    {
        if (bWasSuccessful)
        {
            for (const FOnlineStatsRow& Row : LeaderboardReadRef->Rows)
            {
                // Row.PlayerId, Row.Rank, Row.Columns
            }
        }
    })
);
LeaderboardsInterface->ReadLeaderboards({ LocalUserId.ToSharedRef() }, LeaderboardReadRef);
```

Each row in `Rows` contains three columns:

- `"score"` — the player's primary score (`Int32`)
- `"subscore"` — the player's secondary score (`Int32`)
- `"num_score"` — the number of times the player has submitted a score (`Int32`)

### Reading scores around a player

`ReadLeaderboardsAroundUser` returns scores for the players ranked closest to the given player. The `Range` parameter controls the window size: the interface requests `2 × Range + 1` records centered on the player.

```cpp
FOnlineLeaderboardReadPtr LeaderboardRead = MakeShared<FOnlineLeaderboardRead>();
LeaderboardRead->LeaderboardName = TEXT("my-leaderboard");
FOnlineLeaderboardReadRef LeaderboardReadRef = LeaderboardRead.ToSharedRef();

FDelegateHandle ReadHandle = LeaderboardsInterface->AddOnLeaderboardReadCompleteDelegate_Handle(
    FOnLeaderboardReadCompleteDelegate::CreateLambda([LeaderboardReadRef](bool bWasSuccessful)
    {
        if (bWasSuccessful)
        {
            // LeaderboardReadRef->Rows contains players around the target.
        }
    })
);

uint32 Range = 5; // Returns up to 11 rows (5 above, player, 5 below).
LeaderboardsInterface->ReadLeaderboardsAroundUser(LocalUserId.ToSharedRef(), Range, LeaderboardReadRef);
```

### Reading a friends' leaderboard

`ReadLeaderboardsForFriends` fetches leaderboard scores for all friends of the specified local player. It automatically paginates through the friends list (up to 1,000 per page) before issuing the leaderboard read.

`LocalUserNum` is the local player index used to look up the player's session and friends list.

```cpp
FOnlineLeaderboardReadPtr LeaderboardRead = MakeShared<FOnlineLeaderboardRead>();
LeaderboardRead->LeaderboardName = TEXT("my-leaderboard");
FOnlineLeaderboardReadRef LeaderboardReadRef = LeaderboardRead.ToSharedRef();

FDelegateHandle ReadHandle = LeaderboardsInterface->AddOnLeaderboardReadCompleteDelegate_Handle(
    FOnLeaderboardReadCompleteDelegate::CreateLambda([LeaderboardReadRef](bool bWasSuccessful)
    {
        if (bWasSuccessful)
        {
            // LeaderboardReadRef->Rows contains the friends' scores.
        }
    })
);

int32 LocalUserNum = 0;
LeaderboardsInterface->ReadLeaderboardsForFriends(LocalUserNum, LeaderboardReadRef);
```

### Unsupported operations

`ReadLeaderboardsAroundRank` is not supported. It always returns `false` and fires `OnLeaderboardReadComplete` with a failure state.