Statistics
Track and query player statistics for analytics and progression systems
Statistics track player progress like kills, deaths, playtime, and scores. Stats can trigger achievements when thresholds are met.
Stat names must be UPPERCASE with no spaces or special characters. Example: ENEMIES_KILLED, TOTAL_PLAYTIME
Portal Setup
- Go to the EOS Developer Portal
- Navigate to Game Services → Stats
- Click + New Stat
- Provide Stat Name and choose Aggregation Type:
| Type | Behavior |
|---|---|
| Sum | Adds ingested values together |
| Latest | Keeps the most recent value |
| Max | Keeps the highest value |
| Min | Keeps the lowest value |
Use Sum for cumulative stats (total kills, total playtime). Use Max for high scores or best times.
Update Stats
Ingest stat values to update player statistics.

Copy and paste into Unreal Engine Blueprint editor
Pass an array of stat names and values to ingest. Values are processed according to the aggregation type configured in the portal.
#include "EIKCore/Public/Interfaces/IEIKStats.h"
void UMyClass::UpdateStats()
{
TSharedPtr<IEIKStats> Stats = GetStatsInterface();
if (!Stats.IsValid()) return;
FEIKUpdateStatsParams Params;
Params.Stats.Add(FEIKStatIngest{TEXT("ENEMIES_KILLED"), 1});
Params.Stats.Add(FEIKStatIngest{TEXT("TOTAL_SCORE"), 500});
Stats->UpdateStats(0, Params,
FEIKAsyncCallbackVoid::CreateLambda(
[](const TEIKAsyncResult<void>& Result)
{
if (Result.IsSuccessful())
{
UE_LOG(LogTemp, Log, TEXT("Stats updated"));
}
}));
}#include "Online/OnlineServices.h"
#include "Online/Stats.h"
using namespace UE::Online;
void UMyClass::UpdateStats()
{
IOnlineServicesPtr Services = GetServices(EOnlineServices::Epic);
IStatsPtr Stats = Services->GetStatsInterface();
FUpdateStats::Params Params;
Params.LocalAccountId = GetLocalAccountId();
Params.UpdatedStats.Add(FUserStats{
GetLocalAccountId(),
{{FString(TEXT("ENEMIES_KILLED")), FStatValue(1)},
{FString(TEXT("TOTAL_SCORE")), FStatValue(500)}}
});
Stats->UpdateStats(MoveTemp(Params))
.OnComplete([](const TOnlineResult<FUpdateStats>& Result)
{
if (Result.IsOk())
{
UE_LOG(LogTemp, Log, TEXT("Stats updated"));
}
});
}#include "OnlineSubsystem.h"
#include "Interfaces/OnlineStatsInterface.h"
void UMyClass::UpdateStats()
{
IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(FName(TEXT("EIK")));
IOnlineStatsPtr Stats = OnlineSub->GetStatsInterface();
FUniqueNetIdPtr UserId = OnlineSub->GetIdentityInterface()->GetUniquePlayerId(0);
FOnlineStatsUserUpdatedStats UpdatedStats;
UpdatedStats.AccountId = UserId;
UpdatedStats.Stats.Add(TEXT("ENEMIES_KILLED"), FOnlineStatValue(1));
UpdatedStats.Stats.Add(TEXT("TOTAL_SCORE"), FOnlineStatValue(500));
Stats->UpdateStats(*UserId, {UpdatedStats},
FOnlineStatsUpdateStatsComplete::CreateLambda(
[](const FOnlineError& Error)
{
if (Error.WasSuccessful())
{
UE_LOG(LogTemp, Log, TEXT("Stats updated"));
}
}));
}Query Stats
Fetch player statistics from the server.

Copy and paste into Unreal Engine Blueprint editor
- Stat Names: Array of stat names to query (empty = all stats)
- Target Account Id: User to query (leave empty for local player)
void UMyClass::QueryStats()
{
TSharedPtr<IEIKStats> Stats = GetStatsInterface();
FEIKQueryStatsParams Params;
Params.StatNames.Add(TEXT("ENEMIES_KILLED"));
Params.StatNames.Add(TEXT("TOTAL_SCORE"));
// Leave TargetAccountId invalid to query local player
Stats->QueryStats(0, Params,
FEIKAsyncCallback<FEIKQueryStatsResult>::CreateLambda(
[](const TEIKAsyncResult<FEIKQueryStatsResult>& Result)
{
if (Result.IsSuccessful())
{
const FEIKUserStats& UserStats = Result.GetValue().UserStats;
for (const auto& Pair : UserStats.Stats)
{
UE_LOG(LogTemp, Log, TEXT("%s: %d"), *Pair.Key, Pair.Value);
}
}
}));
}void UMyClass::QueryStats()
{
IStatsPtr Stats = GetStatsInterface();
FQueryStats::Params Params;
Params.LocalAccountId = GetLocalAccountId();
Params.TargetAccountId = GetLocalAccountId();
Params.StatNames.Add(TEXT("ENEMIES_KILLED"));
Params.StatNames.Add(TEXT("TOTAL_SCORE"));
Stats->QueryStats(MoveTemp(Params))
.OnComplete([](const TOnlineResult<FQueryStats>& Result)
{
if (Result.IsOk())
{
for (const auto& Stat : Result.GetOkValue().Stats)
{
UE_LOG(LogTemp, Log, TEXT("%s: %s"), *Stat.Key, *Stat.Value.ToString());
}
}
});
}void UMyClass::QueryStats()
{
IOnlineSubsystem* OnlineSub = IOnlineSubsystem::Get(FName(TEXT("EIK")));
IOnlineStatsPtr Stats = OnlineSub->GetStatsInterface();
FUniqueNetIdPtr UserId = OnlineSub->GetIdentityInterface()->GetUniquePlayerId(0);
TArray<FString> StatNames = {TEXT("ENEMIES_KILLED"), TEXT("TOTAL_SCORE")};
Stats->QueryStats(*UserId, {UserId.ToSharedRef()}, StatNames,
FOnlineStatsQueryUsersStatsComplete::CreateLambda(
[this, Stats, UserId](const FOnlineError& Error,
const TArray<TSharedRef<const FOnlineStatsUserStats>>& UsersStats)
{
if (Error.WasSuccessful() && UsersStats.Num() > 0)
{
for (const auto& Stat : UsersStats[0]->Stats)
{
UE_LOG(LogTemp, Log, TEXT("%s: %s"),
*Stat.Key, *Stat.Value.ToString());
}
}
}));
}