Automation Guide

Automation lets you create browser automation scripts that run on your desktop. You can build automations in three different modes, choosing what works best for your automation:

  • Steps Mode — Configure individual actions (Click, Fill, Navigate, Wait, etc.) in a visual interface
  • Script Mode — Write a script with variables, loops, conditionals, and functions
  • Browser Script Mode — The same automation language in browser mode, for HTTP API automation and integration with external APIs

Requirements

Nocarta Desktop App Required

Automations execute browser automation using Playwright. For security and functionality, this runs on your desktop computer, not on the server.

Download Nocarta Desktop | Setup Guide


Automation Assistant

The Automation Assistant is your conversational helper for creating and testing automations. Open it from any automation page or the automations list.

Two Ways to Use It

Mode What It Does AI Required?
Direct Commands Execute immediately - open pages, navigate, record actions, take screenshots No
Smart Commands Understand natural language - find elements, click buttons by description, answer questions Yes

Nocarta AI is always available — smart commands work out of the box with no configuration. You can also bring your own LLM provider for additional flexibility. Direct commands always work, even without any AI.

Browser Commands

Control the browser with simple commands:

Command What It Does
open google.com Opens a URL in the browser
back Go back to the previous page
forward Go forward in history
refresh Reload the current page
screenshot Capture the current page
close browser Close the browser window
browser status Check if the browser is running

Recording Commands

Record your actions to create automations automatically:

Command What It Does
start recording Begin capturing your clicks, typing, and navigation
stop recording Stop capturing actions
show recorded actions See what you've recorded so far
save as automation Save your recording as a reusable automation

Tip: When saving, you can select specific actions to include. Don't worry if you made mistakes during recording - just pick the steps you want!

Element Selector Tool

Need to find a CSS selector for an element? Use the selector picker:

Command What It Does
get selector Click any element to get its selector
pick element Same as above
inspect element Same as above

After typing the command, hover over elements in the browser - they'll highlight in blue. Click to capture the selector.

Direct Click with CSS Selectors (No AI needed)

When you know the CSS selector, you can click elements directly without AI:

Command What It Does
click #submit-btn Clicks element by ID
click .login-button Clicks element by class
click input[type="submit"] Clicks element by attribute selector
click table > tbody > tr:nth-of-type(2) Clicks with CSS combinators and pseudo-selectors
if exists("#cookie-banner .accept")click #cookie-banner .acceptend Clicks the element only if it existsexists() tests a CSS selector in any condition, so a missing element is skipped and the run continues (a plain click fails and stops the run when the element is absent)

Tip: Use get selector to pick an element visually, then copy the selector directly into a click command!

Optional steps: Wrap a click in if exists("...")end for UI that may or may not appear (cookie banners, "maybe-open" dialogs) so a missing element never stops the automation.

Direct Fill with CSS Selectors (No AI needed)

When you know the CSS selector, you can fill fields directly without AI:

Command What It Does
fill input[name="email"] with [email protected] Fills the email input directly
fill {{SECRET.PASSWORD}} into #password Fills the password field with a secret
fill .search-input with hello Fills element by class selector

Tip: CSS selectors are detected automatically when they contain [], start with #, or start with .. This is faster than AI-powered fill and works without any AI configuration!

Keys and Focus

Command What It Does
press Tab Sends the key itself, wherever the focus currently is (type Tab would type the letters T-a-b)
press Enter in #search Focuses that element first, then sends the key
press Control+A Chords work; so do Escape, Backspace, Delete, the arrows, Home/End/PageUp/PageDown and F1F24
read focus / read active Reads back whatever element has the focus — its value, or its text, or its label

Note: a word that is not a key name is still a button label, so press Cancel keeps clicking the Cancel button.

Click by Text (No AI needed)

Click the first element on the page that contains specific text. This works without AI and is useful when elements don't have stable CSS selectors:

Command What It Does
click Sign In Clicks the first element containing "Sign In" (direct text match, no AI)
click text "Submit Order" Same as above, explicit syntax (also: click by text)

How it works: The command searches all visible elements on the page. It prioritizes exact matches, interactive elements (buttons, links), and shorter text. If multiple elements match, the best candidate is clicked automatically.

Attribute fallback: If no element is found by visible text, the command also searches name, id, and alt attributes. This is useful for elements without visible text like <input type="image" name="Search">. When matched by an attribute, the assistant tells you where it found the match (e.g., "matched by attribute: name").

Find Elements by Text (No AI needed)

Search for elements by their visible text content without clicking them:

Command What It Does
find by text "Dashboard" Lists all elements containing "Dashboard" with their selectors
find on selected Extracts interactive elements from your current text selection in the browser

Select Dropdown Options (No AI needed)

Pick an option from a <select> dropdown by its visible text:

Command What It Does
select "January" from select[name="month"] Selects "January" from the month dropdown
pick "United States" from #country Selects "United States" from the country dropdown
choose "High" from .priority-select Selects "High" from a priority dropdown

Tip: The option is matched by visible text first, then by value attribute. If no match is found, the assistant shows all available options so you can pick the right one.

Frames, Iframes & Link Discovery (No AI needed)

Some websites use <iframe> or legacy <frame>/<frameset> elements to embed content. The assistant can navigate into these frames so you can interact with their content.

Command What It Does
list iframes Show all iframes and frames in the current context (works at any nesting level)
list frames Same as above
list links List all links in the current frame with text, href, class, target, and CSS selectors
list links [keyword] Filter links by keyword (searches text, href, class, name, id, title)
switch to iframe #payment-frame Enter an iframe by CSS selector
switch to frame Menu Enter a frame by name (bare name resolves automatically)
exit iframe Return to the previous level (or main page)
exit frame Same as above
highlight [selector] Highlight an element with a red outline (default). Use to visually identify frames, iframes, or any element
highlight [selector] [color] Highlight with a specific color: red, blue, green, black, white, orange
clear highlights Remove all highlights from the page (alias: unhighlight)

How frame context works: Once you switch into a frame, all subsequent commands (js, click, fill, list links, list iframes, show elements, etc.) execute inside that frame. Use exit iframe to go back one level.

Understanding Nested Frames

Many enterprise applications have multiple levels of frames: a top-level frameset with named frames, and inside each frame there may be additional iframes. The key is to navigate one level at a time:

Page (top level)
├── frame "Header"           ← top-level frame
├── frame "Menu"             ← top-level frame
├── frame "Body"             ← top-level frame
│   └── iframe #iFrame_Tab   ← NESTED iframe inside Body
│       └── (your links, tables, forms are here!)
└── frame "hiddenFrame"      ← hidden utility frame

