Local and Global State (upcoming)
Available in version 1.1.72 (not yet live).
Store values for the current run (local state) or across runs on the same Desktop Agent (global state).
API zw.state.*
, zw.globalState.*
// @zw-run-locally
// Local per-run state — cleared automatically when the run ends
const runState = zw.state.access();
runState.runStartedAt = Date.now();
// Shared Desktop Agent global state — persists across runs on this device
const globalState = zw.globalState.access();
globalState.totalRuns = (globalState.totalRuns ?? 0) + 1;
// In the browser — work with a JSON-safe snapshot of local or global state
const runStateCopy = await zw.state.browser.getCopy();
runStateCopy.lastSeenAt = Date.now();
await zw.state.browser.commit({ state: runStateCopy });
1. Local Per-Run State — zw.state.*
zw.state.*
A per-run scratchpad automatically initiated on run start. It is deleted when the run ends.
At a Glance
zw.state.access()
→ a live mutable object you can read and update anywhere in the run. It can hold anything (e.g., helpers, counters, functions, Maps, Playwright objects like pages or contexts, etc.). It's deleted automatically when the run ends. It is not available in the browser (see Use state in the browser below).zw.state.clear()
→ clears the whole run state.
Examples
// @zw-run-locally
// Add a type-safe validator and stringifier around zw.setRef()
zw.state.access().setRefSafely = ({ ref_id, name, value }, expectedType) => {
if (typeof value !== expectedType) {
throw new Error(`Value for ${name} is not ${expectedType}`);
}
const valueStr = typeof value === "string"
? value
: value
? JSON.stringify(value)
: "";
zw.setRef({ ref_id, name, value: valueStr });
};
// Use the helper in later blocks within the same run
zw.state.access().setRefSafely({ ref_id, name: "age", value: 42 }, "number");
// @zw-run-locally
// Counters or flags across multiple Write JS blocks in the same run
const runState = zw.state.access();
runState.processed = (runState.processed ?? 0) + 1;
await zw.log("processed", runState.processed);
// Clear mid-run if needed
zw.state.clear();
2. Global State — zw.globalState.*
zw.globalState.*
A device-level scratchpad shared across runs on the same Desktop Agent. Persists between runs until the desktop agent quits or restarts. Use it when you need to reuse something across runs on one machine (e.g., cached tokens, a counter of all runs, etc.).
At a Glance
zw.globalState.access()
→ a live mutable object you can read and update across runs. It is not available in the browser (see Use state in the browser below).zw.globalState.clear()
→ clears the whole global state.
Example
// @zw-run-locally
// Track which TaskBots ran today (per device)
const gs = zw.globalState.access();
const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
if (!gs.botsThatRanToday || gs.botsThatRanToday.date !== today) {
gs.botsThatRanToday = { date: today, bots: [] };
}
const taskbotInfo = await zw.getTaskbotInfo();
gs.botsThatRanToday.bots.push(taskbotInfo.id);
Notes
It is not durable storage. It is lost when the Desktop Agent quits or restarts. For durable data use:
Variables/tables via
zw.getRef()
/zw.setRef()
Device storage via
zw.deviceStorage.*
As long as the Desktop Agent isn't quit or restarted, global state is not auto-cleaned. Clear what you no longer need.
3. Use State in the Browser — zw.state.browser.*
and zw.globalState.browser.*
zw.state.browser.*
and zw.globalState.browser.*
In the browser you cannot use *.access()
. Use JSON-safe snapshots instead.
At a Glance
await zw.state.browser.getCopy({ key? })
await zw.globalState.browser.getCopy({ key? })
→ returns the current state (or the section underkey
).await zw.state.browser.commit({ state, key? })
await zw.globalState.browser.commit({ state, key? })
→ accepts any serializable value. Ifkey
is provided, only that section is updated.
Examples
// Whole snapshot
const stateCopy = await zw.state.browser.getCopy();
stateCopy.step = (stateCopy.step ?? 0) + 1;
await zw.state.browser.commit({ state: stateCopy });
// Section-only snapshot with 'key'
const prefs = (await zw.state.browser.getCopy({ key: "prefs" })) ?? {};
prefs.theme = "dark";
await zw.state.browser.commit({ key: "prefs", state: prefs });
Notes
JSON-safe only when using
*.browser.getCopy()
or*.browser.commit()
Snapshots must be JSON-safe. Functions, Maps, circular references, and similar types cannot be serialized for browser use. If your state contains such values, usekey
to fetch only a JSON-safe section that you need in the browser.In-browser snapshot size limits Passing snapshots larger than ~3,000,000 characters fails. If your state is large, use
key
to work with just a section. Serialization of smaller objects is also faster.In-browser calls require
await
In the browser,*.browser.getCopy()
,*.browser.commit()
, and*.clear()
are async.// 🚫 Won't work const stateCopy = zw.state.browser.getCopy(); // missing await stateCopy.runData = {}; // throws because stateCopy is a Promise await zw.state.browser.commit({ state: stateCopy }); // this line never runs // ✅ Works const stateCopy = await zw.state.browser.getCopy(); stateCopy.runData = {}; await zw.state.browser.commit({ state: stateCopy });
*.browser.*
scope is reserved for the browser onlyzw.state.browser.*
is meant for the browser context. In local runs, just usezw.state.access()
and make a copy yourself if needed:// @zw-run-locally const s = zw.state.access(); const shallowCopy = { ...s };
Last updated
Was this helpful?