Cloud variables & requests
A logged-in session can open a project's cloud connection — the same
WebSocket the Scratch player uses — to set and read ☁ variables in real time,
listen for changes, or run a cloud-requests server: a Scratch project sends
named requests with arguments, and your code answers over the cloud.
The request/response wire protocol is byte-for-byte compatible with
scratchattach, so a project built
for its requests sprite works against s-api4js unchanged.
Connecting to Scratch's cloud requires login and the
ws package (a dependency of s-api4js).
Reading the public log does not.
Setting and reading variables
session.cloud(id) fills in the auth cookie, username and origin for you. Set a
variable with setVar — values must be numeric and at most 256
characters unless you opt out:
Sets are queued and rate-limited (default one per 0.1 s) so you won't trip
Scratch's limits. To allow text values, pass allowNonNumeric:
Reading the log without a connection
The cloud-data log is public, so logs() works logged out — handy for reading
recent activity or the requester behind a change:
TurboWarp & custom servers
Everything on this page — variables, requests, storage and events — works against any cloud server, not only Scratch's. There are three ways to connect:
A logged-out session can open a non-Scratch host too:
new ScratchSession().cloud(id, { host: 'wss://…' }) skips the login check and
sends no Scratch cookie.
Two differences off Scratch: values can be far longer — TurboWarp raises the cap
to 100 000 chars (Scratch's is 256), though both servers still accept numbers
only — and there's no log API, so cloud.logs() is Scratch-only and
cloud.events() listens on the WebSocket instead of polling.
Cloud requests
Build a request server on the same connection with cloud.requests(). Register
handlers by name; each receives the decoded string arguments (an array) and
a context, and returns what to send back:
A handler returns:
- a string — encoded and sent back (chunked if it's long);
- a number — sent efficiently when the request allows it;
- an array of strings — delivered as a list.
The context is { name, args, requestId, requester }. The WebSocket stream
doesn't carry the requesting username, so requester is null; resolve it from
cloud.logs() if you need it.
How it works on the wire
The Scratch project writes an encoded request to ☁ TO_HOST and reads the
answer from ☁ FROM_HOST_1 … ☁ FROM_HOST_9. Because cloud values are numeric
and capped at 256 characters, text is encoded to digits and split
across as many packets as needed; the server cycles through the FROM_HOST_n
variables and can re-send a dropped packet on request. All of this is handled
for you — you just register handlers.
You can customize the variable names if your project differs from the default:
Cloud storage
A cloud storage server is a cloud-requests server with a fixed set of
requests — get, set, keys, database_names, ping — backed by one or
more databases. It speaks scratchattach's Cloud Storage protocol, so its
companion Scratch project works unchanged. Build one with cloud.storage() and
register databases:
The project can now set (scores, key, value), get (scores, key) and list
keys (scores) over the cloud.
Choosing a database
A database is any object with name, get(key), set(key, value) and keys()
(async or sync). Three adapters are bundled:
SqlDatabase ships no driver — you pass a small query(sql, params)
function wrapping the client you already use, and the adapter writes the
dialect-appropriate SQL (placeholders, upsert) and creates the two-column table
(k, v) on first use. query must resolve to an array of row objects.
Options: table (default cloud_storage), keyType / valueType, and
ensureSchema (set false to manage the table yourself).
Cloud events
To watch a project's cloud activity — including who changed a variable and
variable create/delete, neither of which the live socket reports — poll its
public log with cloud.events(). Because it reads the log, it works without
login:
start() seeds its cursor from the current log, so only future activity
fires. Each activity event receives { user, verb, name, value, timestamp }.
interval is the poll period in seconds (default 1).
cloud.events() has two sources, auto-selected by host:
logs(default on Scratch) — the log-polling above; reports the user andcreate/delete.websocket(default on TurboWarp/custom servers, which have no log API) — listens on the live connection. Instant, but onlysetfires, with no user or timestamp.
Override with cloud.events({ source: 'websocket' }). For one-off change
notifications you can also use the set event on the
connection directly.
Encoding
The text ⇄ digits scheme is exported in case you need it directly. It matches scratchattach's table and the companion Scratch decoder sprite:
Each character becomes its two-digit index in a fixed table; unknown characters become a space.