# Write JavaScript

Use the **Write JavaScript** building block to run custom code with the `zw` API. Your code runs inside the TaskBot runtime and can work with npm packages, variables and tables, state, device storage, and the browser context.

### What You Can Do

#### Imports and Package Management

Install, import, manage, and use npm packages. Use standard `import` statements or `zw.import(package, options)` for custom options.\
**API** `zw.import()`, `zw.packages.*`

```javascript
// @zw-run-locally

import dayjs from "dayjs@1.11.11"; // auto-installs if needed
await zw.log("now", dayjs().toISOString());

// Example with options — 'isolate' scopes the package to this TaskBot only
const lodash = await zw.import("lodash@4.17.21", { isolate: true });
await zw.log("chunked result", lodash.chunk([1, 2, 3, 4], 2));
```

**Reference:** [Imports and Package Management](/using-zerowork/using-building-blocks/write-javascript/imports-and-package-management.md)

***

#### Variables and Tables

Read from and write to variables and tables (native and Google Sheets).\
**API** `zw.getRef()`, `zw.setRef()`

```javascript
const email = await zw.getRef({ ref_id: 3623, name: "Email" });
await zw.setRef({ ref_id: 3624, name: "Email copy", value: email });
```

**Reference:** [Write and Read Variables and Tables](/using-zerowork/using-building-blocks/write-javascript/write-and-read-variables-and-tables.md)

***

#### Local and Global State

Store and use values for the current run (local state) or across runs (global state). Stays on this device; never sent to ZeroWork servers.\
**API** `zw.state.*`, `zw.globalState.*`

```javascript
// @zw-run-locally 

// Per-run local state, cleared when the run ends
const runState = zw.state.access();
runState.runStartedAt = Date.now();

// Shared Desktop Agent global state, cleared when Agent quits
const globalState = zw.globalState.access();
globalState.totalRuns = (globalState.totalRuns ?? 0) + 1;
```

```javascript
// In-browser snapshot (survives serialization)
const snapshot = await zw.state.browser.getCopy();
snapshot.runStartedAt = Date.now();
await zw.state.browser.commit(snapshot);
```

**Reference:** [Local and Global State](/using-zerowork/using-building-blocks/write-javascript/local-and-global-state.md)

***

#### Device Storage

Persist key–value data on this device. Survives restarts and reinstalls. Stays on this device; never sent to ZeroWork servers.\
**API** `zw.deviceStorage.*`

```javascript
const credentials = {
  username: await zw.deviceStorage.get("username_salesforce"),
  password: await zw.deviceStorage.get("password_salesforce"),
};
await zw.deviceStorage.set("last_login_salesforce", String(Date.now()));
```

**Reference:** [Device Storage](/using-zerowork/using-building-blocks/write-javascript/device-storage.md)

***

#### Utilities

Add delays and write logs.\
**API** `zw.delay()`, `zw.log()`, `zw.logTemp()`

```javascript
await zw.log("starting run");
await zw.delay({ min: 1500, max: 2500 });
```

**Reference:** [Utilities](/using-zerowork/using-building-blocks/write-javascript/utilities.md)

***

#### Browser and Context

Launch, quit, and manage the active browser context and pages.\
**API** `zw.browserContext.*`

```javascript
// @zw-run-locally

// Example (abridged). See the reference for all options.
await zw.browserContext.launch({
  launchConfig: {
    mode: "incognito", // or "sticky"
    bypassDetection: true,
    launchOptions: { headless: true /* proxy, executablePath, ... */ },
    contextOptions: { /* viewport, recordVideo, geolocation, ... */ },
    scripts: [],
    cookies: [],
    onContextReady: async (context) => {
      await context.route('**/*.{png,jpg,jpeg}', route => route.abort());
    },
  }
  // see the reference for the full list of options
});

const contextInfo = await zw.browserContext.getContextInfo();
await zw.log("context", contextInfo);
await zw.browserContext.quit();
```

**Reference:** [Browser Context](/using-zerowork/using-building-blocks/write-javascript/browser-context.md)

***

#### Metadata

