Full guide to submitting scores and querying EOS leaderboards with the Supabase UE5 Plugin. Covers the USupabaseEOSLeaderboards static API, the UAsyncEOSQueryLeaderboard Blueprint latent node, and step-by-step setup for C++ and Blueprint workflows.
EOS Leaderboards lets you submit player scores and retrieve ranked entries from leaderboards defined in the Epic Developer Portal. The plugin provides two approaches:
| Approach | Class | Complexity | Best For |
|---|---|---|---|
| Async Blueprint Node | UAsyncEOSQueryLeaderboard |
Low | Blueprint-driven workflows. Latent node for querying leaderboards. |
| Static API | USupabaseEOSLeaderboards |
Low | Both C++ and Blueprint. Stateless static methods for score submission and leaderboard queries. |
All methods on USupabaseEOSLeaderboards are static and require a World Context object. No initialization or lifecycle management is needed -- call the functions directly.
Status: This feature is in Preview/Alpha. The API surface is stable, but async callback forwarding via
ClientDatais planned for a future update. Recommended for testing and prototyping in production projects.
+----------------+ +----------------+ +-------------------+
| SubmitScore() | ----> | EOS Leaderboard| ----> | OnSuccess fires |
| (static call) | | API call | | (FSimpleDelegate)|
+----------------+ +----------------+ +-------------------+
|
v
+----------------+ +----------------+ +-------------------+
| Score recorded | <---- | EOS validates | <---- | OnFailure fires |
| on server | | and stores | | (Error delegate) |
+----------------+ +----------------+ +-------------------+
--- Query flow: ---
+----------------+ +----------------+ +-------------------+
| QueryLeader- | ----> | EOS Leaderboard| ----> | OnSuccess fires |
| board() | | API call | | (LeaderboardQuery|
| (static call) | | | | Delegate) |
+----------------+ +----------------+ +-------------------+
|
v
+----------------+ +----------------+ +-------------------+
| TArray<FEOS- | <---- | EOS returns | <---- | OnFailure fires |
| Leaderboard- | | ranked entries | | (Error delegate) |
| Record> | | | | |
+----------------+ +----------------+ +-------------------+
| Step | Action | Description |
|---|---|---|
| 1 | Configure leaderboards in Epic Developer Portal | Define leaderboard IDs (e.g., global_highscores) with aggregation rules and stat names. |
| 2 | SubmitScore() |
Submit a score for the local player. Fires OnSuccess when accepted or OnFailure on error. |
| 3 | QueryLeaderboard() |
Fetch ranked entries with pagination control. Returns TArray<FEOSLeaderboardRecord> via OnSuccess. |
| 4 | Process results | Iterate over FEOSLeaderboardRecord entries to display rank, player name, score, and timestamp. |
Before using EOS leaderboards, ensure you have the following:
| Requirement | Details |
|---|---|
| EOS SDK | The EOS SDK must be installed and configured. See the EOS Overview for setup instructions. |
| Leaderboard Definitions | Leaderboards must be configured in the Epic Developer Portal under your product's Leaderboards section. |
| Leaderboard IDs | String identifiers assigned in the portal (e.g., global_highscores, weekly_scores). These are passed to SubmitScore() and QueryLeaderboard(). |
| Authenticated Player | The local player must be authenticated with EOS Connect before submitting or querying scores. |
| Supabase UE5 Plugin | v2.0.0 or later with SupabaseEOS module included. |
SubmitScore() and QueryLeaderboard()For Blueprint workflows that need to query leaderboards, use the UAsyncEOSQueryLeaderboard latent node.
Selfglobal_highscores)EEOSLeaderboardQueryStart enum (FromTop, FromBottom, FromPlayer, FromNone)TArray<FEOSLeaderboardRecord>FSupabaseErrorSelf #include "Async/AsyncEOSQueryLeaderboard.h"
// Query the top 10 players on a leaderboard
UAsyncEOSQueryLeaderboard* QueryTask = UAsyncEOSQueryLeaderboard::QueryLeaderboard(
this,
TEXT("global_highscores"),
EEOSLeaderboardQueryStart::FromTop,
10
);
QueryTask->OnSuccess.AddLambda(
[](const TArray<FEOSLeaderboardRecord>& Records)
{
for (const FEOSLeaderboardRecord& Record : Records)
{
UE_LOG(LogTemp, Log, TEXT("#%d: %s - Score: %d"),
Record.Rank, *Record.PlayerName, Record.Score);
}
});
QueryTask->OnFailure.AddLambda(
[](const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Leaderboard query failed: %s"), *ErrorMessage);
});
USupabaseEOSLeaderboards exposes static methods for submitting scores and querying leaderboards. No instantiation or lifecycle management is required.
Submit a score for the currently authenticated local player:
#include "SupabaseEOSLeaderboards.h"
USupabaseEOSLeaderboards::SubmitScore(
GetWorld(), // World Context
TEXT("global_highscores"), // Leaderboard ID
12500, // Score to submit
FSimpleDelegate::CreateLambda([]()
{
UE_LOG(LogTemp, Log, TEXT("Score submitted successfully!"));
}),
FSupabaseErrorDelegate::CreateLambda([](const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Score submission failed: %s"), *ErrorMessage);
})
);
Fetch ranked entries from a leaderboard with pagination control:
USupabaseEOSLeaderboards::QueryLeaderboard(
GetWorld(), // World Context
TEXT("global_highscores"), // Leaderboard ID
EEOSLeaderboardQueryStart::FromTop, // Start from the best scores
25, // Max entries (1-100)
FSupabaseLeaderboardQueryDelegate::CreateLambda(
[](const TArray<FEOSLeaderboardRecord>& Records)
{
UE_LOG(LogTemp, Log, TEXT("Received %d entries"), Records.Num());
for (const FEOSLeaderboardRecord& Record : Records)
{
UE_LOG(LogTemp, Log, TEXT(" #%d %s Score: %d User: %s"),
Record.Rank,
*Record.PlayerName,
Record.Score,
*Record.UserId);
}
}),
FSupabaseErrorDelegate::CreateLambda([](const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Leaderboard query failed: %s"), *ErrorMessage);
})
);
Static utility class for EOS leaderboard operations. All methods are static and require a World Context object.
| Function | Signature | Description |
|---|---|---|
SubmitScore |
static void SubmitScore(UObject* WorldContext, const FString& LeaderboardId, int32 Score, FSimpleDelegate OnSuccess, FSupabaseErrorDelegate OnFailure) |
Submit a score to an EOS leaderboard for the local player. OnSuccess fires when the score is accepted. OnFailure fires with an error message on failure. |
QueryLeaderboard |
static void QueryLeaderboard(UObject* WorldContext, const FString& LeaderboardId, EEOSLeaderboardQueryStart StartPosition, int32 MaxEntries, FSupabaseLeaderboardQueryDelegate OnSuccess, FSupabaseErrorDelegate OnFailure) |
Query a leaderboard and return ranked entries. MaxEntries must be between 1 and 100. StartPosition controls the offset/range. Results are delivered via OnSuccess as TArray<FEOSLeaderboardRecord>. |
| Parameter | Type | Description |
|---|---|---|
WorldContext |
UObject* |
Any valid world context object (e.g., this, GetWorld(), Self in Blueprint). Required for all static methods. |
LeaderboardId |
const FString& |
The leaderboard identifier as configured in the Epic Developer Portal (e.g., global_highscores). |
Score |
int32 |
The score value to submit for the local player. Interpretation depends on the leaderboard's aggregation method. |
StartPosition |
EEOSLeaderboardQueryStart |
Controls where the query window begins. See EEOSLeaderboardQueryStart. |
MaxEntries |
int32 |
Number of entries to return. Must be between 1 and 100. |
OnSuccess |
FSimpleDelegate / FSupabaseLeaderboardQueryDelegate |
Callback on success. For SubmitScore, this is a FSimpleDelegate (no parameters). For QueryLeaderboard, this receives TArray<FEOSLeaderboardRecord>. |
OnFailure |
FSupabaseErrorDelegate |
Callback on failure. Receives an FString error message. |
| Delegate | Signature | Description |
|---|---|---|
FSimpleDelegate |
DECLARE_DELEGATE(FSimpleDelegate) |
Fired on successful score submission. No parameters. |
FSupabaseLeaderboardQueryDelegate |
DECLARE_DYNAMIC_DELEGATE_OneParam(FSupabaseLeaderboardQueryDelegate, const TArray<FEOSLeaderboardRecord>&, Records) |
Fired on successful leaderboard query with the returned records. |
FSupabaseErrorDelegate |
DECLARE_DYNAMIC_DELEGATE_OneParam(FSupabaseErrorDelegate, const FString&, ErrorMessage) |
Fired on failure with a human-readable error message. |
Enum controlling where the leaderboard query window begins. Passed to QueryLeaderboard() as the StartPosition parameter.
| Value | Description |
|---|---|
FromTop |
Start from the best scores (highest ranked). Returns entries starting from rank 1. |
FromBottom |
Start from the worst scores (lowest ranked). Returns entries starting from the bottom of the leaderboard. |
FromPlayer |
Center results around the local player's rank. The player's entry will appear near the middle of the returned set. Useful for "your ranking" displays. |
FromNone |
Return all entries (no offset). EOS applies no positional filter; use when you want the full range of entries (still bounded by MaxEntries). |
A struct representing a single entry in a leaderboard query result. Received via FSupabaseLeaderboardQueryDelegate.
| Property | Type | Description |
|---|---|---|
PlayerName |
FString |
The display name of the player who achieved this score. |
UserId |
FString |
The EOS Product User ID of the player. |
Score |
int32 |
The player's score on this leaderboard. |
Rank |
int32 |
The player's rank position on the leaderboard (1-based). |
RecordedAt |
int64 |
UNIX timestamp (seconds) indicating when this score was recorded. |
Note:
RecordedAtis a raw UNIX timestamp in seconds. To convert it to anFDateTime, useFDateTime::FromUnixTimestamp(Record.RecordedAt).
A Blueprint-compatible latent action node for querying leaderboards asynchronously. Defined in Async/AsyncEOSQueryLeaderboard.h.
| Method | Signature | Description |
|---|---|---|
QueryLeaderboard |
static UAsyncEOSQueryLeaderboard* QueryLeaderboard(UObject* WorldContextObject, const FString& LeaderboardId, EEOSLeaderboardQueryStart StartPosition, int32 MaxEntries) |
Starts an async leaderboard query. Returns the latent action object for delegate binding. |
| Delegate | Signature | Description |
|---|---|---|
OnSuccess |
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(OnSuccess, const TArray<FEOSLeaderboardRecord>&, Records) |
Fired when the query completes successfully. Contains the full set of requested leaderboard records. |
OnFailure |
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(OnFailure, const FString&, ErrorMessage) |
Fired when the query fails. Contains a human-readable error message. |
Supabase > EOS > Leaderboards
This example demonstrates submitting a score when a match ends:
#include "SupabaseEOSLeaderboards.h"
void AMyGameMode::OnMatchEnd(int32 FinalScore)
{
#if WITH_EOS_SDK && SUPABASE_EOS_INTEGRATION
const FString LeaderboardId = TEXT("global_highscores");
USupabaseEOSLeaderboards::SubmitScore(
GetWorld(),
LeaderboardId,
FinalScore,
FSimpleDelegate::CreateUObject(this, &AMyGameMode::OnScoreSubmitted),
FSupabaseErrorDelegate::CreateUObject(this, &AMyGameMode::OnScoreSubmitFailed)
);
UE_LOG(LogTemp, Log, TEXT("Submitting score %d to leaderboard '%s'..."),
FinalScore, *LeaderboardId);
#else
UE_LOG(LogTemp, Warning, TEXT("EOS leaderboards not available in this build."));
#endif
}
void AMyGameMode::OnScoreSubmitted()
{
UE_LOG(LogTemp, Log, TEXT("Score submitted successfully!"));
// Show a notification to the player
if (UGameplayStatics::GetPlayerController(this, 0))
{
// Display "Score submitted!" in your UI
ShowScoreSubmittedNotification();
}
}
void AMyGameMode::OnScoreSubmitFailed(const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Score submission failed: %s"), *ErrorMessage);
// Optionally retry or queue the score for later submission
QueueScoreForRetry(TEXT("global_highscores"), CachedFinalScore);
}
This example queries the top 10 entries on a global leaderboard:
#include "SupabaseEOSLeaderboards.h"
void AMyLeaderboardWidget::RequestTopPlayers()
{
#if WITH_EOS_SDK && SUPABASE_EOS_INTEGRATION
USupabaseEOSLeaderboards::QueryLeaderboard(
GetWorld(),
TEXT("global_highscores"),
EEOSLeaderboardQueryStart::FromTop,
10,
FSupabaseLeaderboardQueryDelegate::CreateUObject(
this, &AMyLeaderboardWidget::OnLeaderboardReceived),
FSupabaseErrorDelegate::CreateUObject(
this, &AMyLeaderboardWidget::OnLeaderboardQueryFailed)
);
#else
UE_LOG(LogTemp, Warning, TEXT("EOS leaderboards not available."));
#endif
}
void AMyLeaderboardWidget::OnLeaderboardReceived(const TArray<FEOSLeaderboardRecord>& Records)
{
UE_LOG(LogTemp, Log, TEXT("Leaderboard query returned %d entries"), Records.Num());
// Clear previous entries
LeaderboardEntries.Empty();
for (const FEOSLeaderboardRecord& Record : Records)
{
UE_LOG(LogTemp, Log, TEXT(" #%d %s Score: %d"),
Record.Rank, *Record.PlayerName, Record.Score);
// Convert UNIX timestamp to readable date
FDateTime RecordedTime = FDateTime::FromUnixTimestamp(Record.RecordedAt);
UE_LOG(LogTemp, Log, TEXT(" Recorded: %s"),
*RecordedTime.ToString());
// Add to your UI data model
LeaderboardEntries.Add(Record);
}
// Refresh the leaderboard display
RefreshLeaderboardUI();
}
void AMyLeaderboardWidget::OnLeaderboardQueryFailed(const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Leaderboard query failed: %s"), *ErrorMessage);
ShowErrorToast(FString::Printf(TEXT("Failed to load leaderboard: %s"), *ErrorMessage));
}
This example uses FromPlayer to fetch entries centered around the local player's rank, useful for a "Your Ranking" display:
#include "SupabaseEOSLeaderboards.h"
void AMyPlayerController::ShowMyRanking()
{
#if WITH_EOS_SDK && SUPABASE_EOS_INTEGRATION
// Query 11 entries centered around the local player
// (5 above, the player, 5 below)
USupabaseEOSLeaderboards::QueryLeaderboard(
GetWorld(),
TEXT("global_highscores"),
EEOSLeaderboardQueryStart::FromPlayer,
11,
FSupabaseLeaderboardQueryDelegate::CreateUObject(
this, &AMyPlayerController::OnMyRankingReceived),
FSupabaseErrorDelegate::CreateUObject(
this, &AMyPlayerController::OnRankingQueryFailed)
);
#else
UE_LOG(LogTemp, Warning, TEXT("EOS leaderboards not available."));
#endif
}
void AMyPlayerController::OnMyRankingReceived(const TArray<FEOSLeaderboardRecord>& Records)
{
for (const FEOSLeaderboardRecord& Record : Records)
{
// Highlight the local player's entry
bool bIsLocalPlayer = (Record.UserId == LocalPlayerUserId);
if (bIsLocalPlayer)
{
UE_LOG(LogTemp, Log, TEXT(">>> #%d YOU Score: %d <<<"),
Record.Rank, Record.Score);
}
else
{
UE_LOG(LogTemp, Log, TEXT(" #%d %s Score: %d"),
Record.Rank, *Record.PlayerName, Record.Score);
}
}
// Update the ranking UI widget
UpdateRankingWidget(Records);
}
void AMyPlayerController::OnRankingQueryFailed(const FString& ErrorMessage)
{
UE_LOG(LogTemp, Error, TEXT("Ranking query failed: %s"), *ErrorMessage);
}
Follow the EOS Overview setup guide to enable EOS in your project. Ensure:
bEnableEOSIntegration = true in your Build.csSupabaseEOS module is listed in dependenciesOnlineSubsystemEOS is enabled in your .uprojectbEnableLeaderboards = true in your DefaultEngine.ini Supabase EOS settingsSelfErrorMessage string and display it to the player or log it