Skip to main content
Most Automation Tasks start from a prompt or demonstration. Code Tasks are for authoring automation directly — as TypeScript you upload with the SDK, or as workflow JSON you edit by hand when you need precise control.

Overview

Code Tasks cover two related paths: For the standard create-from-prompt or demonstration flow, start with Creating a Task and Run a Task. Use this page when you are writing or editing code yourself.

Writing TypeScript task code

For reliable execution, follow these guidelines:
  • Write your code in TypeScript.
  • Export a single default async function.
  • In that function, return whatever your workflow requires as output (e.g., status, messages, domain data).
Tasks can receive values as inputs. All input names must be prefixed with ANCHOR_

Basic Task Example

Using the SDK

Upload and run a TypeScript Code Task with the v1 Tasks SDK:
1

Save your typescript code as a .ts file

Make sure it follows the guidelines from above.
2

Get the base64 version of the file

Run the script to show your base64 file version
terminal
Copy the output for later.
3

Create your Code Task in Anchor

4

Run the Code Task

By default, the browser session is automatically closed when the task ends. Set cleanupSessions: false to keep the session open after task execution.
Running a task with inputs
5

Deploy the Code Task

For long-running TypeScript task runs, see Async execution.

Support

For additional help with Code Tasks:

Manually editing workflow JSON

Use this when you already have an Automation Task and need to edit the underlying workflow document via API — for example after self-healing produces a draft, or for changes too detailed for the UI editor. See Automation Tasks Overview for the equivalent workflow in the dashboard.
A workflow is a JSON document describing an ordered graph of segments that run against a browser session. Each segment can run deterministic Playwright code, an AI agent, or both. Segment outputs flow forward by parameter name into a shared state, and the workflow’s final output is read from that state at the end. This section covers the JSON schema for hand-editing and the API flow for saving and publishing those edits.

API process for editing a workflow

1

Get the task ID

Use the task_id returned when you created the task, or from a completed demonstration status response.
2

Read the current workflow JSON

The code field is base64-encoded. Decode it to get the raw workflow JSON.
3

Edit and save as draft

Edit the decoded JSON using the schema reference below, re-encode it to base64, then save:
4

Publish the draft

Top-level shape

Parameter

A minimal parameter is { "name": "...", "type": "..." } — the rest take their defaults.
Use secret for credentials, tokens, API keys. Use file for user-uploaded attachments — declare it as a workflow input, reference it as {{parameter_name}} in prompts and parameters.parameter_name in deterministic code. Do not use string for binary uploads.

Segment

A segment only sees parameters it declares in inputParameters. The shared state is global, but the segment’s parameters object at runtime contains only the values the segment opted into. If you forget to declare an input, parameters.foo is undefined, even if an earlier segment produced foo.

Segment types

Rules of thumb:
  • Default to ui. Reach for network only when the response payload is the source of truth (the user said “from API”, or UI parsing is brittle).
  • Use logic when you specifically want no AI fallback — for example, throwing “no results” errors or post-filter validation.
  • Use agent when deterministic code can’t reliably encode the decision.

deterministic

deterministic is a JSON string containing a stringified async arrow function — not a live function. Two valid signatures:
  • page is a Playwright page bound to the active session.
  • parameters contains all declared inputParameters for this segment.
  • networkResponses (network segments only) — see Network segments below.
  • The function must return an object — use {} if there are no outputs.
  • Throw on missing/invalid required values; never return null placeholders.
Because the function is serialized as a JSON string, escape internal double quotes and keep it on a single line. For example, the function body await page.goto('https://example.com'); return {}; becomes:

prompt

Plain English for the AI agent. Reference parameters as {{parameter_name}} for runtime substitution. Describe the goal in terms of logical actions, not selectors:
  • "Search Amazon for {{search_query}} and submit."
  • "Click button[aria-label=Search], fill input#q, press Enter."
For ui/network segments, the prompt is also used as AI fallback if the deterministic step throws — write it as if it might run on its own.

next and router

  • Linear: "next": "next_segment".
  • Terminal: "next": null (workflow ends after this segment).
  • Branching: "next": ["segment_a", "segment_b"] plus "router": "(parameters) => parameters.x ? 'segment_a' : 'segment_b'".
The router function receives only this segment’s outputParameters (its own output object), not the merged shared state. If you want to route on a value, that value must be declared as an outputParameter of the same segment whose router reads it.

