Client¶
The client-side data API: bundle.Client. Read the local player's data
through the same accessor tree as the server (Data.Coins.Get(),
Data.Coins.Observe(fn)); those methods are documented on the Value
class. Writes are local-only (optimistic UI). Server ops always win.
To change data authoritatively, call a server command via Client.Request.
In edit mode (when RunService:IsRunning() is false, e.g. a storybook)
the client skips the transport and initializes instantly to template
defaults, so components render without a running server.
Lifecycle¶
.IsReady¶
Whether the first Init snapshot has arrived (non-yielding). Before this is
true, accessor reads return template defaults. Always true in edit mode.
.WaitForData¶
Yields until the first Init snapshot arrives, then returns true. Returns
false if timeout seconds (default 30) pass first. It never hangs. Use
it to gate startup logic; for reactive UI prefer Observe/Changed.
Commands¶
.Request¶
Calls a server command registered with Server.Command and returns whatever
its handler returned. It yields until the reply arrives, and resolves
false, "timeout" if none comes within RequestTimeout. This is the one way
a client changes data authoritatively.
When Scribe refuses rather than your handler, the result is false, one
Scribe.RequestReason, and Scribe.RequestFailed in a third slot. Test that
third value, because a handler may return false, "timeout" of its own. A
retry after a timeout runs the handler a second time, so reach for
Client.RequestOnce when that is not safe. See
Commands & Requests.
.RequestOnce¶
Like Client.Request, but tagged with an idempotency key: the server runs
the handler at most once per key and replays its original reply, byte for
byte, to every repeat. Use it for anything a retry must not do twice, and
generate the key once per intent rather than once per attempt.
The command must be registered Idempotent = true, and a key sent to one that
is not, or a keyless Client.Request to one that is, is refused with
"bad-idempotency-key". A key must be non-empty, valid UTF-8, and at most 64
bytes, and this call raises on your own thread rather than send one that is
not. See
Running a command at most once.
Leaderboards¶
.GetLeaderboard¶
Types: LeaderboardEntry
The cached top-N of a replicated board (Replicate = true), streamed
to clients at handshake and on change. Empty for server-only boards.
.GetMyRank¶
The local player's rank on a replicated board, or nil if unranked.
.OnLeaderboard¶
Fires (boardName, entries) whenever a replicated board updates.
The value is a Signal, where Connect, Once and Wait are documented.
Service¶
.GetServiceStatus¶
The replicated data-service health. Show players a "progress may save
late" notice during a "Degraded"/"Outage".
.OnServiceStatus¶
Fires with the new status whenever service health changes.
The value is a Signal, where Connect, Once and Wait are documented.
Shared Data¶
.GetShared¶
Reads another player's Scribe.Shared roots (public info replicated to
everyone), or nil if not yet received.
Never returns the local player's own roots: the server broadcasts a
player's Shared data to everyone except that player, so nil there is
permanent rather than pending. Read your own through the ordinary accessor.
.OnSharedChanged¶
Fires (userId, sharedData) when another player's Shared data changes.
The value is a Signal, where Connect, Once and Wait are documented.
Ownership¶
.OnOwnershipChanged¶
Fires (key, owned) whenever the local player's ownership of a pass or perk
actually changes. Ownership already held at load is the baseline and does not
fire. Use Client.ObserveOwned instead when you care about one specific key
and want the current value immediately.
The value is a Signal, where Connect, Once and Wait are documented.
.Owns¶
Whether the local player owns a perk or pass, from the replicated mirror. Yields until data has loaded.
.OwnsAsync¶
Like Client.Owns, but yields until the server has finished syncing
ownership (the initial async gamepass refresh, signalled by a replicated
flag). Use it so a genuinely-owned pass is never briefly reported un-owned in
the window right after join. Perks/gifts are already synced at load. Falls
back to the current mirror value after timeout seconds (default 10).
.ObserveOwned¶
Calls callback with the current ownership and again whenever it changes.
Returns a disconnect function. Ideal for reactively toggling "buy" buttons.
Reads¶
.GetSaveInfo¶
Types: SaveInfo
The owner's replicated save state ({ LastSaveAt, LastResult, Dirty, Size })
for "Saving… / Saved ✓" UI. Size is the approximate byte size of the last
successful save (nil before the first).
.Raw¶
The same Data object without the typed accessor tree: the untyped
escape hatch if the type solver ever trips on your template.
Monetization¶
.GetGiftCredits¶
The local player's unassigned gift credits by product name.
.GetPurchases¶
Types: PurchaseFilter
The local player's purchase history for history UI. Only returned if the
game opts into replicating purchase logs (PurchaseLog.ReplicateRobux).
PurchaseFilter is { Kind: ("Robux" | "InGame")?, Category: string?,
ItemId: string?, Since: number?, Limit: number? }, exported as
Scribe.PurchaseFilter.
Edit Mode¶
.Mock¶
Client.Mock(values: { [string]: any }?, scribeState: { Perks: { string }?, GiftCredits: { [string]: number }?, PurchaseLogs: { Robux: { any }?, InGame: { any }? }?, Leaderboards: { [string]: { LeaderboardEntry } }? }?)
Types: LeaderboardEntry
Seeds mock data for a storybook / edit mode. Errors outside edit mode. Use it to render Scribe-backed components with realistic state.
values holds template fields to seed and is deep-merged into the mirror,
so you only pass the fields your component reads. scribeState seeds the
monetization and leaderboard state those APIs read.
.MockCommand¶
Registers a fake handler so Client.Request resolves in edit mode without
a server. Errors outside edit mode.