Skip to main content

Integrate session storage

Last updated on December 18, 2025

Introduction

AccelByte Gaming Services (AGS) Session has storage capability that offers a versatile solution that caters to a wide range of gaming clients. It facilitates seamless loading within sessions, while providing distinct permissions for leader and public data. Public data will be accessible for reading but can only be modified by its owner. This functionality streamlines the storage of session data for game developers, enhancing overall efficiency.

Session storage is available for both game sessions and party sessions:

Game Session Storage

  • Scope: Data tied to a specific game session / match.
  • Access: Supports leader and member storage; leader storage is only writable by the leader, member storage only by that member.
  • Usage: Shared session metadata and per-member data, readable (with permissions) by leaders/members to coordinate gameplay.
  • Lifecycle: Exists only for the lifetime of the game session.

Party Session Storage

  • Scope: Data tied to a party session (group of players).
  • Access: Each player can only modify their own storage; not exposed to other players or broadly to the game client.
  • Usage: Personal, party-scoped data (e.g., loadouts or per-member prefs) that others can't change.
  • Lifecycle: Exists only while the party session is active.

This article contains code snippets for the following functions:

How it works

The diagram below shows how session storage works using AGS.

A player is granted permission to update or insert data into session storage if they are both registered and active in the game session. Access is restricted to players who have joined and connected to the respective game session. Players who already left or disconnected from a session will not be allowed to update the session storage.

Update session storage

If there's no data in the session storage, create it. If there's already data, update it in the game session.

Update session leader storage

Modify the data for session leader storage. This function can only modify the data of session storage for leader.

// Prepare the storage data
FJsonObjectWrapper LeaderStorageData;
LeaderStorageData.JsonObject = MakeShared<FJsonObject>();
LeaderStorageData.JsonObject->SetStringField(TEXT("map_name"), TEXT("Desert Arena"));
LeaderStorageData.JsonObject->SetBoolField(TEXT("is_ranked"), true);
LeaderStorageData.JsonObject->SetNumberField(TEXT("max_score"), 1000);

// Set a listener when the update session leader storage to backend completes
FOnUpdateSessionLeaderStorageCompleteDelegate OnUpdateLeaderStorageComplete = FOnUpdateSessionLeaderStorageCompleteDelegate::CreateLambda(
[](FName SessionName, const FOnlineError& ErrorInfo)
{
if (ErrorInfo.bSucceeded)
{
// Do something after updating leader storage completes
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Error on updating session leader storage. Code: %s, Reason: %s"), *ErrorInfo.ErrorCode, *ErrorInfo.ErrorMessage.ToString());
return;
}
});
SessionInterface_User1->AddOnUpdateSessionLeaderStorageCompleteDelegate_Handle(OnUpdateLeaderStorageComplete);

// Execute updating session leader storage to the backend
SessionInterface_User1->UpdateSessionLeaderStorage(LocalUserId1.ToSharedRef().Get(), NAME_GameSession, LeaderStorageData);

Update session member storage

Modify the data for session member storage. This function can only modify the data of session storage for members (non-leaders).

// Prepare the member storage data
FJsonObjectWrapper MemberStorageData;
MemberStorageData.JsonObject = MakeShared<FJsonObject>();
MemberStorageData.JsonObject->SetStringField(TEXT("weapon"), TEXT("AK-47"));
MemberStorageData.JsonObject->SetNumberField(TEXT("kills"), 10);
MemberStorageData.JsonObject->SetNumberField(TEXT("deaths"), 5);

// Set the listener when update session storage to the backend completes
FOnUpdateSessionMemberStorageCompleteDelegate OnUpdateSessionMemberStorageComplete = FOnUpdateSessionMemberStorageCompleteDelegate::CreateLambda(
[](FName SessionName, const FUniqueNetId& UpdatedMemberId, const FOnlineError& ErrorInfo)
{
if (ErrorInfo.bSucceeded)
{
// Do something after the update to the backend completes
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Error on updating session member storage. Code: %s, Reason: %s"), *ErrorInfo.ErrorCode, *ErrorInfo.ErrorMessage.ToString());
return;
}
});
SessionInterface_User1->AddOnUpdateSessionMemberStorageCompleteDelegate_Handle(OnUpdateSessionMemberStorageComplete);

