EOS Leaderboard

Example Project

A complete step-by-step walkthrough — from EOS initialization to displaying a leaderboard and updating scores in your game.
EOS LEADERBOARD (EXAMPLE PROJECT)

The example project includes a Markdown file that shows the steps required to use it. Follow along with the instructions below to build a simple EOS Leaderboard integration in your Unreal Engine game.


What We'll Build

A minimal but complete EOS Leaderboard integration that:

  1. Initializes EOS on game start
  2. Logs the player in silently (persistent token) or via browser (fallback)
  3. Fetches the list of available leaderboards from the Dev Portal
  4. Queries the Top 10 entries and displays them in a UI widget
  5. Submits the player's score at the end of a match
  6. Re-queries the leaderboard to reflect the updated rank

Step 1 — Initialize EOS in GameInstance

Create (or open) your GameInstance Blueprint.

In Event Init:

Event Init
  └─► Initialize EOS
        ├─► [true]  ──► Print "EOS Ready"
        └─► [false] ──► Print "EOS Init Failed — check DefaultEngine.ini"

Why GameInstance?UEOSCoreLeaderboardSubsystem is a GameInstanceSubsystem — it lives as long as the GameInstance. Initializing here ensures EOS is ready before any level loads.


Step 2 — Log In the Player

After EOS is initialized, you need two login steps:

  1. Auth Login → Epic Account identity
  2. Connect Login → Game identity (ProductUserId) — auto-triggered by leaderboard nodes if skipped

Create a function BP_LoginPlayer in your GameInstance:

BP_LoginPlayer
  │
  └─► EOS Auth Login (Epic Account)
        PrimaryLoginType = AccountPortal
        Policy           = PersistentThenPortal
        bDeletePersistentBeforeFallback = true
        │
        ├─► OnSuccess
        │     └─► EOS Connect Login (ProductUserId)
        │           │
        │           ├─► OnSuccess
        │           │     └─► Print "Logged in as: " + Result.ProductUserId
        │           │         ──► Call BP_LoadLeaderboards
        │           │
        │           └─► OnFailure
        │                 └─► Print "Connect Login failed: " + Result.ErrorMessage
        │
        └─► OnFailure
              └─► Print "Auth Login failed: " + Result.ErrorMessage
On first launch, Auth Login opens the Epic browser portal. On subsequent launches, the PersistentAuth token is reused silently — no browser appears unless the token expires.

Step 3 — Discover Available Leaderboards

Use EOS Get Leaderboard List to fetch all leaderboards configured in your Dev Portal. This is useful when you want to display multiple boards or build a dynamic leaderboard selector.

Create a function BP_LoadLeaderboards:

BP_LoadLeaderboards
  │
  └─► EOS Get Leaderboard List
        │
        ├─► OnSuccess
        │     └─► Result  ──► [Store in variable: AvailableLeaderboards]
        │         For Each Entry:
        │           Print Entry.LeaderboardId + " → " + Entry.StatName
        │         ──► Call BP_QueryTopLeaderboard with first entry
        │
        └─► OnFailure
              └─► Print "Get Leaderboard List failed: " + ErrorMessage

If you only have one known leaderboard, you can skip this step and hardcode the LeaderboardId string directly in the next step.


Step 4 — Query the Top 10

Use EOS Query Leaderboard Range to fetch only the entries you need.

Create a function BP_QueryTopLeaderboard(LeaderboardId: FString):

BP_QueryTopLeaderboard
  │
  └─► EOS Query Leaderboard Range
        LeaderboardId = [LeaderboardId input]
        RankFrom      = 1
        RankTo        = 10
        │
        ├─► OnSuccess
        │     └─► Result  ──► [Store in variable: TopEntries]
        │         ──► Call BP_PopulateLeaderboardUI
        │
        └─► OnFailure
              └─► Print "Query failed: " + ErrorMessage
RankTo = 0 means no upper limit — use it to fetch every player from RankFrom to the end of the board. For displaying a "near me" section, query with RankFrom = PlayerRank - 2, RankTo = PlayerRank + 2.

Step 5 — Display the Leaderboard in a Widget

Create a Widget Blueprint WBP_Leaderboard.

Add a VerticalBox named EntriesContainer.

