Automation Guide
An automation is a script that does work for you — on a website, against an API, or in a Windows application. Every automation is written in the same language, NAL (Nocarta Automation Language), and comes in one of three kinds, chosen when you create it:
- Desktop — the Nocarta desktop app drives a web page in its own browser: the page commands, plus
js/pwwhen you need them - Browser — runs in your own browser tab, no desktop app needed:
httprequests andapicalls, for API work and data pipelines - Windows — the Nocarta desktop app drives a native Windows application
Requirements
Desktop and Windows automations need the Nocarta desktop app. They drive a real browser or a real application, so for security and functionality they run on your computer, not on the server. Browser automations run in the tab you are reading this in, on any device.
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 |
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 |
click "#row-9" holding "Shift" |
Clicks with keys held down — Shift extends a selection to that row, Control adds it without losing the rest. Combine them with +, as in holding "Control+Shift" |
if exists("#cookie-banner .accept") … click "#cookie-banner .accept" … end |
Clicks the element only if it exists — exists() 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 F1–F24 |
read focus |
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 |
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 "#total" blue |
Highlight with a specific color: red, blue, green, black, white, orange |
clear highlights |
Remove all highlights from the page |
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:
switch to frame "Body"— enter the Body framelist iframes— now shows iframes inside Body, not the top-level onesswitch to iframe "#iFrame_Tab"— enter the nested iframe- 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 framesto see the top-level layout - Use
list iframesinside 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 iframeonce 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 pagesto 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/1orfalse/no/0 - Secrets are supported:
fill table row 0 col 2 with "{{SECRET.VALUE}}" - Playwright variants:
read table pwandfill table pwuse 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 |
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" |
ask "how do I read a table?" |
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:
- Go to Settings
- Scroll to LLM Configuration
- Click Add LLM and choose a provider
- 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 & LLM Configuration guide for details.
How Automations Work
- Create: Choose a kind (Desktop, Browser or Windows) and write the script
- Bind: Connect secrets for credential injection (optional step)
- 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
- Navigate to New Automation
- 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)
- Click Next to go to Step 2
Step 2: Choose the kind
Choose where the automation runs and what it drives. The language is the same in all three — see NAL:
| Kind | Description | Best For |
|---|---|---|
| Desktop | The desktop app drives a web page in its own browser: page commands, js/pw, plus http and api. |
Websites, forms, portals, tables |
| Browser | Runs in your own browser tab, no desktop app: http requests and api calls, with the whole core language. |
API-based automation, webhooks, data pipelines, anything you want to run from a phone |
| Windows | The desktop app drives a native Windows application: the Windows commands, plus http and api. |
Legacy desktop software with no web interface |
Creating a Desktop automation
- After choosing Desktop in Step 2, you'll see the script editor
- Write the script — page commands, variables, loops, conditions, functions, instance data
- Click Create Automation to save
Quick Example:
url = "https://example.com"
open url
fill "#email" with "[email protected]"
click "#login-button"
validate exists("#dashboard")
Creating a Browser automation
- After choosing Browser in Step 2, you'll see the script editor
- Write the script:
httprequests andapicalls plus variables, loops, and conditions - Use Check syntax to validate before saving — it also names any command that needs the desktop app
- List the hosts the script may contact on the Settings tab
- Click Create Automation to save
Quick Example:
r = http get "https://api.example.com/users?page=1", {
headers: {Authorization: "Bearer {{API.TOKEN}}"}
}
validate r.status == 200
Creating a Windows automation
- After choosing Windows in Step 2, you'll see the script editor
- Write the script with the Windows commands (
launch,set value of,read grid,click button … in …, …) — see the NAL reference - Click Create Automation to save, then run it from the desktop app on a Windows machine
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 "#<id>" 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.
Selectors
Each command 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 selectorin 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:
- Create your secrets in the Vault first
- Open the created automation
- Go to the Bound Secrets tab
- Click Bind Secret
- Map a secret to a placeholder:
{{ALIAS.FIELD}}- Use the syntax:
{{STORE_NAME.VALUE}},{{STORE.USERNAME}},{{STORE.PASSWORD}},{{STORE.URL}} - In a Desktop or Windows automation:
fill "#email" with "{{MYSITE.USERNAME}}" - In an
httprequest, any kind:headers: {Authorization: "Bearer {{API.VALUE}}"}
- Use the syntax:
Security: Credentials are injected on your device at runtime — on the desktop app for Desktop and Windows automations, inside the browser sandbox for Browser automations. The server never sees the actual values during execution. Tier 2 secrets require your vault to be unlocked.
Executing Automations
From Web Interface
- Open the automation
- Click Execute
- If not on desktop: You'll be prompted to open the desktop app
From Desktop App
- Open Nocarta Desktop
- Navigate to Automations
- Click Run on any automation
- Watch the browser automation live
From Mobile (Dispatch)
- Open a Notebook on your phone
- Click Dispatch to Desktop
- Select the automation
- Execution starts on your desktop
From the API or an AI assistant
Your own code, or an AI assistant connected to your account, can start a run with POST /api/v1/automations/{id}/runs — the API page has the request and everything that comes back. The run still executes on a desktop: yours when the desktop app is connected, otherwise one Nocarta starts for you, which takes up to a couple of minutes.
Two things have to be true first:
- Remote execution is on — turn on desktop execution and browser dispatch under Settings → Remote Dispatch.
- The token may run, not only read — starting a run is its own permission, separate from editing a script.
Some runs are refused straight away rather than left waiting: an automation that uses vault credentials (only you can unlock the vault, at a desktop), a signed automation whose signature no longer verifies, an input that is missing or of the wrong type, or a second run while one is already going — one automation runs at a time per account. And because nobody is at the screen, ask fails the run instead of waiting for an answer.
Batches
For running the same automation with different inputs:
- Create an Automation Batch
- Add multiple runs with different parameters
- Execute the batch
- Each run executes sequentially with its own data
Use cases:
- Process multiple invoices
- Fill multiple forms
- Batch data entry
Writing the script
Every automation, whatever its kind, is written in NAL. The language itself — variables, conditions, loops, functions, the page commands, http and api requests, credentials, the data a run is given — is documented in one place: NAL — Nocarta Automation Language. This section covers only how the editor and the assistant work with a script.
The script is interpreted statement by statement by the same engine that powers the assistant chat — one language, one live variable environment shared by the chat, script runs, and the debugger. Anything you can type in the chat you can write in a script, and the other way round.
Editing a Desktop or Windows automation
- Navigate to New Automation or edit an existing one
- On the Description tab, the kind is Desktop or Windows
- Switch to the Editor tab — write your script there
- Click Run in Assistant to execute, or Update Automation to save
Browser automations
A Browser automation runs in an isolated sandbox inside your own browser tab — no desktop app, so it is the one kind that works on a phone. It uses the core language with http requests and api calls, exactly as described on the NAL page. 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 here 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 automation
- Navigate to New Automation or edit an existing one
- On the Description tab, set the kind to Browser
- A script editor appears — write your script there (the Check syntax button also flags verbs that need the desktop app)
- Click Update Automation to save
Running from Diagram Output
Browser automations can be linked to Notebooks for diagram-to-API automations:
- Analyze a diagram in a Notebook (Drawing Translator)
- On the diagram output page, link a Browser automation via settings
- Open the Convert dropdown and click Run Script
- 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.
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
list_id = "your-trello-list-id"
diagram.nodes.each do |node|
http post "https://api.trello.com/1/cards?key={{TRELLO.VALUE}}&token={{TRELLO_TOKEN.VALUE}}", {
body: {name: node.label, idList: list_id}
}
log "Created card: #{node.label}"
end
Security: Secret values ({{ALIAS.VALUE}}) 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 the record — export full execution data as JSON
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 interaction —
open,click,filland 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-Origincannot 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 automation that uses
askstops with a message saying so; run it as a Desktop automation when you need the assistant. Everything else in the language works here, includingcheckpointandon stuck restart(only itswith fresh browseroption 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 sleep before it |
| 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 webpageback- Go backforward- Go forwardrefresh- Reload pagescreenshot- Capture pagebrowser status- Check if browser is openclose browser- Close browser windowpress "Tab"- Send a key where the focus is;press "Enter" in "#search"focuses that element first. Chords (press "Control+A") andEscape/Delete/arrows/F1-F24included. A word that is not a key name still clicks that buttonread focus- Read the focused element's text; capture it withx = read focus
Recording (No AI needed)
start recording- Begin recordingstop recording- Stop recordingshow recorded actions- List captured actionssave as automation- Save recording
Element Selection & Text Search (No AI needed)
get selector- Click to pick elementclick "Submit"- Click first element matching visible text, name, id, or alt (explicit form:click text "Submit")find by text "Dashboard"- Find elements containing text and show their selectorsfind on selected- Extract elements from your current text selectionfind 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", thenclick "#{x}"if exists("#selector")…click "#selector"…end- 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, click text, fill — 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
Frames, Iframes & Link Discovery (No AI needed)
list iframes- Show all iframes/frames in the current contextlist links- List all links in the current frame with selectors and attributeslist links "<keyword>"- Filter links by keyword (text, href, class, name, id)switch to iframe "#id"- Enter an iframe by CSS selectorswitch to frame "Name"- Enter a frame by nameexit iframe- Return one level uphighlight "<selector>"- Highlight an element with a red outlinehighlight "#total" blue- Highlight with a color (red, blue, green, black, white, orange)clear highlights- Remove all highlights
Table Read & Fill (No AI needed)
read table- Read table contents with row/col indicesread table "#selector"- Read a specific table by CSS selectorfill 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 selectorclick ".myClass"- Click by class selectorclick "input[type=\"submit\"]"- Click by attribute selectorclick "div > span"- Click with CSS combinatorsclick "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 selectorfill "#myId" with "value"- Fill by ID selectorfill ".myClass" with "value"- Fill by class selectorfill "value" into "input[name=\"x\"]"- Alternative syntax
Secrets (No AI needed)
test secret {{ALIAS.VALUE}}- Test secret placeholder resolutionfill "{{ALIAS.VALUE}}" into "#password"- Fill with secret placeholderopen "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 pagejs document.title- Single-line JSjs fetch('/api?token={{AUTH.VALUE}}')- JS with secret injectionjs...end- Multi-line JavaScript block (Shift+Enter for newlines,endto finish)js from ~/script.js- Execute JavaScript from a local file (file stays on your machine)return- Needed as soon as the code is more than a single expression. A one-liner likejs document.titlegives its value back on its own; two statements withoutreturnstop with aSyntaxError
Capture the value with an assignment: title = js document.title. Secrets like {{AUTH.TOKEN}} are resolved locally on your desktop before injection.
Passing your variables into the code
Your script's variables are not visible inside js. The code runs in the page, so it sees the page's own globals and nothing of your script. Writing a variable's name in there sends the name, never the value — and the page answers name is not defined. Open a with block to hand the value over:
name = "Ada"
js with name
document.querySelector("#greeting").textContent = name
end
List as many as you need: js with first, last. Each one becomes an ordinary JavaScript variable at the top of your code, with its value already in place. with needs the block form — names and code cannot share one line.
Playwright Commands
Try type, fill, press and click first — they cover most typing and clicking, and they take your variables directly (type "#{name}"). Reach for pw when you need something those commands do not offer: it gives you the Playwright page object itself, the same API they use internally.
pw page.click('#btn')- Single-line Playwright commandpw await page.waitForSelector('.loaded')- Wait for an elementpw...end- Multi-line Nocarta Assistant script blockpw from ~/script.js- Execute Nocarta Assistant script from a local filereturn- Same rule asjs: needed as soon as the script is more than a single expression.pw page.title()gives its value back on its own; two statements withoutreturnstop with aSyntaxError
The script receives a page argument with the full Playwright Page API. Secrets are resolved before execution.
Your script's variables are not visible inside pw either — the body sees only page and frame. Pass a value in with a with block, exactly as for js:
def type_code(arg)
pw with arg
return await page.keyboard.type(arg)
end
end
Without with, pw page.keyboard.type(arg) fails with arg is not defined: the name reached the page, the value did not. For this particular example type "#{arg}" is simpler — plain commands read your variables without any of this.
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 environmentclear variables- Reset the variable environment
Reference a captured result by its bare name in expressions (employees.length, cells.includes("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 selectorsanalyze the page- Analyze page structure
Smart Commands (AI required)
search and click "<description>"- AI finds and clicks element by descriptionfind "the search box"- Find element and show selectorfill "<value>" into "<field description>"- Fill a field by descriptiontype "<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 run stops there and the remaining commands do not run
jscommands are not split by;(semicolons are valid JavaScript)
Example: Auto-Login Automation
open "https://app.example.com/login"
fill "#username" with "{{PORTAL.USERNAME}}"
fill "#password" with "{{PORTAL.PASSWORD}}"
click "button[type=\"submit\"]"
validate exists(".dashboard")
screenshot
Or record it:
- Type
open "app.example.com/login" - Type
start recording - Fill in username and password, click login
- Type
stop recording - Type
save as automation - 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 offclears 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.
Turning that email off
On the automation’s Settings tab, Email me when a run needs my attention controls that message. It is on for every new automation. Untick it for an automation you watch yourself, or one that stops often enough that the mail stops being useful.
The setting changes who gets told, never what the run does: the recipe still pauses at needs help, the run page still shows the panel, and Retry, Skip and Abort still wait for you. It applies to one automation at a time, so silencing a noisy one leaves the rest alone.
Need More Help?