Action reference¶
The complete vocabulary a .webtask recipe understands. Every action is listed
here with its parameters, defaults, output shape, and an example. This is the
detailed companion to the condensed table in Recipes.
A step is one action. An optional status "…" line before a step sets the
live progress message SSE callers see; some actions open a block closed with
end:
status "Human text" # optional: emitted as an SSE status event
goto "https://example.com" # a simple step
record clip path "/tmp/run.gif" # a block action…
goto "https://example.com" # …child steps run inside
click "#more"
end
Conventions in the tables below:
- A param written
name?=defaultis optional with that default;namewith no=is required (or the step errors). - "Output" describes what a step's result name receives, and is also what
lands in the response
data. Most capture actions accept apath(write to disk), a result name (return inline), or both. - Param values are templated first — see Templating.
Table of contents¶
- Navigation & timing
- Input & interaction
- Scrolling
- JavaScript
- Extraction
- Rendering & capture
- Recording
- Network & session
- Downloads & blob capture
- Control flow
- Values & data
- Filesystem
- Events
- How results are stored
Navigation & timing¶
goto¶
Navigate the window to a URL.
| Param | Notes |
|---|---|
url |
Absolute URL. Templated, so {{q}} etc. work. |
wait¶
Sleep for a fixed duration. Use sparingly — prefer wait until / wait-network-idle.
| Param | Notes |
|---|---|
| duration | Milliseconds. |
wait until¶
Block until a selector is present in the DOM.
| Param | Notes |
|---|---|
| selector | CSS selector to wait for. |
timeout?=10000 |
Fail with a timeout error if it never appears. |
wait until matches DOM presence, not "data loaded". For SPAs that render a
skeleton first, wait for the loaded state (e.g. .results .item:not(.loading)).
Input & interaction¶
sendkeys¶
Focus an element and type text into it.
| Param | Notes |
|---|---|
| selector | The field to type into. |
keys |
The text to type (templated). |
click¶
A native, trusted click via CDP — works on sites that gate handlers on
isTrusted, unlike JS-dispatched events.
| Param | Notes |
|---|---|
| selector | Element to click (or to match by text when text is set). |
text? |
When set, click the first selector whose visible text matches. |
match?=exact |
exact or contains — only with text. |
closest? |
After matching by text, retarget the click to that element's nearest matching ancestor. Pattern: match a label, click its row. |
Click the first match of a selector:
Click by visible text, retargeting to a row ancestor:
Scrolling¶
scroll until stable¶
Repeatedly scroll a container and stop once its scrollHeight stops changing —
the standard way to exhaust infinite-scroll feeds and chat history.
| Param | Notes |
|---|---|
| selector | The scrollable container. |
direction?=up |
up (loads older content) or down. |
stable?=1500 |
Exit once height has been unchanged for this many ms. |
max?=0 |
Cap the number of scroll steps. 0 = unbounded. |
JavaScript¶
js¶
The escape hatch: evaluate JavaScript in the page. args become its arguments
array; the return value becomes the result. Prefer dedicated actions; reach for
js only when no action fits.
| Param | Notes |
|---|---|
fn? |
Name of a JS module under the bundle's scripts/ (.js optional). |
script? |
Inline JS source. |
args? |
List passed to the page as arguments. |
await?=false |
When true, the script runs async and a returned Promise is awaited. |
A module (fn) or inline script is required.
Inline form:
See Writing tasks for the module-vs-inline trade-off.
Extraction¶
extract¶
Turn rendered HTML into typed JSON via a CSS-selector field spec — the most-used action.
| Part | Notes |
|---|---|
| name | Where the result is stored. |
from "SEL" |
The row(s) to harvest. |
repeat |
Present → one object per match (a list); absent → one object. |
| field lines | One per field (below), closed with end. |
Field lines:
| Line | Captures |
|---|---|
name text "SEL" |
Trimmed text content. |
name text "SEL" trim |
Text, explicitly trimmed. |
name attr ATTR on "SEL" |
An HTML attribute (e.g. href). |
name html "SEL" |
Inner HTML. |
name const "VALUE" |
A literal constant tagged onto every record. |
extract repos from "article.Box-row" repeat
slug text "h2 a" trim
href attr href on "h2 a"
description text "p"
source const "github-trending"
summary html ".desc"
end
With repeat, the result is a list of objects; without it, one object.
Rendering & capture¶
All capture actions accept a path (write to disk) and/or a result name (return
base64 / a {path,size,bytesB64} map). At least one is required. See
How results are stored.
screenshot¶
| Param | Notes |
|---|---|
selector?=. |
. → viewport; a selector → that element only. |
fullPage?=false |
Capture the whole scrollable page. |
format?=png |
png or jpeg. |
quality? |
JPEG quality 0–100. |
pdf¶
Render the current page to PDF.
| Param | Notes |
|---|---|
format? |
A4, A3, Letter, Legal. |
landscape?=false |
Orientation. |
printBackground?=true |
Print background graphics. |
scale? |
Render scale. |
pageRanges? |
e.g. "1-3,5". |
html-to-pdf¶
Render an HTML string (or file) to PDF — no live page needed. Accepts all the
pdf options above.
| Param | Notes |
|---|---|
html? |
Inline HTML source. |
file? |
Path to an HTML file (used when html is absent). |
css? |
CSS injected as a <style> prelude. |
html-to-pdf doc file "/tmp/report.html" css "body{font-family:sans-serif}" format A4 path "/tmp/report.pdf"
snapshot¶
Capture an MHTML single-file archive (HTML + CSS + images inlined).
emulate¶
Override device metrics and emulated media. The override persists on the window until reset.
| Param | Notes |
|---|---|
width?, height? |
Viewport dimensions. |
deviceScaleFactor?=1 |
DPR. |
mobile?=false |
Mobile emulation. |
colorScheme? |
light / dark / no-preference. |
reset?=false |
Clear all overrides. |
Recording¶
record¶
Screencast the page while the block's children run, then encode to an animated
GIF (pure Go) or MP4 (needs ffmpeg). A run that fails is still encoded and
saved — exactly the run worth inspecting.
| Param | Notes |
|---|---|
format?=gif |
gif or mp4. |
fps?=5 |
Frames per second. |
quality?=80 |
Encoder quality. |
maxFrames?=300 |
Hard cap on frames. |
maxDurationMs?=30000 |
Hard cap on wall-clock. |
path? |
Write the media to disk. |
At least one of path / a result name is required.
Step-level recording. Any step can carry record to screencast just that
one step (a GIF under $TMPDIR/webtasks-recordings/); if the step fails, the
error names the file. A debug aid, no block needed.
Network & session¶
capture-network¶
Record request/response entries (HAR-ish) while the block's children run.
| Param | Notes |
|---|---|
includeBodies?=false |
Capture response bodies. |
maxBodyBytes?=65536 |
Truncate bodies past this size. |
urlFilter? |
Only record URLs containing this substring. |
console¶
Collect console.* messages while the block's children run.
wait-network-idle¶
Block until in-flight requests stay quiet.
| Param | Notes |
|---|---|
idle?=500 |
Required quiet window (ms). |
timeout?=15000 |
Give up after this long. |
maxInflight?=0 |
Treat ≤ this many requests as "idle". |
get-cookies¶
Read cookies into the result (name, value, domain, path, expires, httpOnly,
secure, sameSite).
| Param | Notes |
|---|---|
urls? |
List of URLs to scope to (omit for all). |
path? |
Write the cookie list as JSON to disk. |
set-cookies¶
Install cookies — useful for importing a session. Reads from inline cookies or a JSON file.
http-get / http-post¶
An outbound HTTP call with no browser involved. Result:
{status, headers, body, json?} — json is present when the body parses as
JSON.
| Param | Notes |
|---|---|
| url | Target URL. |
headers? |
Map of header → value. |
body? |
String, or a map/list (marshalled to JSON). |
timeout?=30000 |
Request timeout. |
Downloads & blob capture¶
download-each¶
Native-click every match of selector in DOM order. Chrome saves each download
to the per-window directory; the action polls for each new file and returns its
path. Result: [{path, basename}, …].
| Param | Notes |
|---|---|
| selector | Elements to click. |
timeout?=30000 |
Per-file poll timeout. |
The CDP download-behaviour call is already wired into the window factory, so headless Chrome doesn't block downloads.
save-captures-to-dir¶
For apps that decrypt blobs client-side and never trigger a real HTTP download
(Concio, ProtonMail-style). After an in-page URL.createObjectURL hook has
buffered captures, this drains the ready ones to disk. Result:
[{path, basename, size, mime, name, url}, …].
| Param | Notes |
|---|---|
| dir | Server-side output directory. |
naming?={id}_{name} |
Filename template. Tokens: {id} {name} {ext} {mime} {size} {ts}. |
The full pattern (install hook → click files → wait → drain) is in Recipes.
Control flow¶
for-each¶
Iterate a list, running the block once per item with a cloned bindings map.
| Part | Notes |
|---|---|
item in "{{ref}}" |
A single-token ref resolves to the raw list. |
as?=item |
Name bound to the current item. {{<as>_index}} holds the 0-based index. |
continueOnError? |
When set, a failing iteration emits an error event and the loop continues. |
for-each chat in "{{chats}}" continueOnError true
emit status "Processing {{chat.peerName}} ({{chat_index}})"
end
loop¶
A generic loop driven by a JS condition, re-evaluated each iteration.
| Part | Notes |
|---|---|
while js "EXPR" |
Loop while truthy. |
until js "EXPR" |
Loop until truthy. |
while fn "MODULE" / until fn "MODULE" |
A JS module instead of an inline expression. |
pause?=1000 |
Pause between iterations (ms). |
max?=1000 |
Safety cap. |
A bare expression is auto-wrapped. emit in the body streams progress to an SSE
caller.
call¶
Run another registered task's flow in the current window with the current bindings — factor a reusable flow.
return¶
Set the task's response payload to value alone and stop the remaining steps.
Without a return, the full output map is returned.
Values & data¶
set¶
Assign a literal or templated value to a binding/output. The value renders to whatever type it is — string, list, map, number.
export¶
Render a list/map of records into CSV, NDJSON, or a markdown table.
| Param | Notes |
|---|---|
| format | csv, ndjson, or md (markdown table). |
| data | The records (list of maps, or a single map). Usually "{{ref}}". |
columns? |
Explicit column order. Defaults to the sorted union of keys. |
path? |
Output path. |
Filesystem¶
read-file¶
Read a file into the result (as a string).
| Param | Notes |
|---|---|
| path | File to read. |
optional?=false |
When true, a missing file yields "" instead of erroring. |
write-files¶
Store many files at once, creating parent directories as needed. Result:
{count, root, files: [{path, size}, …]}.
| Param | Notes |
|---|---|
| root | Base directory. Each file's path is joined under it (no traversal). |
| files | List of {path, content} or {path, bytesB64}. Usually "{{ref}}". |
save-html¶
Write an element's outerHTML to disk.
| Param | Notes |
|---|---|
selector?=. |
. = whole document. |
| path | Destination file. |
Events¶
emit¶
Emit a custom progress event — visible to SSE/WebSocket callers, a no-op for sync REST.
| Part | Notes |
|---|---|
| kind | status, progress, or anything. |
| text | Human-readable message (templated). |
data? |
Arbitrary structured payload. |
See the HTTP API for the SSE event protocol.
How results are stored¶
Result names and path interact consistently across actions:
- Data actions (
extract,js,http-get,set,for-eachresults,write-files, …) store their result under the given name in both the responsedataand the live bindings. No name → the result is discarded. - Capture actions (
screenshot,pdf,html-to-pdf,snapshot,record,export,capture-network,get-cookies) accept:pathonly → written to disk, nothing bound.- a result name only → returned inline (base64 for binary, text for
export). - both → written to disk and bound as a
{path, size, bytesB64}map (binary) or the text (export). - At least one is required, else the step errors.
returnsets the reserved result. When present, the HTTP responsedatais that value alone, not the full output map.
A param whose entire value is a single {{ref}} token resolves to the raw
bound value (list/map/number), not its stringified form — that's how
for-each chat in "{{chats}}" and write-files files "{{built.files}}" receive
real structured data. → Templating