Server¶
The server-side data API: bundle.Server. Index it with a Player to
get that player's typed accessor tree (Data[player].Coins.Increment(50)),
and call its methods to drive persistence, monetization, leaderboards, and
administration.
Data[player] and Data.Get error while a profile is still loading.
Use Server.WaitForData first (or read inside a command handler, which
only runs once the player is Ready).
Indexing
Data[player] returns the same accessor tree as Data.Get(player). The
methods on individual fields (.Get, .Set, .Increment, …) are
documented on the Value class.
Lifecycle¶
.WaitForData¶
Yields until the player's profile is Ready, then returns their accessor
tree. On failure returns (nil, reason) where reason is "load-failed",
"timeout", or "session-end". Always handle the nil branch. This is
the safe way to get data in Players.PlayerAdded.
.GetState¶
The player's session state, without yielding.
.Get¶
The player's accessor tree. Errors if the profile is not Ready. Prefer
Server.WaitForData on join. Data[player] is shorthand for this.
.Batch¶
Runs fn as a batch: all writes inside coalesce into a single replication
flush and one Changed pass. Use for bulk updates.
.Transaction¶
Runs fn atomically: if it throws, every write inside is rolled back
and (false, error) is returned. On success returns (true, nil).
Persistence¶
.Flush¶
Forces a save now instead of waiting for the next autosave. Call it right
after a grant or purchase. Force = true also pushes through a blocked
wipe-guard save.
.GetSaveInfo¶
The player's save state ({ LastSaveAt, LastResult, Dirty }) for
"Saving… / Saved ✓ / Unsaved changes" UI. Also mirrored to the owner.
.GetOffline¶
Reads a profile that is not on this server (offline, or another server),
or nil if it doesn't exist. Read-only. Use Server.UpdateOffline to
write.
.UpdateOffline¶
Mutates an offline profile's raw data. Fails closed if the user has an active session anywhere, so it can never clobber a live game.
.ListVersions¶
Server.ListVersions(userId: number, limit: number?) → { { VersionId: string, CreatedAt: number, Size: number? } }
Lists a profile's DataStore version history, for support/rollback tools.
.GetVersion¶
Reads the raw data of a specific historical version.
.RestoreVersion¶
Restores a profile to a historical version. Fails closed if the user is active on another server.
.Erase¶
GDPR right-to-erasure: removes the profile and the user's leaderboard
entries. Returns (false, reason) if any part failed so you can retry.
.Export¶
GDPR data export: the profile as a JSON string (buffers base64-encoded),
or nil if it doesn't exist.
Commands¶
.Command¶
Server.Command(name: string, specOrHandler: ({ Args: { string }? } | (player: Player, ...any) -> ...any), handler: ((player: Player, ...any) -> ...any)?)
Registers a named command clients can call via Client.Request. Sender
identity is always the real player; args are shape-validated, rate-limited,
and only run once the caller is Ready.
Data.Command("EquipItem", { Args = { "string" } }, function(player, itemId)
if not Data[player].Inventory[itemId].Get() then return false, "not owned" end
Data[player].Equipped.Set(itemId)
return true
end)
Leaderboards¶
.GetLeaderboard¶
The cached top-N of an all-time board ({ Rank, UserId, Name, Score }).
Never triggers a live OrderedDataStore read.
.GetMyRank¶
The player's current rank on a board, or nil if unranked.
Monetization¶
.PromptGift¶
Prompts buyer to gift a product's perk to recipientUserId. Records a
durable intent before money moves; delivery survives cross-server hops
and offline recipients, and a held gift credit is consumed with no charge.
Returns (false, reason) if the gift can't proceed.
.GetGiftCredits¶
The player's unassigned gift credits by product name.
.HandleReceipt¶
Processes a developer-product receipt. Scribe binds ProcessReceipt
automatically unless OwnReceipts = false, in which case call this from
your own handler. Idempotent by PurchaseId and fail-closed. Robux are
never eaten.
.Owns¶
The unified ownership check: a granted perk or an owned game pass (cached) or RobloxPlus. Hide "buy" buttons whenever this is true.
.GrantPerk¶
Grants a perk directly (admin/reward flows).
.RevokePerk¶
Revokes a granted perk.
.Purchase¶
Atomic soft-currency purchase: debits Cost, runs Grant, and logs it.
All or nothing. Insufficient funds or a throwing Grant rolls everything
back with no debit.
Data.Purchase(player, {
Cost = { Path = "Coins", Amount = 45000 },
Category = "Vehicle", ItemId = "Police01",
Grant = function(data) data.Vehicles.Insert("Police01") end,
})
.RecordPurchase¶
Appends an entry to the player's in-game purchase log (your own records).
.GetPurchases¶
Server.GetPurchases(player: Player, filter: { Kind: ("Robux" | "InGame")?, Category: string?, ItemId: string?, Since: number?, Limit: number? }?) → { table }
The player's purchase history (Robux receipts and in-game purchases), newest first, optionally filtered.
Cooldowns¶
.OnCooldown¶
Server.OnCooldown(player: Player, key: string, seconds: number) → (onCooldown: boolean, remaining: number)
Checks and arms a keyed cooldown: returns false and starts a new
seconds cooldown if it was off. Call it only at the grant/claim moment.
Use Server.PeekCooldown for display checks.
.PeekCooldown¶
Read-only cooldown check. Never arms it. Safe for UI.
.ClearCooldown¶
Clears a cooldown (support/testing resets).
Signals¶
.OnSave¶
Fires after every save attempt with { Player, Ok, Duration, At }.
.SessionEnded¶
Fires when a session ends with (player, reason). With
KickOnSessionEnd = true (the default) the player is also kicked.
.OnAnomaly¶
Fires for integrity anomalies (out-of-bounds writes, a tripped wipe guard,
an unserializable snapshot) with { Player, Path, Value, Reason }.
.OnGiftReceived¶
Fires when a player receives a gift with (player, { FromUserId, Product, GiftId }).
.OnGiftCredit¶
Fires when a player is issued a gift credit with (player, productName).
Messaging¶
.OnMessage¶
Fires with (player, message) when a cross-server message sent through
Server.SendMessage arrives for an active session.
.SendMessage¶
Sends a durable cross-server message to userId, delivered to
Server.OnMessage on whatever server they are (or next become) active on,
including offline recipients (queued until their next load). message must
be DataStore-serializable. Returns whether it was committed. Rides
ProfileStore's global-update channel, so keep messages small and infrequent.
Escape hatch¶
.ProfileStore¶
The underlying ProfileStore instance, an advanced escape hatch for
store-level operations Scribe doesn't wrap (version reads, raw MessageAsync,
and so on). It bypasses Scribe's schema, replication, and session guarantees,
so treat it as read-mostly and never mutate an active-session profile through
it. Most games never need this; prefer the typed API and Server.SendMessage.
.Raw¶
The same Data object without the typed accessor tree: the untyped escape
hatch if the type solver ever trips on your template.