Persistent cloud storage, server-side endpoints, and an editor sync tool for s&box games — powered by the sboxcool.com API.
- Network Storage: https://sbox.cool/tools/network-storage
- Documentation & Tutorials: http://sbox.cool/wiki/network-storage-v3
- s&box editor Library: https://sbox.game/sboxcool/network-storage
- Search
Network Storage by sbox.coolwith author name:sboxcool
- Search
- sbox.cool and sboxcool.com are both operated the same group.
SboxCool.comis our LTS url, e.g.api.sboxcool.com.
- Runtime Client — Call server endpoints, fetch game values, read/write documents from your game code
- Editor Sync Tool — Push and pull collections and endpoints between local YAML source files and the sboxcool.com dashboard
- Setup Wizard — Editor window for entering and validating your API credentials
- Diff Viewer — Side-by-side comparison of local vs remote data before syncing
- Network Logger — Ring buffer that captures all API traffic for in-game debug panels
- JSON Helpers — Extension methods for reading API response payloads
Install directly from the s&box asset browser:
https://sbox.game/sboxcool/network-storage
Or find it in the editor:
- Open the s&box editor
- Go to Editor > Library Manager
- Search for "Network Storage"
- Look for the one published by sboxcool — do not install from other authors
- Click Add to Project
The library appears in your project's Libraries/ folder automatically.
Clone this repo into your project's Libraries/ directory:
cd "YourProject/Libraries"
git clone https://github.com/sbox-cool/sbox-network-storage "Network Storage by sboxcool"
Or add it as a git submodule:
git submodule add https://github.com/sbox-cool/sbox-network-storage "Libraries/Network Storage by sboxcool"
- Go to sboxcool.com and create a new project
- Note your Project ID from the dashboard
- Create API keys:
- Public key (
sbox_ns_prefix) — used by the game client at runtime - Secret key (
sbox_sk_prefix) — used by the editor sync tool only, never ships with your game
- Public key (
- Open Editor > Network Storage > Setup
- Enter your Project ID, Public API Key, and Secret Key
- Click Save Configuration
- Click Test Connection to verify
Your credentials are saved to Editor/Network Storage/.env — this file is in the Editor/ directory which s&box excludes from publishing. Your secret key never ships with your game.
Dedicated servers can supply a runtime endpoint secret without putting it in the published bundle:
sbox-server.exe +game your.org.game your.map +hostname "My Server" +network_storage_secret_key sbox_sk_your_secret_keyThe primary dedicated launch key is +network_storage_secret_key. The library also accepts aliases (+network-storage-secret-key, +sboxcool_secret_key, +networkStorageSecretKey, +sboxcoolSecretKey, +nsSecretKey, +ns_secret_key) on Application.IsDedicatedServer hosts, and validates the supplied key at game startup. Generic names such as +secret-key, +secret_key, and +secretKey are intentionally not supported. When the dedicated key is used, the library does not request or send s&box auth tokens. Endpoint requests use an internal backend flag while the actual launch secret travels in the x-secret-key HTTPS header. Storage document row reads/writes/deletes use the secret as the HTTPS x-api-key header without a URL secret flag so secret keys with collections:execute can access endpoint-only collections. Do not put sbox_sk_ values in code, public credentials, or client-callable URLs. Collection schema deletion remains website-only.
Create a config class in your game project:
namespace Sandbox;
public static class MyNetStorageConfig
{
public const string ProjectId = "your_project_id";
public const string ApiKey = "sbox_ns_your_public_key";
public static void Initialize()
{
NetworkStorage.Configure( ProjectId, ApiKey );
}
}Then call endpoints from your game code:
// Configure once at startup
if ( !NetworkStorage.IsConfigured )
MyNetStorageConfig.Initialize();
// Call a server endpoint (GET)
var player = await NetworkStorage.CallEndpoint( "load-player" );
// Call with input (POST)
var result = await NetworkStorage.CallEndpoint( "mine-ore", new
{
ore_id = "iron",
kg = 5.0f
} );
// Endpoint URLs from the dashboard are also accepted; the slug is extracted.
var sameResult = await NetworkStorage.CallEndpoint(
"https://api.sboxcool.com/v3/endpoints/your_project_id/mine-ore?apiKey=sbox_ns_your_public_key",
new { ore_id = "iron", kg = 5.0f } );
// Update collection documents directly (dedicated servers attach +network_storage_secret_key automatically)
await NetworkStorage.SaveDocument( "player-data", Game.SteamId.ToString(), new { level = 2, xp = 100 } );
await NetworkStorage.UpdateDocument( "player-data", Game.SteamId.ToString(),
NetworkStorageOperation.Increment( "xp", 50, source: "server", reason: "quest" ),
NetworkStorageOperation.Set( "lastSeen", DateTimeOffset.UtcNow.ToUnixTimeSeconds() ) );
await NetworkStorage.DeleteDocument( "player-data", Game.SteamId.ToString() );
// Read the response
if ( result.HasValue )
{
var currency = JsonHelpers.GetInt( result.Value, "currency", 0 );
var level = JsonHelpers.GetInt( result.Value, "level", 1 );
}See the Examples/ folder for complete working patterns.
| Method | Description |
|---|---|
Configure(projectId, apiKey) |
Set credentials. Call once at startup. |
CallEndpoint(slugOrUrl, input?) |
Call a server endpoint by slug or endpoint URL. Returns JsonElement?. |
GetGameValues() |
Fetch all game values (constants + tables). Returns JsonElement?. |
GetDocument(collectionId, documentId?) |
Read a document from a collection. Defaults to current player's Steam ID. |
SaveDocument(collectionId, documentId, data) |
Save/replace a collection document. Dedicated servers attach the configured secret key automatically. |
UpdateDocument(collectionId, documentId, ops) |
Apply server-side operations (set, inc, push, pull, remove) to a document. |
DeleteDocument(collectionId, documentId?) |
Delete one collection document/row. Public calls require record deletes to be enabled; dedicated secret keys with collection execute permission can delete rows for diagnostics/backoffice cleanup. Does not delete collection schemas. |
ListRecords/CreateRecord/RenameRecord/DeleteRecord |
Manage multi-record save slots. |
NetworkStorageAnalytics.TrackEvent(eventType, payload?) |
Report an allowlisted custom Player Analytics event. |
NetworkStorageAnalytics.Warning(code, message?, context?) |
Report a recoverable warning/pain point to the player timeline. |
NetworkStorageAnalytics.Error(exception, code?, context?) |
Report an exception/error to the player timeline without breaking gameplay. |
NetworkStorageAnalytics.SessionStart/SessionEnd |
Report managed session boundaries when analytics is enabled. |
IsConfigured |
true after Configure() has been called. |
ApiRoot |
The full versioned API URL (e.g. https://api.sboxcool.com/v3). |
See analytics.md for Player Analytics setup, custom events, warnings, and error reporting examples.
Safe extraction from API JsonElement payloads with caller-provided defaults. Handles missing keys and string-to-number coercion.
var name = JsonHelpers.GetString( data, "playerName", "Unknown" );
var level = JsonHelpers.GetInt( data, "level", 1 );
var speed = JsonHelpers.GetFloat( data, "speed", 1.0f );
var active = JsonHelpers.GetBool( data, "active", true );Shorthand wrappers around JsonHelpers, plus collection parsers:
// Shorthand
var name = data.Str( "playerName", "Unknown" );
var level = data.Int( "level", 1 );
var speed = data.Float( "speed", 1.0f );
// Parse arrays
var upgrades = data.ReadStringList( "purchasedUpgrades" );
// Parse objects
var ores = data.ReadDictionary( "ores", v => (float)v.GetDouble() );
// Parse table rows
var items = data.ReadList( "rows", row => new ItemInfo(
row.Str( "id" ), row.Str( "name" ), row.Int( "tier" )
) );Wraps endpoint calls with automatic state management for HUD feedback:
var tracker = new SaveStateTracker();
// Simple tracked call
var result = await tracker.Call( "mine-ore", new { ore_id = "iron", kg = 5 } );
// tracker.State is now Saved or Error
// tracker.IsBusy is true while any call is in flight
// Optimistic update with auto-revert
await tracker.CallAndApply( "sell-ore", input,
applyOptimistic: () => { /* update local state */ },
applyServer: (data) => { /* apply authoritative response */ },
revert: () => { /* undo on failure */ }
);Static ring buffer capturing all Network Storage events. Use it for debug panels:
// Entries are added automatically by NetworkStorage
foreach ( var entry in NetLog.Entries )
{
// entry.Time, entry.Kind (Request/Response/Error/Info),
// entry.Tag, entry.Message
}
// Add custom entries
NetLog.Info( "my-system", "Custom log message" );
// Track changes (for UI refresh)
var version = NetLog.Version; // increments on every add/clearThe Sync Tool lets you manage your sboxcool.com project data as local YAML source files, then push/pull changes through the API. YAML is the preferred authoring format. Existing legacy JSON resources remain readable and pushable for compatibility; newly created and pulled resources are written as YAML.
Editor > Network Storage > Sync Tool
- Define new collections, endpoints, workflows, tests, and libraries as YAML source files in
Editor/Network Storage/ - Existing JSON resources can still be pushed; migrate them to YAML when convenient to use the current authoring format
- Click Check for Updates to compare local files against the remote server
- Push sends your local changes to sboxcool.com
- Pull downloads the latest from sboxcool.com to your local files
- View Diff shows a side-by-side comparison before overwriting
YAML source files use kind-specific names:
collections/<id>.collection.yml
endpoints/<slug>.endpoint.yml
workflows/<id>.workflow.yml
tests/<id>.test.yml
libraries/<id>.library.yml
.yaml is also accepted, but project documentation and generated examples should prefer .yml. Legacy JSON files are unsupported and are not automatically reverse-converted into YAML.
Each source file starts with:
sourceVersion: 1
kind: endpoint
id: mine-ore
definition:
method: POST
steps: []See source-authoring.md, source-authoring.schema.json, and Examples/SourceAuthoring/ for the current source model and examples.
Validate and preview source files locally:
python Libraries/sboxcool.network-storage/Editor/source_compiler.py --project-root .
python Libraries/sboxcool.network-storage/Editor/sync.py --project-root . --sources --dry-run| Icon | Meaning |
|---|---|
| ✓ | In sync — local matches remote |
| ▲ | Local only — exists locally but not on server |
| ▼ | Remote only — exists on server but not locally |
| ● | Differs — local and remote have different content |
Editor/
Network Storage/ # Configurable in Setup
.env # Credentials (gitignored, never published)
collections/ # YAML source collections
player_data.collection.yml
game_values.collection.yml
endpoints/ # YAML source endpoints
load-player.endpoint.yml
mine-ore.endpoint.yml
sell-ore.endpoint.yml
workflows/
check-currency.workflow.yml
libraries/
economy.library.yml
- Secret key (
sbox_sk_) is stored inEditor/Network Storage/.env— theEditor/directory is excluded from s&box publishing, so your secret key never ships with your game - Public key (
sbox_ns_) is safe to include in your game code — it can only be used with Steam authentication - The
.envfile is gitignored by default — never commit it to version control - See
.env.examplefor the expected format
Network Storage runs in API Only mode. Runtime reads and editor sync operations use the API; local JSON files and API fallback modes are unsupported.
This repo includes an MCP (Model Context Protocol) server that gives AI coding agents like Claude deep knowledge of the Network Storage system — collections, endpoints, workflows, template syntax, error diagnosis, and more.
- 10 tools — validate source files, scaffold new collections/endpoints/workflows, get documentation, diagnose errors
- 8 resources — all documentation files exposed for contextual reading
The MCP server requires Bun to be installed.
- The
.mcp.jsonfile at the repo root auto-configures Claude Code to use the MCP server - Dependencies are installed automatically on first launch (
bun install) - Open Claude Code in this repo and the MCP will be available
To verify it's working, run /mcp in Claude Code — you should see sbox-network-storage listed.
If your MCP client doesn't auto-discover .mcp.json, add this to your MCP configuration:
{
"mcpServers": {
"sbox-network-storage": {
"command": "bash",
"args": ["-c", "cd mcp && bun install —silent && cd .. && bun run mcp/index.ts"]
}
}
}Set the working directory to this repository root.
| Tool | Description |
|---|---|
get_documentation |
Retrieve docs by topic (collections, endpoints, workflows, setup, errors, etc.) |
validate_collection |
Validate a collection definition for correct schema and naming |
validate_endpoint |
Validate an endpoint definition — steps, operators, templates, constraints |
validate_workflow |
Validate a workflow definition — conditions, onFail config |
scaffold_collection |
Generate a collection YAML source template |
scaffold_endpoint |
Generate an endpoint YAML source template |
scaffold_workflow |
Generate a workflow YAML source template |
get_examples |
Get examples for common game scenarios (inventory, currency, leaderboard, etc.) |
validate_env_config |
Validate .env credential file format |
diagnose_error |
Diagnose s&box console errors and suggest fixes |
MIT — see LICENSE.