EOS Stats

Example Project

A complete step-by-step walkthrough — from EOS initialization to displaying a live stat sheet and ingesting stats in your game.
EOS STATS (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:

  1. Initializes EOS on game start
  2. Logs the player in silently (persistent token) or via browser (fallback)
  3. Declares a stat schema (kills, deaths, revives) with default values
  4. Displays a live stat sheet in the UI, including stats never ingested yet
  5. Ingests a stat when a game event fires
  6. 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:

  1. Auth Login → Epic Account identity
  2. 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.

On first launch, Auth Login will open the Epic browser portal. On subsequent launches, the persistent token is reused silently — the player won't see the browser again unless the token expires. For in-editor testing without the browser, use EOS Login With Dev Auth Async instead.

Step 3 — Declare Your Stat Schema

Before writing any Blueprint logic, declare your stats in Edit → Project Settings → Plugins → EOS Stats:

StatNameDisplayNameDefaultValue
killsKills0
deathsDeaths0
revivesRevives0

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

SymptomLikely cause
Initialize EOS returns falseInvalid credentials in DefaultEngine.ini
Auth Login browser does not openAccountPortal requires a valid ClientId and ClientSecret
Connect Login fails with EOS_InvalidUserThis is handled automatically — should not reach OnFailure
Query Stats returns an empty Stats arrayNormal 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 ingestStatName doesn't match the Dev Portal exactly (case-sensitive), or the stat isn't declared in Project Settings
Ingest returns EOS_NotFoundStatName does not exist in the Dev Portal for this Sandbox/Deployment