Browser Automation
The browser is a first-class OcaltQL object. BROWSER OPEN creates a session, captured with SET. Every subsequent operation is subject-first — BROWSER ?session VERB ... SET ?result — exactly like every other domain in OcaltQL. Multiple sessions run in true parallel using the same AND/Multi/COLLAPSE mechanism used everywhere else in the language.
/api/data request so the network examples have real traffic to match. Press Try it and you get output, not an error.Session Lifecycle
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session NAVIGATE "https://ql.ocalt.com/tutorial/introduction" SET ?session
AFTER BROWSER ?session CLOSE
Interaction
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session CLICK "#menu" SET ?session
AFTER BROWSER ?session TYPE "#email" WITH "user@example.com" SET ?session
AFTER BROWSER ?session SELECT "#country" WITH "South Africa" SET ?session
AFTER BROWSER ?session HOVER "#dropdown" SET ?session
AFTER BROWSER ?session UPLOAD "#file" WITH "/root/document.pdf" SET ?session
AFTER BROWSER ?session CLEAR "#search" SET ?session
AFTER BROWSER ?session CLOSE
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session SCROLL X 0 Y 500 SET ?session
AFTER BROWSER ?session SCROLL X 200 Y 300 SET ?session
AFTER BROWSER ?session CLOSE
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session CLICK AT X 63 Y 125 SET ?element
AFTER EMIT "Clicked: " & ?element("tag") & " #" & ?element("id")
AFTER BROWSER ?session CLOSE
CLICK AT X n Y n clicks a raw pixel coordinate on the page rather than a CSS selector — the counterpart to selector-based CLICK "#id". It is the tool for driving the browser visually: when you are watching a live snapshot of the window and want to click a spot you can see, but have no clean selector for it. Coordinates are relative to the top-left of the viewport, in the same X n Y n form used by SCROLL.Reading and Extraction
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session READ ".itemlist" SET ?html
AFTER BROWSER ?session CLOSE
AFTER EMIT ?html
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session EXTRACT ".price" AS "text" SET ?text
AFTER BROWSER ?session EXTRACT "table" AS "json" SET ?data
AFTER BROWSER ?session EXTRACT "a.link" AS "attribute:href" SET ?href
AFTER BROWSER ?session EXTRACT ".item" AS "count" SET ?count
AFTER BROWSER ?session CLOSE
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session EVALUATE "document.title" SET ?title
AFTER BROWSER ?session EVALUATE "document.querySelectorAll('a').length" SET ?linkCount
AFTER BROWSER ?session CLOSE
AFTER EMIT ?title & " — " & ?linkCount & " links"
Waiting
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session CLICK "#load-more" SET ?session
AFTER BROWSER ?session WAIT 2 SET ?session
AFTER BROWSER ?session READ ".results" SET ?html
AFTER BROWSER ?session CLOSE
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session WAIT FOR "#result" SET ?session
AFTER BROWSER ?session READ "#result" SET ?html
AFTER BROWSER ?session CLOSE
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session CLICK "#load-more" SET ?session
AFTER BROWSER ?session WAIT FOR "#status" TO "Complete" SET ?session
AFTER BROWSER ?session CLOSE
AFTER EMIT "status reached Complete"
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session WAIT FOR NETWORK "*/api/data*" SET ?session
AFTER BROWSER ?session CLOSE
Navigation History
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session NAVIGATE "https://ql.ocalt.com/tutorial/introduction" SET ?session
AFTER BROWSER ?session BACK SET ?session
AFTER BROWSER ?session FORWARD SET ?session
AFTER BROWSER ?session RELOAD SET ?session
AFTER BROWSER ?session CLOSE
Focus and Tab
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session TAB NEXT SET ?session
AFTER BROWSER ?session TAB PREV SET ?session
AFTER BROWSER ?session FOCUS CHECK AS "id" SET ?focusedId
AFTER BROWSER ?session CLOSE
Session & State
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session STORAGE WRITE "theme" WITH "dark" SET ?session
AFTER BROWSER ?session STORAGE READ "theme" SET ?value
AFTER BROWSER ?session CLOSE
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session COOKIES SET ?cookies
AFTER BROWSER ?session COOKIE WRITE "session_id" WITH "abc123" SET ?session
AFTER BROWSER ?session CLOSE
BROWSER OPEN "https://postman-echo.com/get" SET ?session
AFTER BROWSER ?session AUTH "myuser:mypass" SET ?session
AFTER BROWSER ?session NAVIGATE "https://postman-echo.com/get" SET ?session
AFTER BROWSER ?session EVALUATE "document.body.innerText" SET ?echo
AFTER BROWSER ?session CLOSE
AFTER EMIT ?echo
Viewport and Device
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session VIEWPORT WIDTH 1920 HEIGHT 1080 SET ?session
AFTER BROWSER ?session CLOSE
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session MOBILE "iPhone 14" SET ?session
AFTER BROWSER ?session CLOSE
Output and Capture
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session SCREENSHOT "/root/snap.png" SET ?path
AFTER BROWSER ?session CLOSE
AFTER FILE SHARE ?path SET ?url
AFTER EMIT ?url
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session VIEW SET ?path
AFTER BROWSER ?session CLOSE
AFTER EMIT ?path
(* Output: /root/browser/now.png *)
BROWSER ?session VIEW captures the current browser window as a single snapshot, writes it to the fixed path /root/browser/now.png, and returns that path. Unlike SCREENSHOT, which writes to a caller-chosen path, VIEW always targets the same known location — so anything watching /root/browser/now.png always sees the most recent frame. There is no background loop and nothing to stop: each call to VIEW simply overwrites that one file with the window as it looks at that instant. Call it again whenever you want a fresh frame.Visual / Ghost Browsing
VIEW to drop the current window at /root/browser/now.png, FILE SHARE that path so you can watch it, then decide a spot from what you see and CLICK AT those coordinates. Call VIEW again to see the result, and repeat — navigate, look, decide, click, look again.BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session VIEW SET ?path
AFTER FILE SHARE ?path SET ?url
AFTER EMIT "Watch here: " & ?url
(* You look at the shared frame and decide where to click. *)
AFTER BROWSER ?session CLICK AT X 63 Y 125 SET ?element
AFTER EMIT "Clicked: " & ?element("tag")
AFTER BROWSER ?session VIEW SET ?path
AFTER FILE SHARE ?path SET ?url2
AFTER EMIT "After the click: " & ?url2
AFTER BROWSER ?session CLOSE
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session PDF "/root/invoice.pdf" SET ?path
AFTER BROWSER ?session CLOSE
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session DOWNLOAD "https://ql.ocalt.com/tutorial/api/data.json" TO "/root/file.zip" SET ?path
AFTER BROWSER ?session CLOSE
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session NETWORK LOG SET ?har
AFTER BROWSER ?session CLOSE
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session INTERCEPT "*/api/data*" SET ?captured
AFTER EMIT ?captured("url")
AFTER EMIT ?captured("method")
AFTER BROWSER ?session CLOSE
Live Streaming
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session STREAM TO "live-chart"
AFTER BROWSER ?session WAIT 5 SET ?session
AFTER BROWSER ?session CLOSE
(* Subscribers on the "live-chart" channel receive base64-encoded PNG frames *)
Parallel Sessions
Multiple browser sessions run in true parallel using the same AND/Multi/COLLAPSE mechanism as every other domain in OcaltQL. Each AND-chained statement writing to the same target variable builds a multivariable branch. No loop is needed — the branches exist natively.
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session1
AFTER BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session2
AFTER BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session3
AFTER BROWSER ?session1 EXTRACT ".price" AS "text" SET ?price
AND BROWSER ?session2 EXTRACT ".price" AS "text" SET ?price
AND BROWSER ?session3 EXTRACT ".price" AS "text" SET ?price
AFTER BROWSER ?session1 CLOSE
AFTER BROWSER ?session2 CLOSE
AFTER BROWSER ?session3 CLOSE
AFTER COLLAPSE ?price SET ?prices
AFTER EMIT ?prices
Reading What You Clicked
CLICK AT returns the element that was under the coordinate, not just the session —
a blind pixel click becomes self-describing. The returned object carries tag, id,
class, name, href, value, text and html,
plus session, which is why SET ?session still chains as before.
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session CLICK AT X 63 Y 125 SET ?element
AFTER EMIT "tag: " & ?element("tag")
AFTER EMIT "id: " & ?element("id")
AFTER EMIT "href: " & ?element("href")
AFTER EMIT "text: " & ?element("text")
AFTER BROWSER ?session CLOSE
Counting and Measuring
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session EXTRACT ".item" AS "count" SET ?items
AFTER BROWSER ?session EXTRACT ".price" AS "count" SET ?prices
AFTER BROWSER ?session EVALUATE "document.links.length" SET ?links
AFTER BROWSER ?session CLOSE
AFTER EMIT ?items & " items, " & ?prices & " prices, " & ?links & " links"
Watching Traffic End to End
The network verbs compose: wait for a request to happen, read the whole log, then pull the one you care about back out of it.
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session WAIT FOR NETWORK "*/api/data*" SET ?session
AFTER BROWSER ?session NETWORK LOG SET ?log
AFTER COUNT ?log SET ?total
AFTER BROWSER ?session INTERCEPT "*/api/data*" SET ?api
AFTER BROWSER ?session CLOSE
AFTER EMIT ?total & " requests; the api call was " & ?api("method") & " " & ?api("url")
Keyboard Navigation
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session TAB NEXT SET ?session
AFTER BROWSER ?session FOCUS CHECK AS "tag" SET ?tag
AFTER BROWSER ?session TAB NEXT SET ?session
AFTER BROWSER ?session FOCUS CHECK AS "id" SET ?id
AFTER BROWSER ?session CLOSE
AFTER EMIT "first: " & ?tag & " then: " & ?id
Full Pipeline Example
BROWSER OPEN "https://ql.ocalt.com/tutorial/fixture.html" SET ?session
AFTER BROWSER ?session TYPE "#email" WITH "user@example.com" SET ?session
AFTER BROWSER ?session TYPE "#password" WITH "secret" SET ?session
AFTER BROWSER ?session CLICK "#submit" SET ?session
AFTER BROWSER ?session WAIT FOR ".welcome-msg" SET ?session
AFTER BROWSER ?session EXTRACT ".welcome-msg" AS "text" SET ?msg
AFTER BROWSER ?session CLOSE
AFTER EMIT ?msg
SET. Every subsequent verb is subject-first: BROWSER ?session VERB .... Multiple sessions run in true parallel via AND-chained assignment to the same target, producing a native multivariable — no explicit loop required, only a final COLLAPSE.