Quickstart: scriptBeta

Create a scheduled script task that reads a page with Playwright, saves a screenshot and proposes a form submission for approval.

On this page

This guide creates a script task that opens a page every day, records what it sees and, when there is something to send, proposes a form submission that you approve from the dashboard.

Before you start

  • Access to OpenWAF Tasks. See get access.
  • A browser key of OpenWAF Browsers. The task's runs use it and count against its quota.
  • An organization-wide admin to create tasks and approve actions. Reading runs needs readonly.

1. Write the script

A script is an ES module that exports one async function. It gets a Playwright page (and context and browser) connected to the task's browser, and task:

task.…What it is
inputThe task's input JSON, set by you
stateJSON the script saved in the last run ({} the first time)
setState(value)Save JSON for the next run (up to 64 KiB)
log(message)A line in the run's logs
screenshot(name)Save a screenshot of the page as an artifact of the run
output(value)The run's output JSON (up to 64 KiB)
approve({summary, target, steps})Propose an action for a person to approve; see approvals
guestbook.mjs
export default async function ({ page, task }) {
  const { url, message } = task.input;
  await page.goto(url);
  await page.getByRole("heading", { name: "Guestbook" }).waitFor();
  await task.screenshot("before");

  const already = await page.getByText(message).count();
  task.log(`message on the page: ${already > 0}`);
  if (already > 0) {
    task.output({ posted: false, reason: "already there" });
    return;
  }

  // The browser is read-only here: clicking "Sign" would be blocked. Propose it instead.
  await task.approve({
    summary: `Sign the guestbook with "${message}"`,
    target: url,
    steps: [
      { op: "goto", url },
      { op: "fill", selector: "#name", text: "Example Inc." },
      { op: "fill", selector: "#message", text: message },
      { op: "click", selector: "#sign" },
      { op: "wait_for", text: message },
    ],
  });
  task.setState({ proposed_at: new Date().toISOString() });
  task.output({ posted: "pending approval" });
}

task.approve returns the approval id (a string) once the proposal is recorded; the action runs later, after approval, in a new browser. The script never sees whether it was approved: keep the id with task.setState so the next run does not propose the same action again, and read the approval or the page in the next run.

2. Create the task

  1. Open Tasks in the organization menu and choose New task, kind Script.
  2. Name it guestbook, pick the browser key, paste the script and set the input.
  3. Allowed domains: example.com. Schedule: 0 9 * * *, time zone Europe/Madrid.
  4. Save.

3. Run it now

Choose Run now on the task, or call POST /v1/orgs/{org}/tasks/{task}/run, or openwaf-cloud ctl tasks run guestbook --org acme --reason "First run". The answer is the run (202). Follow its logs with GET /v1/orgs/{org}/task-runs/{run}/logs?after=<seq>. While it runs, live_url lets you watch the browser.

When the script proposes the action, the run goes to awaiting_approval and the proposal appears in Tasks → Approvals.

4. Approve it

Open the approval. Check the summary, the target, every step and the screenshot, then choose Approve. From the API you send back the hash you saw:

curl -sS -X POST "https://dash.openwaf.dev/v1/orgs/$ORG/task-approvals/$APPROVAL/approve" \
  -H "Authorization: Bearer $OPENWAF_TOKEN" -H "Content-Type: application/json" \
  -d '{"payload_sha256": "9c1e…", "reason": "Text checked"}'

The runner replays the steps in a new browser, takes a final screenshot and stores the result in the approval. The run ends succeeded or failed.

Next steps

  • Approvals: every step type, the hash and the webhook.
  • Limits: per-domain limits that may delay an approved action.

Last updated:

↑↓ to navigate↵ to openesc to close