EOS Achievements

Example Project

A complete step-by-step walkthrough — from EOS initialization to displaying achievements and unlocking them in your game.
EOS ACHIEVEMENTS (EXAMPLE PROJECT)

What We'll Build

A minimal but complete EOS Achievements integration that:

  1. Initializes EOS on game start
  2. Logs the player in silently (persistent token) or via browser (fallback)
  3. Queries all achievements with player progress
  4. Displays a simple achievement list in the UI
  5. Unlocks an achievement when a game event fires
  6. 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:

  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
        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.

On first launch, Auth Login will open the Epic browser portal. On subsequent launches, the PersistentAuth token is reused silently — the player won't see the browser again unless the token expires.

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)
  • TextBlock for name
  • TextBlock for description
  • ProgressBar for 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 is null on 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

SymptomLikely cause
InitializeEOS 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 returns empty Achievements arrayNo achievements configured in Dev Portal for this Sandbox/Deployment
Unlock returns EOS_NotFoundAchievementId does not match the Dev Portal exactly (case-sensitive)
Icons are always nullNetwork access to Epic's CDN may be blocked — check firewall / proxy
Listener never fires OnUnlockedEnsure Connect Login has completed before starting the listener