Achievements
Create, track, and unlock achievements to reward player accomplishments
Achievements reward players for completing tasks or reaching milestones. In EOS, achievements are tied to stats and can auto-unlock when stat thresholds are met.
Achievements require setup in the EOS Developer Portal. Create achievements and link them to stats before using the API.
Portal Setup
- Go to the EOS Developer Portal
- Navigate to Game Services → Achievements
- Click + New Achievement
- Select the Stat Name and Stat Value threshold for auto-unlock
- Fill in achievement details (name, description, icons)
Achievements auto-unlock when the linked stat reaches the threshold. You can also manually unlock achievements using the API.
Query Achievement Definitions
Fetch all achievement metadata (names, descriptions, icons) from the server. Call this once at startup.

Returns an array of achievement definitions with:
- Achievement ID
- Display names (locked/unlocked variants)
- Descriptions (locked/unlocked variants)
- Icon URLs
- Hidden status
#include "EIKCore/Public/Interfaces/IEIKAchievements.h"
void UMyClass::QueryAchievementDefinitions()
{
TSharedPtr<IEIKAchievements> Achievements = GetAchievementsInterface();
if (!Achievements.IsValid()) return;
Achievements->QueryAchievementDefinitions(0,
FEIKAsyncCallback<FEIKQueryAchievementDefinitionsResult>::CreateLambda(
[this](const TEIKAsyncResult<FEIKQueryAchievementDefinitionsResult>& Result)
{
if (Result.IsSuccessful())
{
for (const FEIKAchievementDefinition& Def : Result.GetValue().Definitions)
{
UE_LOG(LogTemp, Log, TEXT("Achievement: %s - %s"),
*Def.AchievementId,
*Def.UnlockedDisplayName.ToString());
}
}
}));
}#include "Online/OnlineServices.h"
#include "Online/Achievements.h"
using namespace UE::Online;
void UMyClass::QueryAchievementDefinitions()
{
IOnlineServicesPtr Services = GetServices(EOnlineServices::Epic);
IAchievementsPtr Achievements = Services->GetAchievementsInterface();
FQueryAchievementDefinitions::Params Params;
Params.LocalAccountId = GetLocalAccountId();
Achievements->QueryAchievementDefinitions(MoveTemp(Params))
.OnComplete([this](const TOnlineResult<FQueryAchievementDefinitions>& Result)
{
if (Result.IsOk())
{
UE_LOG(LogTemp, Log, TEXT("Achievement definitions loaded"));
}
});
}#include "OnlineSubsystem.h"
#include "Interfaces/OnlineAchievementsInterface.h"
void UMyClass::QueryAchievementDefinitions()
{
IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(FName(TEXT("EIK")));
IOnlineAchievementsPtr Achievements = OnlineSub->GetAchievementsInterface();
IOnlineIdentityPtr Identity = OnlineSub->GetIdentityInterface();
FUniqueNetIdPtr UserId = Identity->GetUniquePlayerId(0);
if (!UserId.IsValid()) return;
Achievements->QueryAchievementDescriptions(*UserId,
FOnQueryAchievementsCompleteDelegate::CreateLambda(
[this](const FUniqueNetId& PlayerId, bool bWasSuccessful)
{
if (bWasSuccessful)
{
UE_LOG(LogTemp, Log, TEXT("Achievement definitions loaded"));
}
}));
}Query Achievement States
Fetch the player's achievement progress and unlock status.

Returns an array of achievement states with:
- Achievement ID
- Progress (0.0 to 1.0)
- Unlock time (if unlocked)
void UMyClass::QueryAchievementStates()
{
TSharedPtr<IEIKAchievements> Achievements = GetAchievementsInterface();
Achievements->QueryAchievementStates(0,
FEIKAsyncCallback<FEIKQueryAchievementStatesResult>::CreateLambda(
[this](const TEIKAsyncResult<FEIKQueryAchievementStatesResult>& Result)
{
if (Result.IsSuccessful())
{
for (const FEIKAchievementState& State : Result.GetValue().States)
{
UE_LOG(LogTemp, Log, TEXT("%s: %.0f%% %s"),
*State.AchievementId,
State.Progress * 100.f,
State.IsUnlocked() ? TEXT("(Unlocked)") : TEXT(""));
}
}
}));
}void UMyClass::QueryAchievementStates()
{
IAchievementsPtr Achievements = GetAchievementsInterface();
FQueryAchievementStates::Params Params;
Params.LocalAccountId = GetLocalAccountId();
Achievements->QueryAchievementStates(MoveTemp(Params))
.OnComplete([this](const TOnlineResult<FQueryAchievementStates>& Result)
{
if (Result.IsOk())
{
UE_LOG(LogTemp, Log, TEXT("Achievement states loaded"));
}
});
}void UMyClass::QueryAchievementStates()
{
IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(FName(TEXT("EIK")));
IOnlineAchievementsPtr Achievements = OnlineSub->GetAchievementsInterface();
FUniqueNetIdPtr UserId = OnlineSub->GetIdentityInterface()->GetUniquePlayerId(0);
Achievements->QueryAchievements(*UserId,
FOnQueryAchievementsCompleteDelegate::CreateLambda(
[this, Achievements, UserId](const FUniqueNetId& PlayerId, bool bWasSuccessful)
{
if (bWasSuccessful)
{
TArray<FOnlineAchievement> PlayerAchievements;
Achievements->GetCachedAchievements(*UserId, PlayerAchievements);
for (const FOnlineAchievement& Achievement : PlayerAchievements)
{
UE_LOG(LogTemp, Log, TEXT("%s: %.0f%%"),
*Achievement.Id, Achievement.Progress);
}
}
}));
}Unlock Achievements
Manually unlock achievements. Useful for achievements not tied to stats.

