Example Project
What We'll Build
A minimal but complete EOS Achievements integration that:
- Initializes EOS on game start
- Logs the player in silently (persistent token) or via browser (fallback)
- Queries all achievements with player progress
- Displays a simple achievement list in the UI
- Unlocks an achievement when a game event fires
- Shows a real-time unlock popup via the listener
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?UEOSCoreSubsystem 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:
- 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
bDeletePersistentBeforeFallback = true
│
├─► OnSuccess
│ └─► EOS Connect Login (ProductUserId)
│ │
│ ├─► OnSuccess
│ │ └─► Print "Logged in as: " + Result.ProductUserId
│ │ [Optionally: open main menu level]
│ │
│ └─► 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 — Query Achievements
Once the player is logged in (Connect Login successful), query all achievements.
Create a function BP_QueryAchievements and call it after Connect Login OnSuccess:
BP_QueryAchievements
│
└─► EOS Query Achievements
│
├─► OnSuccess
│ └─► Result.Achievements ──► [Store in variable: AllAchievements]
│ ──► Call BP_PopulateAchievementsList (see Step 4)
│
└─► OnFailure
└─► Print "Query failed: " + Result.ErrorMessage
Store the returned TArray<FEOSAchievementInfo> in a variable (e.g., AllAchievements) on your GameInstance or a dedicated UI widget.
Step 4 — Display Achievements in a Widget
Create a Widget Blueprint WBP_AchievementsList.
Add a WrapBox or VerticalBox named AchievementsContainer.
Create a child widget WBP_AchievementEntry with:
Image(icon)TextBlockfor nameTextBlockfor descriptionProgressBarfor progress- A visual difference between locked (greyed out) and unlocked states
In WBP_AchievementsList, create a function PopulateList(Achievements: TArray<FEOSAchievementInfo>):
PopulateList
└─► Clear Children (AchievementsContainer)
└─► For Each Achievement in Achievements
└─► Create Widget WBP_AchievementEntry
└─► Set AchievementId = Achievement.AchievementId
Set NameText = (bUnlocked) ? Achievement.UnlockedDisplayName
: Achievement.LockedDisplayName
Set DescText = (bUnlocked) ? Achievement.UnlockedDescription
: Achievement.LockedDescription
Set ProgressBar % = Achievement.Progress
Set Icon Texture = (bUnlocked) ? Achievement.AchievementUnlockedIcon
: Achievement.AchievementLockedIcon
Add to AchievementsContainer
Icon textures (
UTexture2D*) are downloaded asynchronously. If a texture isnullon first display, bind to a timer or re-query after a moment to refresh the list.
Step 5 — Unlock an Achievement
Unlock an achievement when your game logic demands it — for example, on first kill, level complete, or any custom event.
[Game Event: Player wins first match]
│
└─► Find Achievement in AllAchievements where AchievementId == "ACH_FIRST_WIN"
└─► EOS Unlock Achievement
Achievement = [found achievement]
IngestAmount = 1
│
├─► OnSuccess
│ └─► Print "Achievement unlocked!"
│ (UI update handled by the Listener — see Step 6)
│
└─► OnFailure
└─► Print "Unlock failed: " + Result.ErrorMessage
If the achievement uses a linked stat (
bRequiresStat = true), you do not need to do anything differently — the node ingests the stat automatically. EOS unlocks the achievement on its servers when the stat threshold is reached.
Step 6 — Real-Time Unlock Listener
Set up a persistent listener so your UI gets notified instantly when an achievement is unlocked (including server-side stat-triggered unlocks).
In your main HUD or GameInstance, create a variable AchievementsListener of type UEOSAsyncStartAchievementsUnlockedListener.
On login success (after Connect Login):
[After Connect Login OnSuccess]
│
└─► EOS Start Achievements Unlocked Listener
├─► OnStarted
│ bSuccess = true ──► Set AchievementsListener = [node reference]
│ bSuccess = false ──► Print "Listener failed to start"
│
└─► OnUnlocked
└─► AchievementsInfo ──► Call BP_ShowUnlockPopup
Create BP_ShowUnlockPopup(Info: FEOSAchievementInfo):
BP_ShowUnlockPopup
└─► Create Widget WBP_UnlockToast
Set Name = Info.UnlockedDisplayName
Set Icon = Info.AchievementUnlockedIcon
Add to Viewport
Play animation (fade in / slide / fade out after 3s)
Stop the listener on logout or game end:
[On Logout or Game End]
└─► EOS Stop Achievements Unlocked Listener
Target = AchievementsListener
Complete Flow Summary
GameInstance::Init
└─► Initialize EOS ──► BP_LoginPlayer
│
Auth Login (PersistentThenPortal)
│ OnSuccess
Connect Login
│ OnSuccess
┌──────────┴─────────────┐
BP_QueryAchievements Start Listener
│ │
Store AllAchievements OnUnlocked ──► Show Toast
│
WBP_AchievementsList::PopulateList
Tips
Re-query after unlock
After EOS Unlock Achievement OnSuccess, call BP_QueryAchievements again to refresh AllAchievements and update your UI list. The listener handles the popup independently.
Hidden achievements
Check bIsHidden before displaying achievement names and descriptions. For hidden achievements, show a placeholder (e.g., "???" and "Keep playing to unlock.") until bUnlocked = true.
Progress achievements
Use Progress (0.0 → 1.0) to fill a ProgressBar widget. Note that Progress = 1.0 does not guarantee bUnlocked = true — the server confirmation can have a brief delay.
Stat-linked achievements
If bRequiresStat = true, you can display LinkedStatName and StatThreshold to the player as an objective (e.g., "Win 10 matches — 3/10"). Combine with Progress for the fill amount.
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 — achievements can sync later when the connection is restored.
Troubleshooting
| Symptom | Likely cause |
|---|---|
InitializeEOS 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 returns empty Achievements array | No achievements configured in Dev Portal for this Sandbox/Deployment |
Unlock returns EOS_NotFound | AchievementId does not match the Dev Portal exactly (case-sensitive) |
Icons are always null | Network access to Epic's CDN may be blocked — check firewall / proxy |
Listener never fires OnUnlocked | Ensure Connect Login has completed before starting the listener |