Create a child widget WBP_LeaderboardEntry with:

  • TextBlock for rank (e.g. #1)
  • TextBlock for display name
  • TextBlock for score

In WBP_Leaderboard, create a function PopulateList(Entries: TArray<FEOSLeaderboardEntry>):

PopulateList
  └─► Clear Children (EntriesContainer)
      └─► For Each Entry in Entries
            └─► Create Widget WBP_LeaderboardEntry
                  Set RankText  = "#" + Entry.Rank
                  Set NameText  = (Entry.UserDisplayName.IsEmpty)
                                    ? "Unknown"
                                    : Entry.UserDisplayName
                  Set ScoreText = Entry.Score
                  Add to EntriesContainer

Highlight the local player's row:

Compare Entry.UserId with Get Local Product User Id from the subsystem to identify which row belongs to the local player, then apply a different background or text color.

For Each Entry:
  └─► Is Entry.UserId == GetEOSSubsystem.GetLocalProductUserId?
        ├─► true  ──► Set row background to highlight color
        └─► false ──► Set row background to default color

Step 6 — Submit a Score

Call EOS Ingest Stat at the end of a match (or on any score event) to update the player's leaderboard position.

[Game Event: Match ended — final score = 1500]
  │
  └─► EOS Ingest Stat (Leaderboard)
        StatName = "score"
        Amount   = 1500
        │
        ├─► OnSuccess
        │     └─► Print "Score submitted!"
        │         ──► Call BP_QueryTopLeaderboard  [refresh the UI]
        │
        └─► OnFailure
              └─► Print "Ingest failed: " + ErrorMessage

EOS processes the stat asynchronously on its servers. The new rank appears after a short delay. Calling BP_QueryTopLeaderboard right after OnSuccess will show the updated leaderboard once EOS has applied it.

Aggregation reminder: if your stat uses MAX aggregation, only the call with Amount > current best will change the rank. Calls with lower values are silently ignored by EOS — they still fire OnSuccess.

Complete Flow Summary

GameInstance::Init
  └─► Initialize EOS ──► BP_LoginPlayer
                              │
                   Auth Login (PersistentThenPortal)
                              │ OnSuccess
                   Connect Login
                              │ OnSuccess
                   BP_LoadLeaderboards
                              │
                   EOS Get Leaderboard List
                              │ OnSuccess
                   BP_QueryTopLeaderboard (Top 10)
                              │ OnSuccess
                   WBP_Leaderboard::PopulateList
                              │
                   [Match ends]
                              │
                   EOS Ingest Stat ("score", finalScore)
                              │ OnSuccess
                   BP_QueryTopLeaderboard  ──► Refresh UI

Tips

Re-query after ingest Always call BP_QueryTopLeaderboard after EOS Ingest Stat OnSuccess to keep the UI in sync. EOS may need a moment to process the new rank — a 1–2 second delay before querying can help on slow connections.

Display name missingUserDisplayName can be empty if EOS does not return it for a given player. Always fall back to a placeholder like "Player" or the truncated UserId.

Score formattingScore is an int64. Use ToString in Blueprint and add any visual formatting (commas, units) in your widget logic.

Leaderboard not updating If a submitted score does not appear, check:

  • The stat name matches exactly (case-sensitive) what is configured in the Dev Portal
  • The aggregation method (MAX, SUM, etc.) is consistent with your expectations
  • The player's Product User ID is valid (check Is Player Logged In)

Multiple leaderboards Store the full AvailableLeaderboards array in your GameInstance. Display a tab or dropdown to let players switch between boards, and call BP_QueryTopLeaderboard with the selected LeaderboardId each time.

Offline / no connection If EOS returns EOS_NoConnection on any node, show a friendly message and allow the player to retry. Do not block gameplay — scores can be submitted when the connection is restored.


Troubleshooting

SymptomLikely cause
InitializeEOS returns falseInvalid credentials in DefaultEngine.ini
Auth Login browser does not openAccountPortal requires a valid ClientId and ClientSecret
EOS Get Leaderboard List returns empty arrayNo leaderboards configured in Dev Portal for this Sandbox/Deployment
EOS Query Leaderboard returns empty ResultNo entries yet — submit at least one stat ingest first
EOS Ingest Stat fails with EOS_NotFoundStatName does not match the Dev Portal exactly (case-sensitive)
Score submitted but rank unchangedAggregation is MAX and the new score is lower than the current best
UserDisplayName is always emptyNormal — EOS does not always return display names in leaderboard records
Connect Login fires automatically in nodesExpected behavior — the nodes handle it for you