Connect a game
Point the game library at your server: project, public key and base URL.
sbox Network Storage Server speaks the same HTTP API as the managed service at sbox.cool. The published s&box client library works without changes: you only change its base URL.
- s&box library: https://sbox.game/sboxcool/network-storage
- Client source: https://github.com/sbox-cool/sbox-network-storage
- API and library docs: https://sbox.cool/wiki/network-storage-v3
The client appends the API version itself (/v3/...), so the base URL is just
the scheme, host and port of your server, with no path and no trailing slash.
1. Find your server URL
| How players reach the server | Base URL |
|---|---|
Domain with HTTPS (tls.mode = acme or certificate, or a reverse proxy) |
https://ns.example.com |
| Domain over plain HTTP | http://ns.example.com:8080 |
| Public IP and port | http://203.0.113.10:8080 |
| Same machine as the game (development) | http://localhost:8080 |
Check the server responds from the machine running s&box:
curl -i http://your-server:8080/health
curl http://your-server:8080/v3/server-info
Make sure the port is open in your firewall and forwarded on your router if the server is behind NAT.
2. Create a project and API keys
Use the local-owner dashboard, or run the CLI
on the server. A project created in the dashboard gets a public key, and its
overview shows the filled-in NetworkStorage.Configure line and Setup window
values to copy.
On the CLI:
sbox-ns project create "My Game" # prints the project ID
sbox-ns key create <projectId> --type public --label game
sbox-ns key create <projectId> --type secret --label editor
3. Configure the editor
- Open your game in the s&box editor.
- Open Editor > Network Storage > Setup.
- Enter the Project ID, Public API Key and Secret Key from step 2.
- Set Base URL to your server URL from step 1.
- Leave CDN URL empty unless you serve a CDN in front of your server.
- Save, then use Editor > Network Storage > Sync Tool to push YAML Source
definitions for collections, endpoints and workflows (
.ymlpreferred;.yamlalso accepted).
The Setup window stores the base URL in your project's Network Storage
credentials, and the generated config is picked up automatically by
NetworkStorage.AutoConfigure() at runtime.
Staged pushes and editor play sessions
The Sync Tool's Push Staged sends x-ns-publish-target: next. Endpoint and
collection definitions go into revision-overrides.json, leaving live game
definitions unchanged. Workflows and saved tests remain live. Staging requires
a synced game package with a numeric current revision; without one, the push
goes live and reports publishTarget: live and stagedFallback in its response.
Management lists with includeStaged=true include live definitions and staged
copies marked revisionTarget: next. Explicit revisionTarget=live returns
only live definitions. Editor play sessions and management endpoint tests
targeting next use staged endpoint and collection definitions, falling back
to live definitions for anything not staged. Player records are shared, not a
separate staging database: a next-targeted runtime call can change real data.
Dry-run management tests do not persist those writes.
Syncing a new game package revision promotes staged definitions into live and clears the overrides. Use the normal live target for changes that should take effect immediately.
The command-line sync tool's PUT endpoints?replaceAll=true replaces the live
endpoint set after a successful push: omitted endpoints are deleted. Without
that query parameter, pushes only upsert the supplied endpoints. Staged pushes
never delete live definitions.
4. Or configure in code
NetworkStorage.Configure( projectId, publicKey, "https://ns.example.com" );
Configure also accepts an optional API version and CDN URL, exactly as with the
managed service. Only pass the public API key in game code; the secret key
belongs in the editor only.
Collection access from game clients
The public key ships inside every game build, so anyone can extract it. The
direct document API (GET, POST and DELETE /v3/storage/{projectId}/{collection}/{key},
the /api/storage alias and /probe) therefore treats public-key calls as
untrusted:
- The collection must declare
accessMode: public. Any other value, or noaccessModeat all, is endpoint-only and answers403 ENDPOINT_ONLY. Route those reads and writes through endpoints or queries. Collections created in the dashboard start as endpoint-only. - Deleting needs
allowRecordDelete: true, otherwise403 RECORD_DELETE_DISABLED. - Writing or deleting in a collection that is not declared at all answers
404. - When the project requires s&box authentication, the call must carry a valid
s&box token (
x-sbox-tokenwithx-steam-id) or auth session, otherwise401 SBOX_AUTH_FAILED. Writes and deletes in a per-player collection must then target the player's own document: the key is the verified Steam ID, or starts with{steamId}_for save slots. Anything else answers403 FORBIDDEN. Reads of public collections are not limited to the player's own documents. - With s&box authentication turned off (development), the Steam ID the client
sends is trusted as is, but the
accessModeandallowRecordDeleterules still apply.
Secret keys (dedicated servers, tools) count as trusted backend calls: they need
collections execute permission and may read, write and delete in any
collection without s&box tokens.
Error codes
The project's Logs and Errors tabs in the dashboard list rejected requests and explain them. The common ones:
| Status and code | Cause | Fix |
|---|---|---|
401 UNAUTHORIZED |
The API key is missing, wrong or disabled. | Check the public key passed to NetworkStorage.Configure. |
401 SBOX_AUTH_FAILED |
The project requires s&box authentication and the player's token was missing or did not verify. | Run the game through s&box, or turn off Require s&box authentication for development. |
403 ENDPOINT_ONLY |
The collection is not accessMode: public. |
Call it through an endpoint, or set accessMode: public. |
403 RECORD_DELETE_DISABLED |
The collection does not allow deletes from game clients. | Set allowRecordDelete: true, or delete through an endpoint. |
403 FORBIDDEN |
A player wrote another player's record, or a secret key lacks the permission. | Use the player's own key, or grant the permission on the secret key. |
404 |
The project, collection, endpoint or record does not exist. | Save or sync the definition and check the ID in the game code. |
409 STALE_SAVE |
A save was based on older data than the stored record. | Reload the record and retry. |
SAVE_NOT_CONFIRMED |
The client could not confirm a save reached the server. | Check the player's connection and the request log around that time. |
In the game, read the last error of an endpoint call by its slug:
var result = await NetworkStorage.CallEndpoint( "grant-coins", new { } );
if ( !result.HasValue )
{
NetworkStorage.TryGetLastEndpointError( "grant-coins", out var code, out var message );
Log.Warning( $"{code}: {message}" );
}
s&box hides the body of 4xx responses from game code, so the code there can be
HTTP_ERROR with the status in the message. The dashboard's Logs tab shows
the status for the same request.
On the server, sbox-ns logs -f follows the server log.
Client reachability
Whether s&box allows game clients to call a given kind of URL has not been tested yet against a self-hosted server. Every row below is untested. Please report what works for you in an issue so this table can be filled in.
| Server URL type | Example | Status |
|---|---|---|
| HTTPS domain | https://ns.example.com |
untested |
| HTTP domain | http://ns.example.com:8080 |
untested |
| IP address and port | http://203.0.113.10:8080 |
untested |
| localhost | http://localhost:8080 |
untested |
If plain HTTP or bare IP addresses turn out to be blocked by the s&box sandbox, put the server behind a reverse proxy with a real domain and a TLS certificate (see self-hosting.md).
Moving an existing project from the managed service
- Create the project and keys on your server with
sbox-ns project createandsbox-ns key create. - Point the editor Setup window at your server (above) and sync your
Editor/Network Storage/source files with the Sync Tool to recreate collections, endpoints and workflows. - Publish a new build of your game.
Player data stored on the managed service is not copied by syncing. Moving existing player records is not covered by this guide yet. The synced sources describe schemas and server-side logic, not player save files. Runtime records live in your server's SQLite or PostgreSQL database.
Players running an older build keep talking to whichever server that build was configured for.