// Execute updating session member storage to the backend
SessionInterface_User1->UpdateSessionMemberStorage(LocalUserId1.ToSharedRef().Get(), NAME_GameSession, MemberStorageData);

Read session storage

Get the data of session storage with a JSON object type in the game session.

Read session leader storage

Get the data of session storage from the leader.

// Get the named session object
const FNamedOnlineSession* GameSession = SessionInterface_User1->GetNamedSession(NAME_GameSession);
if (GameSession == nullptr)
{
return;
}

// Get the named game session's info object and cast it to FOnlineSessionInfoAccelByteV2
TSharedPtr<FOnlineSessionInfoAccelByteV2> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(GameSession->SessionInfo);
if (!SessionInfo.IsValid())
{
return;
}

// Get session leader storage data
FJsonObjectWrapper LeaderStorage;
bool bSuccess = SessionInfo->GetSessionLeaderStorage(LeaderStorage);
if (bSuccess && LeaderStorage.JsonObject.IsValid())
{
// Access the storage data
FString MapName = LeaderStorage.JsonObject->GetStringField(TEXT("map_name"));
bool bIsRanked = LeaderStorage.JsonObject->GetBoolField(TEXT("is_ranked"));
int32 MaxScore = LeaderStorage.JsonObject->GetNumberField(TEXT("max_score"));

// Do something with the data
}

Read session member storage

Get the data of session storage from the members.

// Get the named session object
const FNamedOnlineSession* GameSession = SessionInterface_User1->GetNamedSession(NAME_GameSession);
if (GameSession == nullptr)
{
return;
}

// Get the named game session's info object and cast it to FOnlineSessionInfoAccelByteV2
TSharedPtr<FOnlineSessionInfoAccelByteV2> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(GameSession->SessionInfo);
if (!SessionInfo.IsValid())
{
return;
}

// Read all session member storage
TUniqueNetIdMap<FJsonObjectWrapper> AllMemberStorages;
bool bSuccess = SessionInfo->GetAllSessionMemberStorage(AllMemberStorages);
if (bSuccess)
{
// Loop through all member storage
for (const TPair<FUniqueNetIdRef, FJsonObjectWrapper>& MemberStorage : AllMemberStorages)
{
const FUniqueNetIdRef& MemberId = MemberStorage.Key;
const FJsonObjectWrapper& Storage = MemberStorage.Value;

if (Storage.JsonObject.IsValid())
{
// Access the member's storage data
FString Weapon = Storage.JsonObject->GetStringField(TEXT("weapon"));
int32 Kills = Storage.JsonObject->GetNumberField(TEXT("kills"));
int32 Deaths = Storage.JsonObject->GetNumberField(TEXT("deaths"));

// Do something with the data
}
}
}

// Read specific member storage
FJsonObjectWrapper SpecificMemberStorage;
bSuccess = SessionInfo->GetSessionMemberStorage(LocalUserId1.ToSharedRef(), SpecificMemberStorage);
if (bSuccess && SpecificMemberStorage.JsonObject.IsValid())
{
// Access specific member's storage data
FString Weapon = SpecificMemberStorage.JsonObject->GetStringField(TEXT("weapon"));
// Do something with the data
}

Listen to session storage updated event

An event that will be sent to all users in the same game session when there is a session storage update. This event is sent through a WebSocket connection to ensure that they've been received in real time.

Session leader storage updated event

Received when there is a session storage update from leader.

// Get notified when there is an update to session leader storage from backend
FOnSessionLeaderStorageUpdateReceivedDelegate OnSessionLeaderStorageUpdated = FOnSessionLeaderStorageUpdateReceivedDelegate::CreateLambda(
[](FName SessionName)
{
if (SessionName == NAME_GameSession)
{
// Session leader storage has been updated
// You can retrieve the updated storage data here
}
});
auto DelegateHandle = SessionInterface_User1->AddOnSessionLeaderStorageUpdateReceivedDelegate_Handle(OnSessionLeaderStorageUpdated);