To reach content inside a nested iframe, you switch into each level:

  1. switch to frame Body — enter the Body frame
  2. list iframes — now shows iframes inside Body, not the top-level ones
  3. switch to iframe #iFrame_Tab — enter the nested iframe
  4. All commands now operate on the actual content inside that iframe

Example: Finding Where an Element Lives

Can't find an element? It's probably inside a nested frame. Follow this discovery automation:

# 1. List the top-level frames
list frames
#   Frame 0: name="Header" (986x40)
#   Frame 1: name="Menu" (184x832)
#   Frame 2: name="Body" (802x832)

# 2. Switch to the most likely frame (usually "Body" or "Content")
switch to frame Body

# 3. Check for nested iframes inside this frame
list iframes
#   iFrame 0: id="iFrame_Content" src=".../search.jsp" (800x600)

# 4. Switch into the nested iframe
switch to iframe #iFrame_Content

# 5. Now search for your element using list links
list links
#   1. "View Details" class="action_link" target="Body"
#      href: /app/actions?id=123&operation=view...
#      selector: a.action_link

# 6. Filter links by keyword for faster results
list links employee
#   1. "Employee 12345" class="action_link"
#      href: /app/actions?matricola=12345...

# 7. Click the link you found
click a.action_link[href*="matricola=12345"]

# 8. Exit back when done: iframe → frame → main
exit iframe       # back to Body frame
exit iframe       # back to main page

Example: Simple Frameset Navigation

# 1. See all frames on the page
list frames
#   Frame 0: name="Header" src=".../header.jsp"
#   Frame 1: name="Navigation" src=".../nav.jsp"
#   Frame 2: name="Content" src=".../main.jsp"

# 2. Switch into the Navigation frame
switch to frame Navigation

# 3. Now all commands run inside the Navigation frame
click Reports
click Monthly Summary

# 4. Switch to the Content frame to see results
exit frame
switch to frame Content

# 5. Interact with the content
list links report
read table
click #export-button

# 6. Return to main page when done
exit frame

Example: Embedded iFrame (Payment Form)

# 1. On a checkout page with an embedded payment form
list iframes
#   iFrame 0: id="stripe-frame" src="https://js.stripe.com/..."

# 2. Switch into the payment iframe
switch to iframe #stripe-frame

# 3. Fill the payment form inside the iframe
fill input[name="cardnumber"] with 4242424242424242
fill input[name="exp-date"] with 12/28

# 4. Return to the main page to click submit
exit iframe
click #place-order

