# Utilities

Add delays and write logs.

**API** `zw.delay()`, `zw.log()`, `zw.logTemp()`

```js
await zw.log("Starting run");
await zw.delay({ min: 1500, max: 2500 }); // randomized delay 1.5–2.5s
```

***

#### At a Glance

* <mark style="color:$info;">async</mark>\
  `await zw.delay({ min: number, max?: number })` \
  → pauses for `min` (ms). If `max` (ms) is provided and `max > min`, the delay is randomized between `min` and `max`.
* <mark style="color:$info;">async/sync\*</mark> \
  `await zw.log(...values: any)` \
  → like console.log, logs comma-separated values.
* <mark style="color:$info;">async/sync\*</mark> \
  `await zw.log({ message: any, status?: "success" | "fail" | "warning", tag?: string })` \
  → logs with custom styling.
* <mark style="color:$info;">async/sync\*</mark> \
  `await zw.logTemp(...values: any)` \
  `await zw.logTemp({ message, status?: "success" | "fail" | "warning", tag?: string })`\
  → same as `zw.log()` but not persisted to Run Reports.

\*`async` in browser, `sync` locally (see [Broken link](https://docs.zerowork.io/using-zerowork/using-building-blocks/write-javascript/broken-reference "mention")).

***

#### **Examples**

**Structured status logs (styled in the UI)**

```js
await zw.log({ message: "Logged in", status: "success", tag: "auth" });
await zw.log({ message: "Slow response detected", status: "warning", tag: "network" });
await zw.log({ message: "Failed to submit form", status: "fail", tag: "checkout" });
```

**Log objects, arrays, and functions — no manual stringify needed**

```js
const payload = { id: 42, items: [1, 2, 3] };
const helper = (x) => x * 2;
await zw.log("Logging objects, arrays, functions", payload, helper);
```

**Exact wait with only `min`**

```js
await zw.delay({ min: 1000 }); // exactly 1s, no randomized delay
await zw.log("Waited for exactly 1s");
```

**Dynamic backoff based on state**

```js
// @zw-run-locally

const state = zw.state.access();
state.retryCount = (state.retryCount ?? 0) + 1;
const backoffMs = Math.min(5000, 500 * state.retryCount);

await zw.log("Retry:", state.retryCount, "waiting:", backoffMs);
await zw.delay({ min: backoffMs });
```

**Live-only logging of secrets (never persisted to Run Reports)**

```js
const token = await zw.deviceStorage.get("auth_token");
await zw.logTemp("Auth token received", token);

// Structured live-only (styled in running log)
await zw.logTemp({ message: token, status: "warning", tag: "debug_auth" });
```

**Try/catch with styled fail log**

```js
try {
  // do something that may throw
} catch (err) {
  await zw.log({ 
    message: `Action failed: ${err?.message}`,
    status: "fail",
    tag: "custom_code_error"
  });
  throw err;
}
```

***

#### Notes

* **Size limits.**\
  The **persistent** message saved to Run Reports is capped at **\~500 characters**. The **running** log view shows up to **\~500,000 characters** per message. Longer inputs do not throw an error but are truncated.
* **Delay always requires `await`.**\
  `zw.delay()` is async and must be awaited in both local and browser execution.
* **Log async behavior.**\
  In the browser, `zw.log()` and `zw.logTemp()` are async — use `await`. When Write JS code runs locally, `await` is optional (the examples use `await` for consistency).