Read TaskBot and ZeroWork Desktop Agent details.\
**API** `zw.getTaskbotInfo()`, `zw.getAgentInfo()`

```javascript
const taskbotInfo = await zw.getTaskbotInfo();
await zw.log("TaskBot name", taskbotInfo.name);
await zw.log("variables", taskbotInfo.variables);

const agent = zw.getAgentInfo();
await zw.log("agent version", agent.version);
```

**Reference:** [Metadata](/using-zerowork/using-building-blocks/write-javascript/metadata.md)

***

### **Local vs. Browser Execution**

Some methods only work when the code runs locally.

To run code locally, either enable the **Run locally** checkbox in the building block UI or include `// @zw-run-locally` anywhere in your code (top is recommended for visibility).

**Example**

```javascript
// @zw-run-locally
await zw.log("This runs locally now");
console.log("And this will no longer be visible in the browser console.");
```

* **Fully available in browser execution**
  * **Variables and tables** — `zw.getRef()`, `zw.setRef()`
  * **Device storage** — `zw.deviceStorage.*`
  * **Utilities** — `zw.delay()`, `zw.log()`, `zw.logTemp()`
  * **Metadata** — `zw.getTaskbotInfo()`, `zw.getAgentInfo()`
* **Available in browser with limitations**
  * **Imports and package management** — `zw.import()`, `zw.packages.*` \
    Installing and managing packages is only available when running locally; using already imported packages is supported in the browser — see how [**here**](/using-zerowork/using-building-blocks/write-javascript/imports-and-package-management.md#how-to-use-imported-packages-in-the-browser).
  * **Local and global state** — `zw.state.*`, `zw.globalState.*` \
    Access to the live mutable object via `*.access()` is **only** available locally. In the browser, you can get a snapshot with `*.browser.getCopy()` and save state with `*.browser.commit()` — see how [**here**](https://docs.zerowork.io/using-zerowork/using-building-blocks/pages/DI5u1TjzGfw12nL7h8V2#id-3.-use-state-in-the-browser-zw.state.browser.-and-zw.globalstate.browser).\
    The clear method `*.clear()` is available in both local and browser execution.
  * **Browser context** — `zw.browserContext.*`\
    Largely unavailable in browser execution. Only inspection methods `zw.browserContext.getContextInfo()` and `zw.browserContext.getDefaults()` are supported in the browser.

***

### **Using the `zw` APIs in No-Code Blocks**

You can use the `zw` APIs in no-code blocks, too, either as expressions `${...}` or as code blocks with `return` statements `$${...}`.

**Example**

<div align="left"><figure><img src="/files/cDz3BYs78HKmJahGa77p" alt=""><figcaption></figcaption></figure></div>

**Reference**:  [Code in Inputs](/using-zerowork/using-building-blocks/dynamic-inputs/code-in-inputs.md)

***

### Error Handling

Thrown errors are automatically saved to **Error Reports** in **Run Reports** (see [Using Run Reports](/using-zerowork/using-run-reports.md)). Notifications, if enabled, then follow your error run notification settings (by email, Slack, or a custom webhook). This is a useful way to generate custom errors and get notified automatically.

**Example**

```javascript
throw new Error(
  "Test error to verify Error Reports in Run Reports"
);
```

**Resulting error report**

<div align="left"><figure><img src="/files/RRdPa4Oh1QmCqT6rCK7B" alt="" width="563"><figcaption></figcaption></figure></div>

Thrown errors can also be caught by the **Try-Catch** building blocks, see: [Try-Catch](/using-zerowork/using-building-blocks/try-catch.md).

***

### Notes

* Old API `log()`, `delay()`, `setRef()`, and `getRef()` (without the `zw.` prefix) still work. We recommend the new convention `zw.*` (e.g., `zw.getRef()`), but your current code will continue to run. Existing `activePage` and `taskbotContext` will also continue to work, although they're now discouraged — prefer `zw.browserContext.getActivePage()` and `zw.browserContext.getContext()`.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.zerowork.io/using-zerowork/using-building-blocks/write-javascript.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