// When done listening, clear the delegate
// SessionInterface_User1->ClearOnSessionLeaderStorageUpdateReceivedDelegate_Handle(DelegateHandle);

Session member storage updated event

Received when there is a session storage update from a member.

// Get notified when a session member updates their storage
FOnSessionMemberStorageUpdateReceivedDelegate OnSessionMemberStorageUpdated = FOnSessionMemberStorageUpdateReceivedDelegate::CreateLambda(
[](FName SessionName, const FUniqueNetId& UpdatedMemberId)
{
if (SessionName == NAME_GameSession)
{
// Get the session info to access the updated member storage
const FNamedOnlineSession* GameSession = SessionInterface_User1->GetNamedSession(SessionName);
if (GameSession == nullptr)
{
return;
}

TSharedPtr<FOnlineSessionInfoAccelByteV2> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(GameSession->SessionInfo);
if (!SessionInfo.IsValid())
{
return;
}

// Get the updated member's storage
FJsonObjectWrapper UpdatedMemberStorage;
bool bSuccess = SessionInfo->GetSessionMemberStorage(UpdatedMemberId.AsShared(), UpdatedMemberStorage);
if (bSuccess && UpdatedMemberStorage.JsonObject.IsValid())
{
// Access the updated storage data
FString Weapon = UpdatedMemberStorage.JsonObject->GetStringField(TEXT("weapon"));
int32 Kills = UpdatedMemberStorage.JsonObject->GetNumberField(TEXT("kills"));

// Do something with the updated storage
}
}
});
auto DelegateHandle = SessionInterface_User1->AddOnSessionMemberStorageUpdateReceivedDelegate_Handle(OnSessionMemberStorageUpdated);

// When done listening, clear the delegate
// SessionInterface_User1->ClearOnSessionMemberStorageUpdateReceivedDelegate_Handle(DelegateHandle);

Update party session storage

Update the party session storage for the current user. Each party member can only update their own storage data. This will overwrite the current party session storage if successful.

// Prepare the party storage data
FJsonObjectWrapper PartyStorageData;
PartyStorageData.JsonObject = MakeShared<FJsonObject>();
PartyStorageData.JsonObject->SetStringField(TEXT("playerRole"), TEXT("tank"));
PartyStorageData.JsonObject->SetNumberField(TEXT("playerLevel"), 42);
PartyStorageData.JsonObject->SetBoolField(TEXT("isReady"), true);

// Set the listener when update party session storage to the backend completes
FOnUpdatePartySessionStorageCompleteDelegate OnUpdatePartyStorageComplete = FOnUpdatePartySessionStorageCompleteDelegate::CreateLambda(
[](FName SessionName, const FOnlineError& ErrorInfo)
{
if (ErrorInfo.bSucceeded)
{
// Do something after updating party storage completes
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Error on updating party session storage. Code: %s, Reason: %s"), *ErrorInfo.ErrorCode, *ErrorInfo.ErrorMessage.ToString());
return;
}
});
auto DelegateHandle = SessionInterface_User1->AddOnUpdatePartySessionStorageCompleteDelegate_Handle(OnUpdatePartyStorageComplete);

// Execute updating party session storage to the backend
SessionInterface_User1->UpdatePartySessionStorage(*LocalUserId1.Get(), PartyStorageData);

// When done listening, clear the delegate
// SessionInterface_User1->ClearOnUpdatePartySessionStorageCompleteDelegate_Handle(DelegateHandle);

Read party session storage

Get the party session storage data from the local cache or query from the backend.

Read party storage from local cache

// Get the party session
const FNamedOnlineSession* PartySession = SessionInterface_User1->GetPartySession();
if (PartySession == nullptr)
{
return;
}

// Get the party session's info object and cast it to FOnlineSessionInfoAccelByteV2
TSharedPtr<FOnlineSessionInfoAccelByteV2> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(PartySession->SessionInfo);
if (!SessionInfo.IsValid())
{
return;
}