Data flow

State is a single flat map keyed by parameter name. After a segment runs, its outputParameters are merged into that map and made available to every later segment whose inputParameters declare the same name. The workflow’s outputParameters are read from the same map at the end. Implications:
  • Two segments with the same output name overwrite each other.
  • A segment only reads parameters it explicitly declares in inputParameters — declaring an input is opt-in even though the underlying state is shared.
  • A router only reads its own segment’s outputs — see the warning above.
  • If a downstream segment treats an input as required: true, the producing segment’s output should also be required: true, and its deterministic code must throw (not return null/empty) when the value is unavailable.
  • Demonstration values and static URLs belong inside the prompt, not as parameters.

Network segments

For type: "network" segments, the deterministic function receives a third argument — networkResponses — containing all responses recorded during the session. Each entry has fields like requestUrl, method, status, headers, and a body. The body field name varies by recorder version, so always read it with the canonical fallback:
Match responses with stable predicates (pathname/method/status), not full URL string equality:
Do not use page.waitForResponse inside a workflow segment — networkResponses is the deterministic source of truth.

Reliability patterns

These are the highest-leverage rules for hand-written deterministic code.

Split navigation from interaction

Always put page.goto(url) in its own segment. Element waits, fills, and clicks belong in the next segment.
  • nav_open_and_fill_search — navigation + interaction in one segment
  • nav_to_search_pagefill_search_form
The page load is handled automatically by the browser; do not call page.waitForLoadState('networkidle') after page.goto. The next segment handles waiting for specific elements to appear. Splitting them makes segments reusable and resilient to timing issues.

Click and input stability

For any element that may be off-screen or in a virtual list, use the canonical pattern:
  • state: 'attached' waits for DOM presence even when the element is off-screen. The default state: 'visible' breaks on virtual lists.
  • For text inputs (input, textarea, contenteditable), click/focus first, then fill() or type().

Selector quality

Prefer stable attributes in this order: data-testidaria-labelname → semantic role + text. Scope selectors to a relevant region before text matching; avoid global .first() unless uniqueness is guaranteed.

Optionality (the most common gotcha)

The schema validator accepts undefined (i.e. a missing key) for optional fields, not null. An AI agent producing structured JSON tends to emit "field": null for “absent”, which fails validation — especially for optional fields with options (enums). Three patterns that work: 1. Route around it. Declare the optional value as an outputParameter of the segment whose router will read it, so the router can branch before the consuming segment ever runs. The consuming segment can then treat the input as required.
Note that parameters.estimation here refers to this segment’s own output, which is what the router receives. 2. Add an explicit “none” option. For optional enums, include a sentinel like "none" in options and make the field required: true. The agent will pick "none" instead of null. 3. Omit the key. If you control the deterministic code, return {} (omit the key entirely) instead of { field: null }.

Identity-linked workflows

When an identity is attached to the workflow, the platform pre-authenticates the session before the workflow runs. In that case:
  • Do not declare username, password, otp_code, totp_secret, mfa_code, login email, or any other auth credential as an inputParameter.
  • Do not add login segments to the workflow — login is handled before your first segment runs.
  • Treat any login actions you saw during recording as pre-conditions performed by the platform, not as part of the user’s task.
  • Only declare business-logic parameters the user actually needs to provide at runtime (e.g. report_name, invoice_number, search_query).

Authoring checklist

  • Every segment has a type.
  • logic segments have prompt: null and a non-null deterministic.
  • agent segments have deterministic: null and a comprehensive prompt.
  • Every value referenced in a router is declared as an outputParameter of the same segment as the router.
  • Every value a segment uses is declared in its inputParameters.
  • Required downstream inputs come from required upstream outputs; deterministic code throws instead of returning null for them.
  • Optional values are handled by routing, an explicit "none" option, or by omitting the key — not by emitting null.
  • Prompts use {{parameter_name}} for dynamic values; static URLs and demonstration values are embedded in the prompt, not declared as parameters.
  • secret for credentials/tokens; file for user-uploaded attachments.
  • Navigation segments do page.goto only — element waits and interactions live in the next segment.
  • next: null only on terminal segments; otherwise a single string or an array paired with a router.
  • deterministic is a JSON string with quotes escaped, on a single line.
  • If an identity is attached, no auth credentials are declared as parameters.

Complete example

A two-input, two-output workflow that searches Amazon and extracts the first result.