Browser reference has every option and error code; this page is about which ones to reach for.
Verified against lua-cli 3.58.0.
Before you begin
- A project created with
lua initand signed in withlua auth configure(Install and sign in). browser: trueon the agent, or at least oneLuaBrowserinbrowsers, thenlua push agent.
Pick the narrowest way in
A browser session costs money and time. Start at the top of this list and only move down when the one above cannot do it.Browser.read opens its own session and closes it again, so it is the cheapest call in the API. Use the step-by-step commands when one page is not enough, and give them a sessionKey so they share one session:
Browser.execute for the parts you cannot pin down, give it a schema so the answer has a shape, and cap it:
Name the sites, always
allowedDomains is the one setting worth having on every browser. It is checked before every command that opens a URL, it covers redirects and everything a page loads, and it is enforced on the server, so a prompt-injected page cannot talk the agent into leaving.
src/browsers/supplier.ts
Ask before it submits, pays or sends
Put every action that changes something at the other end inconfirmActions. submit covers clicking Buy, Pay, Place order, Sign in or Send, and pressing Enter.
stopReason: 'confirmation_required' and a pendingAction. Tell the person what is waiting, in their words, and approve it from their next message:
Logins: ask for the least access
A saved login is the person’s own account, not the agent’s. Ask for one only when the page genuinely needs it, and ask forread unless the work really writes:
readcan open, navigate, scroll and read. Most work is read.actcan click, fill, type, select and press, and the person approves each one.act-autodoes those without asking. Ask for it only for work the person has already said yes to as a whole, such as a nightly task they set up.
- Never put a password in a tool, a prompt or an environment variable. There is no API that takes one. The person types it on a Lua page, and the browser fills it in.
- Never ask for a password or a verification code in the chat. When a site asks for a code, Lua sends the person a private link; say that, and stop.
- One login per site per person, named for the site:
'supplier','linkedin'. Asking again with the same name replaces that person’s login; a different name on the same site just leaves two logins to go stale. A name already saved against differentoriginsis refused withbrowser_login_origin_changed. - Return names and states from a tool, never a receipt. The receipt carries no link, but keep the habit.
Do not loop on a failed sign-in
A saved login is tried sparingly on purpose: one attempt per 30 minutes by default, and a sign-in that did not work starts a 30-minute cooldown. Sites lock accounts out, and a retry loop spends the person’s attempts for them.reason is already written for the person, so pass it along rather than inventing one. On too_many_attempts, say when they can try again and stop. On wrong_password, ask them to add the login again. On needs_verification, captcha or needs_approval, tell them a private link is on its way and that the run waits for them. Never start a second sign-in for the same login.
A signed-in session is saved and reused next time, so a second run usually comes back with restored: true and no sign-in at all.
Let a job use a login only with a grant
A job has nobody to ask, so a login is off limits to it until the person says otherwise on a live turn. The grant names the job by its id, whichJobs.getAll gives you:
browser_login_grant_required. The person can also remove the login or the grant themselves, which deletes the saved session, so handle a sign-in that stops working rather than assuming it will always be there.
Files: smallest cap, named types, mind the scan
Files are off until a browser setsmaxDownloadMb. Set the smallest number that fits the work, and name the types:
src/browsers/invoices.ts
scanStatus: 'scanning' and cannot be opened or uploaded until the malware scan clears it:
- There is no download by URL. Take a
snapshot, find the link or button, and click it withdownload({ ref }). - Files have their own confirm categories. Add
'download','upload'or'pdf'toconfirmActionswhen the person should see each file before it moves. - Uploads take only the same person’s own files, and only after their scan passed. If the file is from an older message, ask the person to send it again and upload it in that turn rather than digging for an old one.
- A file over the cap, or a run that has used up its per-run total, is refused with
file_cap. Download one file per run where you can. - Files are not available on the Browser-Use browser (
remote_session), and in a signed-in sessiondownloadanduploadneed anact-autologin.
Page scripts only when there is no command
Browser.eval is the last resort, not a shortcut. Reach for get, snapshot, find or extract first; use a script only for something no command exposes, such as a value the page computes.
allowScripts: true and an allowedDomains list naming a real domain, so a browser that can run scripts is always a browser locked to its sites. Keep that browser separate from the one that opens arbitrary pages. Scripts are developer-only: the chat model never runs them, Browser.execute never runs them, and they never run in a signed-in session. Add 'eval' to confirmActions when even your own scripts should wait for a person.
Keep sessions short
Sessions are the cost. A session stays open until you close it, its idle timeout passes (120 seconds by default), or its length limit does (10 minutes by default).- Use
Browser.readfor one page. It closes its own session. - Close what you open.
await Browser.close({ sessionKey })at the end of a tool, and in your error path too. - Do not raise the limits to cover a slow page. Raise
timeoutMson the call instead. - Watch concurrency. An agent may hold 3 cloud sessions at once for one person by default, and at most 3
Browser.executeruns; one too many fails withBROWSER_SESSION_LIMITorBROWSER_EXECUTE_CONCURRENCY. Give each piece of work its ownsessionKey, and do not open one per item in a loop. - Cap every
execute.maxStepsandmaxCostUsdare the only things between a confused model and a long bill.
Try it from the terminal first
Both commands run on the platform against the agent you pushed, so they show you exactly what your code will get:lua logs --type browser is where the browser tells you the truth: which engine ran, what it was refused, which wall it hit, which files it moved and which sign-ins it tried. Read it after every failure before changing code.
When it goes wrong
Next
Browser— every method, saved logins, files, page scripts, limits and error codesLuaBrowser— named browsers and every setting one takeslua browser— the terminal commands in full- Logs and debugging — reading agent logs

