Skip to content

Session Data (Non-Persistent) ​

PlayerState supports runtime-only data that replicates during play but is never persisted to the DataStore. Use session data for temporary state that should reset each time a player joins.

For how session fits next to normal player data, SharedSession, and Server-only roots, see the data visibility model.

Quick Start ​

Add a session root to your DefaultData and use normal API calls. Session data syncs to clients but is never saved.

lua
-- DefaultData
session = {
    isChopping = false,
    isSprinting = false,
}

-- Server: set session state
PlayerState.SetPath(player, "session.isSprinting", true)

-- Client: read session state
local PlayerStateClient = require(game.ReplicatedStorage.Libraries.PlayerState.PlayerStateClient)
local sprinting = PlayerStateClient.GetPath("session.isSprinting")

What It Is ​

Session data (also called non-persistent or runtime-only data) lives at special roots such as session. PlayerState treats these roots differently:

  • Replicates during play — clients can read it and listeners fire when it changes
  • Never persisted — stripped from the save payload
  • Reset on load — cleaned on profile load and re-seeded from template defaults

Use it for activity flags, temporary UI state, minigame progress, or any value that should not survive rejoin or server restart.

Why Use It ​

Use CaseExample
Activity flagssession.isChopping, session.isSprinting, session.inCombat
Temporary progresssession.currentMinigameScore, session.questStep
UI / client statesession.selectedTab, session.tutorialStep
Per-session counterssession.killsThisSession, session.deathsThisSession

You get real-time sync and change listeners without bloat in the DataStore or save/load cost.

DefaultData Example ​

Define session roots in your template. They will be initialized from these defaults on every profile load:

lua
-- ReplicatedStorage.Libraries.PlayerState.DefaultData
return {
    Coins = 100,
    Level = 1,

    session = {
        isChopping = false,
        isSprinting = false,
        inCombat = false,
        currentMinigame = nil,
    },
}

Server: Set and Get ​

Use SetPath / GetPath (or Set / Get) the same way as persistent data:

lua
-- ServerScriptService
local PlayerState = require(game.ReplicatedStorage.Libraries.PlayerState.PlayerStateServer)

Players.PlayerAdded:Connect(function(player)
    PlayerState.Init(player)

    -- Set session state
    PlayerState.SetPath(player, "session.isSprinting", true)
    PlayerState.SetPath(player, "session.isChopping", false)

    -- Read it back
    local sprinting = PlayerState.GetPath(player, "session.isSprinting")
end)

Client: Read and Listen ​

Clients read session data like any other path. It is available as soon as the profile is loaded:

lua
-- LocalScript
local PlayerState = require(game.ReplicatedStorage.Libraries.PlayerState.PlayerStateClient)

local sprinting = PlayerState.GetPath("session.isSprinting")
print("Is sprinting:", sprinting)

PlayerState.OnChanged("session.isSprinting", function(newValue, oldValue)
    print("Sprinting changed:", oldValue, "->", newValue)
end)

Save Behavior ​

Session roots are never persisted:

  • Stripped from the save payload before writing to the DataStore
  • Restored in-memory from template defaults after save
  • On load, runtime roots are cleaned and re-seeded from DefaultData

You do not need to do anything special. PlayerState handles this automatically.

Common Mistakes ​

Using SetOfflineData for Session Paths ​

SetOfflineData writes to the persistent profile. It blocks runtime-only paths such as session.* and will warn or fail for those writes.

lua
-- ❌ WRONG: session data cannot be set offline
PlayerState.SetOfflineData(userId, "session.isSprinting", true)

-- ✅ Use SetPath when the player is in-server only
PlayerState.SetPath(player, "session.isSprinting", true)

Session data only exists while the player has an active profile session. There is no offline equivalent.

Mixing Session and Persistent Data ​

Keep session and persistent data clearly separated by root:

lua
-- ✅ Clear separation
session = { isSprinting = false }
Stats = { TotalPlayTime = 0, LastLogin = 0 }

-- ❌ Avoid putting session state inside persistent roots
Stats = { TotalPlayTime = 0, isSprinting = false }

Expecting Session Data After Rejoin ​

Session data resets on every join. Do not rely on it across sessions:

lua
-- Session data is per-session only
PlayerState.SetPath(player, "session.killsThisSession", 10)
-- Player leaves and rejoins -> session.killsThisSession is 0 again

Troubleshooting ​

ProblemCauseFix
Session data not syncing to clientClient may not be readyUse PlayerState.IsReady() before reads
SetOfflineData fails for session pathRuntime roots are not persistedUse SetPath when player is in-game only
Session values persist after rejoinWrong root usedEnsure data is under session (or configured runtime root)

PlayerState - High-Performance Roblox Data Management