Tips:

  • Start with list frames to see the top-level layout
  • Use list iframes inside a frame to discover nested iframes (it always shows what's inside the current context)
  • Use list links [keyword] to quickly find a specific link by any attribute (text, href, class, name, id)
  • For named frames, you can use just the name: switch to frame Content
  • For iframes with IDs, use CSS selectors: switch to iframe #my-iframe
  • Both <iframe> and legacy <frame> elements are fully supported
  • Use exit iframe once per level to go back (iframe → frame → main page)

Page/Window Navigation (No AI needed)

Some websites open popups or new windows (via window.open(), target="_blank", or JavaScript calls like onclick="openWindow()"). The assistant can switch between these windows so you can interact with the popup content.

Command What It Does
list pages Show all open windows/pages with their index, URL, title, and which one is active
switch to page last Switch to the most recently opened window (the popup)
switch to page 0 Switch to a window by index (0-based)
switch to page "causale" Switch to a window whose URL contains the keyword

Example: Interacting with a Popup

# 1. Click a button that opens a popup window
js scegliCausale(5)

# 2. List all open pages to find the popup
list pages
#   [0] https://app.example.com/main (active)
#   [1] https://app.example.com/popup/causale

# 3. Switch to the popup
switch to page last

# 4. Interact with the popup content
click Approve
fill #note with "Approved"

# 5. Switch back to the main window
switch to page 0

Tips:

  • Use list pages to see all windows after a popup opens
  • switch to page last is the quickest way to jump to a newly opened popup
  • Frame context is reset when switching pages — you start at the main frame of the new page
  • You can switch back and forth between windows as many times as needed

Table Read & Fill (No AI needed)

Read HTML tables and fill their input fields by row and column index. Useful for data entry forms, timesheets, attendance tables, and similar grid-based interfaces.

Command What It Does
read table Read the first table on the page, showing all rows, columns, and editable fields
read table #my-table Read a specific table by CSS selector
fill table row 0 col 2 with 8 Fill the input at row 0, column 2 with "8" (0-indexed)
read table pw Playwright-based table read — better for tables inside frames or complex pages
read table pw #my-table Playwright-based read of a specific table
fill table pw row 0 col 2 with 8 Playwright-based table fill — better for frames or complex pages

Example: Filling a Timesheet Table

# 1. Read the table to see its structure
read table

# Output:
#   Table: #timesheet (5 rows)
#   row\col  [0] Employee   [1] Date        [2] Hours   [3] Notes
#   0        John Smith     2026-01-15      [text] 8    [text]
#   1        Jane Doe       2026-01-15      [text]      [text]
#   2        Bob Wilson     2026-01-15      [text] 7.5  [text]

# 2. Fill empty cells
fill table row 1 col 2 with 8
fill table row 1 col 3 with Remote work

# 3. For tables inside frames, switch to the frame first
switch to frame Content
read table
fill table row 0 col 2 with 8

Tips:

  • Row and column indices are 0-based
  • Editable cells are highlighted with their input type: [text], [select], [checkbox]
  • For dropdowns, use the visible option text: fill table row 0 col 1 with January
  • Checkboxes accept true/yes/1 or false/no/0
  • Secrets are supported: fill table row 0 col 2 with {{SECRET.VALUE}}
  • Playwright variants: read table pw and fill table pw use Playwright instead of raw JS — better for tables inside frames or complex pages

Page Analysis (AI-Powered)

Discover what's on a page before building your automation:

Command What It Does
show elements Analyze the page and list all interactive elements with their CSS selectors
what's on the page? Same as above - natural language variant
analyze the page Same as above - get a structured breakdown of the page

The show elements command returns a categorized list of:

  • Forms - with all their fields and submit buttons
  • Buttons - clickable actions with their purpose
  • Input fields - text boxes, checkboxes, dropdowns
  • Links - navigation and action links
  • Interactive elements - modals, dropdowns, accordions
  • Data displays - tables, lists, cards

Each element includes its CSS selector, making it easy to use in subsequent commands or automation steps.

Smart Commands (AI-Powered)

When AI is configured, you can describe what you want in plain language:

Example What Happens
search and click the login button AI finds and clicks the login button
find the search box AI locates the element and shows its selector
fill "hello" into the message field AI finds the field and types "hello"
what step types are available? AI answers your question

Using Secrets in Commands

When your automation has bound secrets, you can use them in commands:

Example What Happens
fill {{MYSITE.USERNAME}} into the email field Fills the username from your bound secret
type {{MYSITE.PASSWORD}} Types the password into the focused field
open https://api.example.com?key={{API.VALUE}} Opens URL with your API key injected
js fetch('/api?token={{AUTH.VALUE}}') Runs JavaScript with secret injected

Security: Secrets are resolved on your desktop - they never go through the server during command execution. Tier 2 secrets require your vault to be unlocked.

AI Configuration

Smart commands work immediately with Nocarta AI — no setup needed. If you want to use your own LLM provider instead, configure it in Settings:

  1. Go to Settings
  2. Scroll to LLM Configuration
  3. Click Add LLM and choose a provider
  4. Enter your API key and select a model

Supported providers:

  • Ollama - Free, runs locally on your computer
  • OpenAI - GPT models (requires API key)
  • Anthropic - Claude models (requires API key)
  • Google Gemini - Gemini models (requires API key)
  • Custom (OpenAI-compatible) - vLLM, LM Studio, Together AI, Groq, and more

Your own LLMs take priority when configured. Nocarta AI remains available as a fallback. See the AI Assistant &amp; LLM Configuration guide for details.


How Automations Work

  1. Create: Choose a mode (Steps, Script, or Browser Script) and build your automation
  2. Bind: Connect secrets for credential injection (optional step)
  3. Execute: Run on your desktop with a live browser or as a script

Creating an Automation

Automation creation happens in 2 steps in the new wizard:

Step 1: Automation Description

  1. Navigate to New Automation
  2. Fill in the details:
    • Name — a unique name to identify the automation
    • Description — instructions or context about what the automation does
    • Browser Type — choose between Chromium (recommended), Firefox, or WebKit
    • Timeout — max time in seconds for the entire execution (default: 300s)
    • Headless Mode — run the browser without visual interface (faster)
  3. Click Next to go to Step 2

Step 2: Choose Execution Mode

Choose how you want the automation to be built:

Mode Description Best For
Steps
(Steps Mode)
Define individual actions manually: Click, Fill, Navigate, Wait, etc. Each step is a discrete action with configurable timeout and error handling. UI automation, forms, website navigation
Script
(Script Mode)
Write a script using assistant commands with variables, loops, conditionals, and functions. The script is processed by the assistant. Complex logic, data processing, loops and conditions
Browser Script
(Browser Script Mode)
The same automation language in browser mode, for HTTP API automation: REST requests, JSON handling, integration with external APIs. API-based automation, webhooks, data pipelines

Creating Automation (Steps Mode)

  1. After choosing Steps in Step 2, you'll see the steps editing area
  2. Click Add Step to create the first action
  3. For each step, configure:
    • Step Type — Navigate, Click, Fill, Select, Wait, Scroll, Screenshot, etc.
    • Selector — the CSS selector, XPath, or text to target an element (not needed for Navigate or Wait)
    • Value — the URL, text to type, key to press, or condition to wait for
    • Timeout — max wait per step in milliseconds (default 30000 = 30s)
    • Delay Before / After — extra pause in ms around the step
    • Continue on error — check if the automation should skip this step on error
  4. Use the Quick Help (expand question mark icon) to see example syntax
  5. Click Create Automation to save
  6. After creating, you can bind Secrets in the edit tab

Tips for Steps Mode:

  • Use the Assistant to discover selectors: type open [url], then get selector to visually pick elements
  • You can convert an automation with steps to Script using the Convert to Script button
  • CSS selectors are faster; text selectors are more readable but less stable

Creating Automation (Script Mode)

  1. After choosing Script in Step 2, you'll see a text editor for script
  2. Write your assistant commands as a script
  3. Supports: variables, loops, conditionals, functions, instance data, and date/time
  4. Use the Quick Help to see variable and control structure syntax
  5. Click Create Automation to save

Quick Example:

url = "https://example.com"
open #{url}
fill #email with [email protected]
click #login-button
wait for #dashboard

Creating Automation (Browser Script Mode)

  1. After choosing Browser Script in Step 2, you'll see the script editor
  2. Write the automation language in browser mode: http requests plus variables, loops, and conditionals
  3. Supports: http get/post/put/patch/delete, headers, authentication, real variables and expressions
  4. Use Check syntax to validate before saving
  5. Click Create Automation to save

Quick Example:

r = http get "https://api.example.com/users"
  query page: 1
  auth bearer {{API.TOKEN}}
end
validate r.status == 200

Working in the Script Editor

The editor on an automation's Script tab colours the script as you type, numbers the lines, counts the commands, and completes verbs: start typing cl and pick click # with the arrow keys, then Tab or Enter.

Right-click a line for the things you do most often:

  • Run this line in the assistant — sends just that line (or every line the selection touches) to the assistant chat, so you can try one command without running the whole script
  • Comment out / Uncomment, Duplicate line, Delete line, Copy line

Every item works on whole lines, and blank lines and comments are dropped before anything is sent to the assistant.

When a command fails, the message appears in the chat and as a red notice in the corner. The notices stack, and they stay for 5 seconds after the last one — so a run that keeps failing keeps its errors on screen instead of each one vanishing before you read it. Click the × to dismiss one.


Step Types (Steps Mode)

The following step types are available when you choose Steps Mode when creating the automation:

Step Description Example
Navigate Go to a URL https://example.com/login
Click Click an element Button, link, checkbox
Fill Enter text in a field Username, search box
Select Choose dropdown option Country selector
Wait Pause for condition Wait for element to appear
Validate Assert condition Check if logged in
Extract Get data from page Scrape a value
Screenshot Capture current state For debugging/audit
Scroll Scroll the page Scroll to element
Hover Mouse over element Trigger dropdown menu
Press Key Keyboard input Enter, Tab, Escape
Press Sequentially Type text char by char Slow typing for reactive fields
Sleep Pause for fixed time Wait 2000ms between steps
JavaScript Run custom JS Advanced interactions

Selectors

Each step that interacts with the page needs a selector. Use the get selector command to pick elements visually, or use these formats:

Type Syntax Best For
CSS #login-button, .submit-btn IDs and classes
XPath //button[@type='submit'] Complex queries
Text "Sign In" Button/link text

Tips:

  • Use get selector in the assistant to pick elements visually
  • CSS is fastest and most reliable
  • IDs (like #login-btn) are the most stable
  • Text selectors are readable but may break if text changes

Binding Secrets

After creating your automation, you can bind credentials stored in the Vault for secure injection in your steps or scripts:

  1. Create your secrets in the Vault first
  2. Open the created automation
  3. Go to the Bound Secrets tab
  4. Click Bind Secret
  5. Map a secret to a placeholder: {{ALIAS.FIELD}}
    • Use the syntax: {{STORE_NAME.VALUE}}, {{STORE.USERNAME}}, {{STORE.PASSWORD}}, {{STORE.URL}}
    • In Steps, use the placeholder directly: fill #email with {{MYSITE.USERNAME}}
    • In Scripts, also use: fill #email with {{MYSITE.USERNAME}}
    • In Browser Scripts, use: auth bearer {{API.VALUE}}

Security: Credentials are injected on your device at runtime — on the desktop app for desktop automations, inside the browser sandbox for Browser Scripts. The server never sees the actual values during execution. Tier 2 secrets require your vault to be unlocked.


Executing Automations

From Web Interface

  1. Open the automation
  2. Click Execute
  3. If not on desktop: You'll be prompted to open the desktop app

From Desktop App

  1. Open Nocarta Desktop
  2. Navigate to Automations
  3. Click Run on any automation
  4. Watch the browser automation live

From Mobile (Dispatch)

  1. Open a Notebook on your phone
  2. Click Dispatch to Desktop
  3. Select the automation
  4. Execution starts on your desktop

Batches

For running the same automation with different inputs:

  1. Create an Automation Batch
  2. Add multiple runs with different parameters
  3. Execute the batch
  4. Each run executes sequentially with its own data

Use cases:

  • Process multiple invoices
  • Fill multiple forms
  • Batch data entry

Script Mode (Assistant Commands)

Script Mode lets you write assistant commands as a script with variables, loops, conditionals, functions, and access to form instance data. The script is interpreted statement by statement at execution time by the same engine that powers the assistant chat — one language, one live variable environment shared by the chat, script runs, and the debugger.

Creating a Script Mode Automation

  1. Navigate to New Automation or edit an existing one
  2. On the Description tab, set Execution Mode to Script
  3. Switch to the Editor tab — write your script there
  4. Click Run in Assistant to execute, or Update Automation to save

Variables

# String
url = "https://example.com"
greeting = "Hello"

# Number
count = 42
total = 2 + 3

# Array
items = ["a", "b", "c"]

# Hash
config = {url: "https://app.com", port: 8080}

# Bare names in expressions; #{...} inside command text
open #{url}
fill #count with #{total}

Variables are plain assignments — there is no set keyword. In conditions, arithmetic, and other expressions, reference variables by bare name (total + 1). Inside command text (selectors, URLs, fill values) and double-quoted strings, interpolate with #{...}. Referencing an undefined variable is a runtime error naming it, with the line number. Secret placeholders {{SECRET.PASS}} pass through untouched — they are injected on your desktop at runtime.

Command text and message text (log, stuck, finish, ask) also accept two shortcuts: a value slot that is just one bare variable name works directly — select opt from #dept is the same as select #{opt} from #dept — and wrapping the whole slot in quotes is optional, so open "https://x" and open https://x render identically. An undefined bare name falls back to the literal word rather than erroring.

String Methods

MethodExampleResult
.upcasename.upcase"HELLO"
.downcasename.downcase"hello"
.lengthname.length5
.strips.striptrims whitespace
.reverses.reverse"cba"
.replace(old, new)s.replace("a", "b")substitution
.split(sep)csv.split(",")array from string
.slice(start, end)s.slice(0, 5)substring
.includes(str)s.includes("x")true/false

Type Conversion Methods

Convert between types. Instance data field values are always strings — use .to_i or .to_f when you need to do arithmetic with them.

MethodExampleResult
.to_is.to_istring → integer (errors on non-numeric)
.to_fs.to_fstring → float (errors on non-numeric)
.to_sn.to_snumber/boolean → string
.absn.absabsolute value
.ceiln.ceilround up
.floorn.floorround down
.roundn.roundround to nearest integer

Example: Instance Field Arithmetic

# Instance fields come as strings — convert before arithmetic
hours = instance.fields.monthly_hours.to_i
rate = instance.fields.hourly_rate.to_f
total = hours * rate
rounded = total.round
fill #total with #{rounded}

Array Methods

MethodExampleResult
.lengthitems.length3
.first / .lastitems.first"a"
.join(sep)items.join(", ")"a, b, c"
.reverseitems.reverse["c", "b", "a"]
.includes(item)items.includes("b")true
.sortitems.sortsorted array
.uniqitems.uniqremove duplicates
.compactitems.compactremove empty values
[n]items[0]"a"
.push(v)items.push("d")append to array (mutates)

Hash Methods

MethodExampleResult
.keysconfig.keys["url", "port"]
.valuesconfig.values["https://app.com", 8080]
.lengthconfig.length2
dot accessconfig.url"https://app.com"
bracket accessconfig["url"]"https://app.com"

Method chaining is supported: items.uniq.sort.join(",")

Built-in Date Functions

Date and time functions are built into the language and can be called anywhere an expression is legal — in assignments, conditions, or inside #{...} interpolation in command text.

FunctionExampleResult
weekday(y, m, d)weekday(2026, 2, 1)"SUN"
weekday(y, m, d, locale)weekday(2026, 2, 1, "it")"DOM"
days_in(y, m)days_in(2026, 2)28
today()today()"2026-03-06"
today(format)today("dd/MM/yyyy")"06/03/2026"
now()now()"2026-03-06 14:30:00"
now(format)now("hh:mm tt")"02:30 PM"
format_date(y, m, d)format_date(2026, 3, 6)"2026-03-06"
format_date(y, m, d, fmt)format_date(2026, 3, 6, "dd/MM/yyyy")"06/03/2026"

Format Tokens

TokenMeaningExample
yyyy4-digit year2026
MM2-digit month03
dd2-digit day06
HH24-hour hours14
hh12-hour hours02
mmMinutes30
ssSeconds45
ttAM/PMPM

Weekday Locales

LocaleDays (Sun–Sat)
"en" (default)SUN, MON, TUE, WED, THU, FRI, SAT
"it"DOM, LUN, MAR, MER, GIO, VEN, SAB
"pt"DOM, SEG, TER, QUA, QUI, SEX, SAB
"es"DOM, LUN, MAR, MIE, JUE, VIE, SAB
"fr"DIM, LUN, MAR, MER, JEU, VEN, SAM
"de"SO, MO, DI, MI, DO, FR, SA

Example: Timesheet Loop

year = 2026
month = 2
total = days_in(year, month)

each i in 0..total - 1
  day = i + 1
  dow = weekday(year, month, day, "it")
  date = format_date(year, month, day, "dd/MM/yyyy")
  if dow != "DOM"
    fill table row i col 0 with #{date}
    fill table row i col 1 with #{dow}
  end
end

Conditionals

if status == "active"
  click #activate
elsif status == "pending"
  click #wait
else
  click #skip
end

Conditions are ordinary expressions — variables by bare name, full operator precedence, and parentheses. Operators: ==, !=, >, <, >=, <=. Compound: and, or, not. Substring and membership checks use the .includes(...) method: if title.includes("Invoice").

Loops

# Count with a range (i takes each value in turn)
each i in 0..2
  fill table row i col 0 with data
end

# Iterate over a list
each item in items
  click ##{item}
end

# With index variable
each item, idx in items
  fill table row idx col 0 with #{item}
end

# Loop while a condition holds
while exists("#next-page")
  click #next-page
end

Counted loops use ranges (each i in 1..n). break exits the innermost loop and next skips to the following iteration.

Variable scoping inside loops

Scoping is lexical: if/each/while bodies share the enclosing scope, so a variable assigned inside a loop is still visible after it. Only the loop variable itself (each n in …) is scoped to the loop; function bodies (def) are separate scopes.

# Accumulator declared outside, modified inside the loop
total = 0
each n in [1, 2, 3]
  total = total + n     # or the shorthand: total += n
end
log #{total}                      # → "6"

# A variable first assigned inside the loop lives on after it
each n in [1, 2, 3]
  y = n
end
log #{y}                          # → "3" (the loop variable n is gone, y remains)

This makes "linear-walk to find a value" patterns work correctly — and break lets you stop at the first match:

my_row = 0
each r, idx in rows
  if idx == target_idx
    my_row = r           # outer my_row is updated
    break
  end
end
log #{my_row}             # the matched row

Expressions inside interpolation

#{...} holds a full expression — indexing, arithmetic, string building, and method calls all evaluate in one pass, no nesting needed:

rows = [10, 20, 30, 40]
i    = 2
log #{rows[i]}                 # → "30"

# Dynamic field-name access is string-keyed hash access
chapter = 5
log #{instance.fields["title_" + chapter.pad_zero]}
# chapter.pad_zero → "05", so this reads the title_05 field

Padding

MethodExampleResult
.pad_zeron.pad_zero2-digit string (5"05")
.pad_left(n, char)s.pad_left(4, "0")"0007" from "7"
.pad_right(n, char)s.pad_right(6, "-")"abc---" from "abc"

Nullish-coalescing (??)

Provide a default value when a value might be nil. Useful for optional / sparse instance fields:

# Safe field access — falls back to "N/A" when the field is absent
log #{instance.fields.optional_phone ?? "N/A"}

# Other defaults
phone = instance.fields.optional_phone ?? "N/A"
count = instance.fields.item_count ?? 0

A missing instance field simply reads as nil?? is an optional convenience for supplying a default, not a requirement. (Referencing an undefined variable, by contrast, is a runtime error naming it.)

Table cursor

By default, fill table and read table target the first <table> in the active frame. To scope them to a different table on a multi-table page, set a cursor with switch to table SELECTOR:

switch to table "div.invoices > table"
fill table row 2 col 3 with OK
read table

# Cursor stays sticky until cleared:
fill table row 5 col 1 with Done

exit table                            # back to first-<table> default

Selectors with >, spaces, or pseudo-classes work as-is; surrounding double or single quotes are stripped.

The cursor is automatically cleared on any frame transition (switch to frame, switch to iframe, exit frame) because a CSS selector is document-scoped. If you need the cursor across frames, re-set it after each frame change.

Functions

# Define a reusable function
def login(url, user, pass)
  open #{url}
  fill #user with #{user}
  fill #pass with #{pass}
  click #submit
end

# Call it
login("https://app.com", "admin", "{{SECRET.PASS}}")

Functions can contain loops, conditionals, and any other commands. They are real functions: an early return works and returns a value you capture with an assignment, e.g. col = find_first_empty(1). Parameters can have defaults (def f(a, b = 0)). Secret placeholders inside string arguments pass through untouched.

The last statement is the value — the same rule Ruby uses, so return is only for leaving early:

def focused_field()
  read focus              # this line's value IS the function's value
end

def status_of(row)
  if row == 0
    "header"              # if gives back the branch that ran
  else
    read table cell row row col 3
  end
end

label = status_of(0)

A function that ends in a command which captures nothing (click, fill, press), in a loop, or in a log gives back nil.

Instance Data (Batches)

When a script runs as part of a batch, it receives instance data from the linked form instance. Access fields with instance.fields.field_name:

# Access instance fields
fill #email with #{instance.fields.email}
fill #phone with #{instance.fields.phone}

# Access metadata
fill #id with #{instance.instance_id}
fill #pub with #{instance.metadata.publisher}

# Iterate over all fields
each field in instance.fields
  fill [name="#{field.name}"] with #{field.value}
end

instance.fields iterates as {name, value} entries, automatically filtering out UUID-keyed entries. A missing or empty field reads as nil — use ?? when you want a default. Dynamic field names are string-keyed hash access: instance.fields["prefix_" + var].

Important: All instance field values are strings, even if they look like numbers. Use .to_i or .to_f to convert before arithmetic:

# BAD — arithmetic on strings is an error
total = instance.fields.hours * instance.fields.rate    # "8" * "25" = error

# GOOD — convert to numbers first
hours = instance.fields.hours.to_i
rate = instance.fields.rate.to_f
total = hours * rate                                     # 8 * 25.0 = 200

Complete Example

# Define a reusable notification function
def notify(email)
  fill #recipient with #{email}
  click #send
  sleep 1
end

# Split contacts from instance data into an array
emails = instance.fields.contacts.split(",")

# Fill the company field
fill #company with #{instance.fields.name}

# Notify each contact
each email in emails
  notify(email)
end

Comments

Lines starting with # or // are comments and will be ignored. Blank lines are also skipped.


Browser Scripts

Browser Scripts are an alternative to step-based automations. You write the same automation language used everywhere in Nocarta, in browser mode: the http verbs plus the core language (variables, strings, arrays, loops, if, validate) — designed for HTTP API automation, data transformation, and integration tasks.

Browser Scripts are ideal when your automation is API-driven (REST calls, webhooks, data pipelines) rather than UI-driven (clicking buttons, filling forms). They run in an isolated sandbox inside your browser, and requests go straight from your browser to the target — never through Nocarta’s servers, and never carrying your Nocarta session. Page-driving verbs like open and click need the desktop app; using one in a Browser Script gives you a clear error saying exactly that.

You must list the hosts a script may contact, on the automation’s Settings tab. The list is deliberately strict: an empty list reaches nothing at all, so a script with no configured hosts cannot make a single request. Use exact hostnames (api.example.com) or a wildcard (*.example.com).

Creating a Browser Script Automation

  1. Navigate to New Automation or edit an existing one
  2. On the Description tab, set Execution Mode to Browser Script
  3. A script editor appears — write your script there (the Check syntax button also flags verbs that need the desktop app)
  4. Click Update Automation to save

Running from Diagram Output

Browser Scripts can be linked to Notebooks for diagram-to-API automations:

  1. Analyze a diagram in a Notebook (Drawing Translator)
  2. On the diagram output page, link a Browser Script automation via settings
  3. Open the Convert dropdown and click Run Script
  4. The Execution Monitor opens, showing real-time progress

The script receives the diagram context (nodes, edges, type) automatically, so you can iterate over diagram data and make API calls for each element.

Language Reference (browser mode)

HTTP Requests

Make HTTP requests to any API on the automation’s allowed-hosts list. Requests go directly from your browser to the target. Capture the response into a variable with =; add clauses in a block closed by end:

r = http get "https://api.example.com/users"
  query  page: 1
  header Accept: application/json
  auth   bearer {{GITHUB.VALUE}}
end

Available verbs: http get, http post, http put, http patch, http delete. A request with no clauses fits on one line: r = http get "https://api.example.com/users"

Clause Purpose Example
query URL query parameter (repeatable) query page: 1
header Custom HTTP header (repeatable) header Accept: application/json
auth Authentication auth bearer {{TOKEN.VALUE}}
json JSON request body — a real hash, values are expressions json {title: "Test", userId: 1}
body Raw string body body "plain text content"

The captured response is an ordinary value:

Field Returns
r.status HTTP status code (e.g., 200). A non-2xx response is a value you inspect — it never aborts the run by itself.
r.json Parsed JSON body (or nil when the response is not JSON)
r.json.field, r.json.items[0].id Nested fields and array elements
r.body Raw response text
r.headers["content-type"] Response header value (lowercase names)

Variables

count = 0
username = r.json.login
message = "Hello #{username}, you have #{count} items"

Variables are ordinary values: use them bare in expressions (count + 1), interpolate them into strings with #{...}, and use string/array methods (text.split(","), items.length, name.upcase).

Control Flow

each — loop over collections (add , i for the 0-based index):

each user, i in r.json.users
  if user.status == "active"
    http post "https://api.example.com/notify"
      json {user_id: user.id, message: "Hello"}
    end
    log Processing #{user.name}
  end
end

if / elsif / else — conditional execution:

if r.status == 200
  log Success
else
  log Failed with status #{r.status}
end

Operators: ==, !=, >, <, >=, <=, and, or, not, ?? (default when missing)

Logging, Waiting & Validation

Command Purpose Example
log Write to execution log log Found #{count} items
sleep Pause for seconds sleep 2
validate Assert a condition (stops on failure) validate r.status == 200
stuck Stop and say why, in your own words. Recorded as stuck with your category, so “the other service is down” is not filed as “your script is broken”. stuck "Portal under maintenance", category: "external_outage"
finish Stop early and successfully — nothing after it runs. Use it when there is simply nothing to do. finish "nothing to invoice this month"

Comments

# This is a comment
// This is also a comment

Diagram Context

When running from a Notebook diagram, the script gets a diagram variable with the analysis data:

Expression Returns
diagram.nodes All diagram nodes
diagram.edges All diagram edges
diagram.type Diagram type (flowchart, mind_map, etc.)

Example — create a Trello card for each node in a flowchart:

# Create a Trello card for each diagram node
each node in diagram.nodes
  http post "https://api.trello.com/1/cards"
    query key: "{{TRELLO.VALUE}}"
    query token: "{{TRELLO_TOKEN.VALUE}}"
    json {name: node.label, idList: list_id}
  end
  log Created card: #{node.label}
end

Secrets in Scripts

Use bound secrets with {{ALIAS.VALUE}} placeholders, just like in step-based automations:

r = http get "https://api.github.com/user"
  auth bearer {{GITHUB.VALUE}}
end
log Logged in as #{r.json.login}

Security: Secret values are resolved inside the sandbox at the moment the request is sent — they are never stored in the script and never pass through Nocarta’s servers in resolved form. Tier 2 secrets require your vault to be unlocked. A missing credential stops the run with the placeholder’s name; an empty value is never silently sent.

Execution Monitor

When a script runs, the Execution Monitor shows real-time progress:

  • Step list (left panel) — each command with status icon
  • Detail panel (right panel) — request/response details, variables, errors
  • Progress bar — completed vs. total steps
  • Pause — pause before the next step
  • Stop — abort execution
  • Copy Log — export full execution data as JSON

Complete Example: API Chain

# Authenticate and fetch user data
auth_r = http post "https://api.example.com/auth"
  json {email: "[email protected]", password: "{{SECRET.VALUE}}"}
end
validate auth_r.status == 200
token = auth_r.json.token

# Fetch paginated data
items_r = http get "https://api.example.com/items"
  header Authorization: Bearer #{token}
  query page: 1
  query limit: 50
end
log Retrieved #{items_r.json.data.length} items

# Process each item
each item in items_r.json.data
  if item.status == "pending"
    http patch "https://api.example.com/items/#{item.id}"
      header Authorization: Bearer #{token}
      json {status: "processed"}
    end
    log Updated item #{item.id}
  end
end

Signing an automation

You can sign an automation with a keypair from your Vault, and Nocarta will tell you if it is ever altered. Create the keypair once (Vault → New Secret → type Keypair), then use Sign on the automation’s Settings tab.

What gets signed is more than the script: it also covers the allowed hosts and the credentials bound to the automation. That matters, because the dangerous change is not always in the code — someone who could add a host to your allow-list could send your credentials somewhere new without touching a line of the script.

  • Signed — it matches what you approved.
  • Changed since signing — something has been altered. Review it and sign again.
  • Signature invalid — the signature no longer belongs to the key it claims. Treat this as suspicious.

Tick Refuse to run if altered and the automation will not run at all while it does not match. Without that, signing still tells you — it just does not stop you.

The private half of your keypair is encrypted with your master password and never leaves your browser, so Nocarta cannot sign anything on your behalf. That is exactly what makes the signature worth something. Signing therefore needs your vault unlocked.

Limitations

  • No page interactionopen, click, fill and the other page verbs need the desktop app; using one here gives a clear error saying so
  • Allowed hosts only — a script reaches nothing until you list its hosts, and nothing outside that list
  • The target must permit browser access — a service that does not send Access-Control-Allow-Origin cannot be read by any browser script. You can still send the request; you just cannot read the reply.
  • 5-minute timeout — scripts must complete within 5 minutes
  • The assistant is not reachable — a Browser Script that uses ask stops with a message saying so; run it as a desktop automation when you need the assistant. Everything else in the language works here, including checkpoint and on stuck restart (only its with fresh browser option needs the desktop app)

Troubleshooting

Issue Solution
Automation doesn't start Ensure Desktop app is running
Element not found Use get selector to verify the element, or add a Wait step
Timeout error Increase step/automation timeout
Login fails Verify secret binding and values
Page changed Update selectors using get selector
AI not responding Check AI connection status in the assistant (click the CPU icon)
Recording doesn't capture actions Make sure recording is started before interacting with the page

Quick Reference: Assistant Commands

All commands you can use in the Automation Assistant:

Browser (No AI needed)

  • open [url] - Open a webpage (aliases: go to, navigate to, visit)
  • back - Go back (aliases: go back, previous page)
  • forward - Go forward (aliases: go forward, next page)
  • refresh - Reload page (alias: reload)
  • screenshot - Capture page (aliases: take screenshot, capture screenshot)
  • browser status - Check if browser is open
  • close browser - Close browser window
  • press Tab - Send a key where the focus is; press Enter in #search focuses that element first. Chords (press Control+A) and Escape/Delete/arrows/F1-F24 included. A word that is not a key name still clicks that button
  • read focus - Read the focused element's text (alias: read active); capture it with x = read focus

Recording (No AI needed)

  • start recording - Begin recording (alias: begin recording)
  • stop recording - Stop recording (aliases: end recording, finish recording)
  • show recorded actions - List captured actions (aliases: recorded actions, what did I record?)
  • save as automation - Save recording (aliases: create automation, save actions)

Element Selection & Text Search (No AI needed)

  • get selector - Click to pick element (aliases: pick element, inspect element, selector)
  • click Submit - Click first element matching visible text, name, id, or alt (aliases: click text "Submit", click by text)
  • find by text "Dashboard" - Find elements containing text and show their selectors
  • find on selected - Extract elements from your current text selection
  • find input near "Password" - Proximity finder: locate the element (input/button/select/textarea/link/checkbox/radio/field) nearest a landmark (quoted text or a CSS selector) and return its selector. Capture and reuse: X = find input near "Password", then click #{X}
  • if exists("#selector")click #selectorend - Click only if the element exists; a missing element is skipped and the run continues (exists() works in any condition)

Find never stops the run on no-match. find column, find by text, find on selected, and find … near … return nil (or an empty array) when nothing matches — guard the result with if, e.g. if x != nil. (Action verbs — click/fill, click by text, fill by text — still fail if their target is missing; wrap a click in if exists("...")end to make it optional.)

Select Dropdown Options (No AI needed)

  • select "January" from select[name="month"] - Pick dropdown option by visible text
  • pick "Option" from #dropdown - Same as above (aliases: choose)

Frames, Iframes & Link Discovery (No AI needed)

  • list iframes - Show all iframes/frames in the current context (alias: list frames)
  • list links - List all links in the current frame with selectors and attributes
  • list links [keyword] - Filter links by keyword (text, href, class, name, id)
  • switch to iframe #id - Enter an iframe by CSS selector
  • switch to frame Name - Enter a frame by name
  • exit iframe - Return one level up (alias: exit frame)
  • highlight [selector] - Highlight an element with a red outline
  • highlight [selector] [color] - Highlight with a color (red, blue, green, black, white, orange)
  • clear highlights - Remove all highlights (alias: unhighlight)

Table Read & Fill (No AI needed)

  • read table - Read table contents with row/col indices
  • read table #selector - Read a specific table by CSS selector
  • fill table row 0 col 2 with value - Fill input at row 0, col 2 (0-indexed)
  • read table pw / read table pw #selector - Playwright-based table read (better for frames)
  • fill table pw row 0 col 2 with value - Playwright-based table fill

Direct Click with Selectors (No AI needed)

  • click #myId - Click by ID selector
  • click .myClass - Click by class selector
  • click input[type="submit"] - Click by attribute selector
  • click div > span - Click with CSS combinators
  • click tr:nth-of-type(2) - Click with pseudo-selectors

Direct Fill with Selectors (No AI needed)

  • fill input[name="x"] with value - Fill by attribute selector
  • fill #myId with value - Fill by ID selector
  • fill .myClass with value - Fill by class selector
  • fill value into input[name="x"] - Alternative syntax

Secrets (No AI needed)

  • test secret {{ALIAS.VALUE}} - Test secret placeholder resolution (aliases: check secret, show secret, resolve secret)
  • fill {{ALIAS.VALUE}} into #password - Fill with secret placeholder
  • open https://api.example.com?key={{API.VALUE}} - Use secrets in URLs

Security: Secrets are resolved on your desktop - they never go through the server during command execution. Tier 2 secrets require your vault to be unlocked.

JavaScript Execution

All JS commands run directly in the browser page — like typing in the Developer Console. Full access to document, window, fetch, and all browser APIs. If you used switch to iframe, JS runs inside that iframe automatically.

  • js [code] - Execute JavaScript in the page
  • js document.title - Single-line JS
  • js fetch('/api?token={{AUTH.VALUE}}') - JS with secret injection
  • js ... end - Multi-line JavaScript block (Shift+Enter for newlines, end to finish)
  • js from ~/script.js - Execute JavaScript from a local file (file stays on your machine)

Use return to send a value back, and capture it with an assignment: title = js document.title. Secrets like {{AUTH.TOKEN}} are resolved locally on your desktop before injection.

Playwright Commands

Direct access to the Playwright page object — the same API used by click, fill, find and all assistant commands internally.

  • pw page.click('#btn') - Single-line Playwright command
  • pw await page.waitForSelector('.loaded') - Wait for an element
  • pw ... end - Multi-line Nocarta Assistant script block
  • pw from ~/script.js - Execute Nocarta Assistant script from a local file

The script receives a page argument with the full Playwright Page API. Use return to capture results. Secrets are resolved before execution.

Result Variables

  • employees = read table - Capture a command's result in a variable (any command works as the right-hand side of an assignment)
  • show variables - List all variables in the environment (aliases: list vars, show results)
  • clear variables - Reset the variable environment (aliases: clear vars, clear results)

Reference a captured result by its bare name in expressions (employees.length, cells.include?("Total")) or with #{...} inside command text. Structured results support dot-path and index access: employees.items[0].name. The same variables are live in the chat, script runs, and the debugger.

Page Analysis (AI required)

  • show elements - List all interactive elements with selectors (aliases: page elements, elements)
  • what's on the page? - Analyze page structure
  • analyze the page - Same as above (alias: page analysis)

Smart Commands (AI required)

  • search and click [description] - AI finds and clicks element by description
  • find [description] - Find element and show selector (aliases: locate, where is)
  • fill [value] into [field description] - Fill a field by description
  • type [value] - Type into the focused field
  • Any question or request in natural language

Note: click is always a direct text match (no AI needed). Use search and click for AI-powered element matching. click with CSS selectors (like click #id or click .class) also works without AI.


Tips & Shortcuts

Command History (Arrow Keys)

The assistant remembers the last 50 commands in each chat session. Navigate through them with your keyboard:

Key What It Does
Arrow Up Go to the previous (older) command
Arrow Down Go to the next (newer) command, or return to what you were typing

Tips:

  • Your current draft is preserved - pressing Up then Down returns to what you were typing
  • Consecutive duplicate commands are not stored twice
  • In multi-line inputs, arrow keys only navigate history when the cursor is at the first or last line

Smart Quotes Auto-Correction

When you paste commands from word processors (Microsoft Word, Google Docs, macOS TextEdit), curly "smart" quotes are automatically replaced with straight quotes. This prevents selector and string errors.

If smart quotes are detected, you'll see a notice:

Smart quotes detected and auto-corrected to straight quotes.
Tip: disable smart quotes in your text editor to avoid this.

Characters corrected: \u201C \u201D (double), \u2018 \u2019 (single), \u201E \u201A (low), \u00AB \u00BB (guillemets) - all replaced with standard ASCII quotes.

Multi-Command Execution (Batch Mode)

Send multiple commands at once, separated by ; (semicolon) or newline (Shift+Enter). They execute sequentially, one after another.

Separator How to Type Example
; Type directly on one line switch to frame Body; list iframes; list links
Newline Press Shift+Enter Each line becomes a separate command

Example: Navigate into nested frames in one command

switch to frame Body; list iframes; switch to iframe #iFrame_Tab; list links employee

Example: Multi-line batch

switch to frame Body
list iframes
switch to iframe #iFrame_Tab
list links employee
click a[href*="matricola=12345"]

How it works:

  • Commands run one at a time, in order, with results shown after each
  • A progress indicator shows [1/4], [2/4], etc.
  • If a command fails, the remaining commands still execute
  • js commands are not split by ; (semicolons are valid JavaScript)

Example: Auto-Login Automation

Step 1: Navigate → https://app.example.com/login
Step 2: Fill → #username → {{username}}
Step 3: Fill → #password → {{password}}
Step 4: Click → button[type="submit"]
Step 5: Wait → .dashboard (wait for dashboard to load)
Step 6: Screenshot → (capture logged-in state)

Or record it:

  1. Type open app.example.com/login
  2. Type start recording
  3. Fill in username and password, click login
  4. Type stop recording
  5. Type save as automation
  6. Edit the saved automation to bind secrets for credentials

When an Automation Gets Stuck

Scripts can hit a wall — a page under maintenance, a renamed button, a slow load. Instead of a cryptic failure, you can make automations explain themselves, recover on their own, and ask for help. These are all optional; leave them out and nothing changes.

Checkpoints, stuck, and fail messages

  • checkpoint "login" — mark a point you trust. It shows in the run log and becomes the anchor an auto-restart resumes from. Put checkpoints at the top level (not inside an each/while loop or a def).
  • stuck "Portal is under maintenance", category: "external_outage" — stop the run on purpose with your own message. That message is what the user sees, never a raw error. The category is an optional label.
  • on fail message "Could not open the invoices list" — from this line on, if a command fails the user sees your message instead of the technical error. on fail message off clears it.
  • finish "Nothing to do for this employee" — end the run early as a success, with your message in the run log. Use it for instances the script has nothing to do for (e.g. an empty month): test the precondition at the top, finish, and the rest of the script never runs. The run reports completed, never failed.

Automatic restart

Give a stuck run a second chance without a person watching:

on stuck restart from checkpoint max 2            # resume from the last checkpoint, up to twice
on stuck restart from start max 3 with fresh browser  # start over with a clean browser
on stuck restart from command max 1              # retry just the failing command

Restarts run on your desktop. The automation only reports a final failure once the attempts are used up, and the run log shows each ↻ restart attempt. The built-in restart_attempt variable (0 on the first run, then 1, 2, …) lets a script behave differently on a retry.

Ask the assistant

When a run is stuck, open it and use Ask the assistant for a diagnosis and a suggested fix. You can pick your own configured AI, Nocarta AI, or — in the desktop app — the local Claude Code agent (which runs entirely on your machine and can look at the page screenshot without it ever leaving your computer). If the assistant proposes a change to the script, you can review the diff and apply it; a revertible version of the previous script is saved first.

Recipes: needs-help

When an automation runs as a step inside a Recipe and gets stuck, the whole recipe pauses in a needs help state instead of failing, and you (the owner) get an email. Open the run and choose Retry (run the step again with the same input), Skip (pass its input through unchanged), or Abort (cancel the run) — the same Ask the assistant diagnosis is available there too.

Need More Help?

Ask AI Assistant