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 Stats integration in your Unreal Engine game.
What We'll Build
A minimal but complete EOS Stats integration that:
- Initializes EOS on game start
- Logs the player in silently (persistent token) or via browser (fallback)
- Declares a stat schema (
kills,deaths,revives) with default values - Displays a live stat sheet in the UI, including stats never ingested yet
- Ingests a stat when a game event fires
- Refreshes the stat sheet after ingest
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?UEOSCoreStatsSubsystem and UEOSStatsSubsystem are both GameInstanceSubsystems — they live 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:
- Auth Login → Epic Account identity
- Connect Login → Game identity (ProductUserId)
Create a function BP_LoginPlayer in your GameInstance:
BP_LoginPlayer
│
└─► EOS Auth Login (Epic Account)
PrimaryLoginType = AccountPortal
Policy = PersistentThenPortal
bDeletePersistentAuthBeforeFallback = true
│
├─► OnSuccess
│ └─► EOS Connect Login (ProductUserId)
│ │
│ ├─► OnSuccess
│ │ └─► Print "Logged in as: " + Result.ProductUserId
│ │ [Continue to Step 3]
│ │
│ └─► OnFailure
│ └─► Print "Connect Login failed: " + Result.ErrorMessage
│
└─► OnFailure
└─► Print "Auth Login failed: " + Result.ErrorMessage
Call BP_LoginPlayer right after Initialize EOS returns true.
Step 3 — Declare Your Stat Schema
Before writing any Blueprint logic, declare your stats in Edit → Project Settings → Plugins → EOS Stats:
| StatName | DisplayName | DefaultValue |
|---|---|---|
kills | Kills | 0 |
deaths | Deaths | 0 |
revives | Revives | 0 |
Make sure each StatName also exists in Dev Portal → [Your Sandbox] → Stats with the appropriate Aggregation Type (Sum for all three, in this example).
Step 4 — Load and Display the Stat Sheet
Once Connect Login succeeds, load the schema and query real values:
BP_LoadStatSheet
│
└─► EOS Query Stat Definitions
└─► EOS Query Stats (StatNames = empty → query everything the player already has)
│
├─► OnSuccess
│ └─► EOS Get All Stats (With Defaults) ──► [Store in variable: StatSheet]
│ ──► Call BP_PopulateStatSheet (see below)
│
└─► OnFailure
└─► Print "Query failed: " + Result.ErrorMessage
Create a Widget Blueprint WBP_StatSheet with a VerticalBox named StatsContainer, and a child widget WBP_StatEntry with two TextBlocks (label + value).
BP_PopulateStatSheet(StatSheet: TArray<FEOSStatInfo>)
└─► Clear Children (StatsContainer)
└─► For Each Stat in StatSheet
└─► Find matching FEOSStatDefinition (by StatName) for the DisplayName
└─► Create Widget WBP_StatEntry
Set Label = Definition.DisplayName
Set Value = Stat.Value
Add to StatsContainer
Because you used Get All Stats (With Defaults), kills/deaths/revives all show up immediately with 0, even for a brand-new player who has never had a value ingested.
Step 5 — Ingest a Stat on a Game Event
Ingest a stat when your game logic demands it — for example, on a player kill.
[Game Event: Player Killed Enemy]
│
└─► EOS Ingest Stat
StatName = "kills"
IngestAmount = 1
│
├─► OnSuccess
│ └─► Print "Kill ingested"
│ ──► Call BP_LoadStatSheet (Step 4) to refresh the UI
│
└─► OnFailure
└─► Print "Ingest failed: " + Result.ErrorMessage
EOS Ingest Stat does not auto-refresh the cache. Re-run Query Stats (Step 4) afterward if you want the UI to reflect the new value immediately.Complete Flow Summary
GameInstance::Init
└─► Initialize EOS ──► BP_LoginPlayer
│
Auth Login (PersistentThenPortal)
│ OnSuccess
Connect Login
│ OnSuccess
BP_LoadStatSheet
│
Query Stat Definitions → Query Stats → Get All Stats (With Defaults)
│
WBP_StatSheet::PopulateStatSheet
[Later — game event]
└─► EOS Ingest Stat ──► OnSuccess ──► BP_LoadStatSheet (refresh)
Tips
Show defaults, not blanks
Always use Get All Stats (With Defaults) for the initial display of a stat sheet — Get All Cached Stats alone will simply omit any stat the player hasn't triggered yet, which usually looks like a bug to players.
Batch UI refreshes If several stats change in quick succession (e.g. a match-end summary), ingest them all first, then call Query Stats once at the end rather than after every single ingest.
Aggregation matters
Pick the right Aggregation Type per stat in the Dev Portal. Sum for counters, Max/Min for personal bests, Latest for values like currency where only the newest number matters.
Offline / no connection
If EOS returns EOS_NoConnection on any node, show a friendly message and let gameplay continue — stats can sync later. Don't block core gameplay on a stat ingest succeeding.
Troubleshooting
| Symptom | Likely cause |
|---|---|
Initialize EOS returns false | Invalid credentials in DefaultEngine.ini |
| Auth Login browser does not open | AccountPortal requires a valid ClientId and ClientSecret |
Connect Login fails with EOS_InvalidUser | This is handled automatically — should not reach OnFailure |
Query Stats returns an empty Stats array | Normal for a new player — none of their stats have a value yet. Use Get All Stats (With Defaults) instead |
| A stat never appears even after ingest | StatName doesn't match the Dev Portal exactly (case-sensitive), or the stat isn't declared in Project Settings |
Ingest returns EOS_NotFound | StatName does not exist in the Dev Portal for this Sandbox/Deployment |
Functions
Complete reference for every Blueprint node and utility function provided by EOS Stats.
Introduction
EOS Leaderboard is a Blueprint-first plugin for Unreal Engine 5.4+ that integrates Epic Online Services Leaderboards into your game — stat ingestion, rank queries, range filtering, and automatic player identity management included.