// Read all party members' storage
TUniqueNetIdMap<FJsonObjectWrapper> AllPartyStorages;
bool bSuccess = SessionInfo->GetAllPartyStorage(AllPartyStorages);
if (bSuccess)
{
// Loop through all party members' storage
for (const TPair<FUniqueNetIdRef, FJsonObjectWrapper>& PartyStorage : AllPartyStorages)
{
const FUniqueNetIdRef& MemberId = PartyStorage.Key;
const FJsonObjectWrapper& Storage = PartyStorage.Value;

if (Storage.JsonObject.IsValid())
{
// Access the party member's storage data
FString PlayerRole = Storage.JsonObject->GetStringField(TEXT("playerRole"));
int32 PlayerLevel = Storage.JsonObject->GetNumberField(TEXT("playerLevel"));
bool bIsReady = Storage.JsonObject->GetBoolField(TEXT("isReady"));

// Do something with the data
}
}
}

// Read specific party member's storage
FJsonObjectWrapper SpecificMemberStorage;
bSuccess = SessionInfo->GetPartyStorage(LocalUserId1.ToSharedRef(), SpecificMemberStorage);
if (bSuccess && SpecificMemberStorage.JsonObject.IsValid())
{
// Access specific member's storage data
FString PlayerRole = SpecificMemberStorage.JsonObject->GetStringField(TEXT("playerRole"));
// Do something with the data
}

Query party storage from backend

// Query party session storage from backend
FUniqueNetIdAccelByteUserPtr AccelByteUserId = FUniqueNetIdAccelByteUser::Cast(LocalUserId1.ToSharedRef().Get());
SessionInterface_User1->GetPartySessionStorage(AccelByteUserId,
FOnGetPartySessionStorageComplete::CreateLambda([](const FAccelByteModelsV2PartySessionStorage& Result, bool bWasSuccessful)
{
if (bWasSuccessful)
{
// Access the party storage data from backend
// Result.Leader contains party leader's storage data
// Result.Members contains all party members' storage data
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Error on getting party session storage"));
return;
}
}));

Listen to party session storage updated event

An event that will be sent to all party members when there is a party storage update. This event is sent through a WebSocket connection to ensure that they've been received in real time.

// Get notified when a party member updates their storage
FOnPartyStorageUpdateReceivedDelegate OnPartyStorageUpdated = FOnPartyStorageUpdateReceivedDelegate::CreateLambda(
[](FName SessionName, const FUniqueNetId& UpdatedMemberId)
{
if (SessionName == NAME_PartySession)
{
// Get the party session info to access the updated member storage
const FNamedOnlineSession* PartySession = SessionInterface_User1->GetPartySession();
if (PartySession == nullptr)
{
return;
}

TSharedPtr<FOnlineSessionInfoAccelByteV2> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(PartySession->SessionInfo);
if (!SessionInfo.IsValid())
{
return;
}

// Get the updated member's storage
FJsonObjectWrapper UpdatedMemberStorage;
bool bSuccess = SessionInfo->GetPartyStorage(UpdatedMemberId.AsShared(), UpdatedMemberStorage);
if (bSuccess && UpdatedMemberStorage.JsonObject.IsValid())
{
// Access the updated storage data
FString PlayerRole = UpdatedMemberStorage.JsonObject->GetStringField(TEXT("playerRole"));
int32 PlayerLevel = UpdatedMemberStorage.JsonObject->GetNumberField(TEXT("playerLevel"));
bool bIsReady = UpdatedMemberStorage.JsonObject->GetBoolField(TEXT("isReady"));

// Do something with the updated storage
}
}
});
auto DelegateHandle = SessionInterface_User1->AddOnPartyStorageUpdateReceivedDelegate_Handle(OnPartyStorageUpdated);

// When done listening, clear the delegate
// SessionInterface_User1->ClearOnPartyStorageUpdateReceivedDelegate_Handle(DelegateHandle);