Pass an array of achievement IDs to unlock. The overlay will display for each unlocked achievement.
void UMyClass::UnlockAchievement(const FString& AchievementId)
{
TSharedPtr<IEIKAchievements> Achievements = GetAchievementsInterface();
FEIKUnlockAchievementsParams Params;
Params.AchievementIds.Add(AchievementId);
Achievements->UnlockAchievements(0, Params,
FEIKAsyncCallbackVoid::CreateLambda(
[AchievementId](const TEIKAsyncResult<void>& Result)
{
if (Result.IsSuccessful())
{
UE_LOG(LogTemp, Log, TEXT("Achievement unlocked: %s"), *AchievementId);
}
}));
}void UMyClass::UnlockAchievement(const FString& AchievementId)
{
IAchievementsPtr Achievements = GetAchievementsInterface();
FUnlockAchievements::Params Params;
Params.LocalAccountId = GetLocalAccountId();
Params.AchievementIds.Add(AchievementId);
Achievements->UnlockAchievements(MoveTemp(Params))
.OnComplete([](const TOnlineResult<FUnlockAchievements>& Result) {});
}void UMyClass::UnlockAchievement(const FString& AchievementId)
{
IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(FName(TEXT("EIK")));
IOnlineAchievementsPtr Achievements = OnlineSub->GetAchievementsInterface();
FUniqueNetIdPtr UserId = OnlineSub->GetIdentityInterface()->GetUniquePlayerId(0);
FOnlineAchievementsWriteRef WriteObject = MakeShared<FOnlineAchievementsWrite>();
WriteObject->SetFloatStat(FName(*AchievementId), 100.0);
Achievements->WriteAchievements(*UserId, WriteObject,
FOnAchievementsWrittenDelegate::CreateLambda(
[](const FUniqueNetId& PlayerId, bool bWasSuccessful)
{
if (bWasSuccessful)
{
UE_LOG(LogTemp, Log, TEXT("Achievement unlocked"));
}
}));
}Achievement Events
Listen for achievement unlock notifications.
Bind to events from EIK Achievements Subsystem or use the async node callbacks.
| Event | When Fired |
|---|---|
| On Achievement Unlocked | Achievement was unlocked (overlay appears) |
| On Achievement State Updated | Achievement progress changed |
void UMyClass::SetupAchievementEvents()
{
TSharedPtr<IEIKAchievements> Achievements = GetAchievementsInterface();
if (!Achievements.IsValid()) return;
Achievements->OnAchievementUnlocked().AddUObject(this, &UMyClass::HandleAchievementUnlocked);
Achievements->OnAchievementStateUpdated().AddUObject(this, &UMyClass::HandleAchievementUpdated);
}
void UMyClass::HandleAchievementUnlocked(const FEIKAccountId& AccountId, const FString& AchievementId)
{
UE_LOG(LogTemp, Log, TEXT("Achievement unlocked: %s"), *AchievementId);
}
void UMyClass::HandleAchievementUpdated(const FEIKAccountId& AccountId, const FString& AchievementId)
{
// Re-query to get updated progress
}Helper Functions
The Achievements Library provides cached access after querying:
| Function | Returns | Description |
|---|---|---|
GetAchievementIds() | TArray<FString> | All achievement IDs |
GetAchievementDefinition(Id) | FEIKAchievementDefinition | Get definition by ID |
GetAchievementState(Id) | FEIKAchievementState | Get player progress |
IsAchievementUnlocked(Id) | bool | Check if unlocked |
GetAchievementProgress(Id) | float | Get progress (0.0-1.0) |
GetAchievementUnlockTime(Id) | FDateTime | When unlocked |
GetAchievementDisplayName(Def, bUnlocked) | FText | Get appropriate name |
GetAchievementDescription(Def, bUnlocked) | FText | Get appropriate description |
GetAchievementIconUrl(Def, bUnlocked) | FString | Get appropriate icon URL |
GetUnlockedAchievementCount(States) | int32 | Count unlocked in array |
Common Patterns
Display Achievement List
void UMyClass::DisplayAchievements()
{
TSharedPtr<IEIKAchievements> Achievements = GetAchievementsInterface();
TArray<FString> Ids = Achievements->GetAchievementIds(0);
for (const FString& Id : Ids)
{
bool bDefFound, bStateFound;
FEIKAchievementDefinition Def = Achievements->GetAchievementDefinition(0, Id, bDefFound);
FEIKAchievementState State = Achievements->GetAchievementState(0, Id, bStateFound);
if (bDefFound && bStateFound)
{
bool bUnlocked = State.IsUnlocked();
FText Name = bUnlocked ? Def.UnlockedDisplayName : Def.LockedDisplayName;
FText Desc = bUnlocked ? Def.UnlockedDescription : Def.LockedDescription;
FString Icon = bUnlocked ? Def.UnlockedIconUrl : Def.LockedIconUrl;
// Add to UI list
AddAchievementToUI(Name, Desc, Icon, State.Progress, bUnlocked);
}
}
}Track Progress
Achievements linked to stats update automatically. For manual tracking:
void UMyClass::OnEnemyKilled()
{
EnemiesKilled++;
// Update stat (achievement auto-unlocks at threshold)
Stats->IngestStat(0, FName("EnemiesKilled"), EnemiesKilled);
// Or manually unlock at milestone
if (EnemiesKilled == 100)
{
UnlockAchievement(TEXT("KILL_100_ENEMIES"));
}
}