Selenium Commands vs the Modern Automation API
From Selenium-derived Commands to the uiv.* API
Ui.Vision's classic table macros are Selenium-derived: the command | target | value format, the command names (click, type, storeText, verifyText...) and the locators all come from the Selenium IDE heritage. That made Ui.Vision instantly familiar to a generation of Selenium users — and it still works today.
The modern automation API takes the next step: a macro is a plain
JavaScript program built on the uiv.* API. Loops, conditions, retries and calculations
are real JavaScript — no more gotoIf label jumping, no !csvLine magic variables, no counting
end commands. Finders auto-wait, matches feed input tiers, and errors are ordinary exceptions.
Your existing Selenium-style macros keep working — nothing is removed or broken. And most users will never convert by hand: the built-in AI sidebar converts a classic macro to a JS script automatically when you ask it to fix or extend one (the original table macro file is never modified; the converted copy is saved to the "AI Generated" folder). This page is for everyone who wants to understand the new API coming from the Selenium world — every classic command and its modern translation.
The Big Five Differences
| Selenium-derived (classic) | Modern uiv.* API | Comment |
|---|---|---|
Variables: ${myvar}, created with store |
Plain JavaScript variables: const price = 42; |
uiv.getVar('!URL') / uiv.setVar(...) read and write the same pool the classic commands use — internal !-variables included. |
Flow control commands: if / while / times / forEach / label / gotoIf / gotoLabel / end |
Real JavaScript: if / else, for, while, for...of, functions |
Reads top to bottom instead of jumping between labels. |
Errors: !errorignore, !statusOK, onError |
try { ... } catch (e) { ... } and throw new Error('...') |
A failed uiv call throws a real exception — the catch block can say exactly what to do next. |
Waiting: waitForElementVisible, pause commands |
Finders auto-wait: uiv.$('css=.results') waits up to !TIMEOUT_WAIT, then throws |
Finding an element IS the wait. uiv.open() waits for the page load, a click that navigates is waited for automatically. |
Frames: selectFrame | index=2 before every access |
Not needed — uiv.$() finds elements in ALL frames, even cross-origin iframes, and in open shadow roots |
The selectFrame concept does not exist in the modern API. |
A Complete Example, Side by Side
A typical search flow — Selenium-style on the left, modern API on the right:
| Selenium-derived (classic) | Modern uiv.* API |
|---|---|
open | https://en.wikipedia.org
type | id=searchInput | Solar cell
sendKeys | id=searchInput | ${KEY_ENTER}
waitForElementVisible | id=firstHeading
storeText | id=firstHeading | myresult
echo | Landed on: ${myresult}
|
uiv.open('https://en.wikipedia.org');
uiv.page.type('id=searchInput', 'Solar cell');
uiv.browser.type('${KEY_ENTER}', {nav: true});
const h1 = uiv.$('css=#firstHeading'); // auto-waits
uiv.log(`Landed on: ${h1.text}`, 'green');
|
Input Commands: Three Explicit Tiers
Selenium WebDriver has one way to click. The modern API names how the input reaches the page — because that is what decides whether it works: uiv.page.* (fast synthetic DOM events, like Selenium), uiv.browser.* (trusted browser input via the debugger API — for canvas apps, drag & drop and sites that ignore synthetic clicks; Chrome/Edge, no XModule needed) and uiv.desktop.* (real OS input via the XModule — reaches OS dialogs and other apps).
| Selenium-derived (classic) | Modern uiv.* API | Comment |
|---|---|---|
| click | id=buy | uiv.page.click('id=buy') |
Locators work unchanged: css= id= name= link= xpath=. If a synthetic click is ignored, escalate to uiv.browser.click('id=buy') — a trusted event. |
| type | id=email | [email protected] | uiv.page.type('id=email', '[email protected]') |
Fills the field in one call, no click-to-focus needed. |
| sendKeys | id=q | ${KEY_ENTER} | uiv.browser.type('${KEY_ENTER}', {nav: true}) |
Keystrokes go to the focused element. {nav: true} waits for a navigation the keystroke causes. |
| select | id=cars | label=Volvo | uiv.page.select('id=cars', 'Volvo') |
Also 'value=...' / 'index=N'. Works even when the select is hidden behind a styled skin. |
| check / uncheck | id=box | uiv.page.click('id=box') plus a read-back of the checked state via uiv.eval |
|
| mouseOver | css=.menu | uiv.browser.move('css=.menu') |
A real hover, so CSS hover menus open. |
| dragAndDropToObject | uiv.browser.down(start); uiv.browser.up(end) |
Press, move, release. Every uiv.browser.move between down and up drags. Works on canvas apps and sliders that ignore synthetic drag events. |
| clickAt (deprecated) | uiv.browser.click(x, y) |
Coordinates in viewport CSS pixels — or better, click a match from a finder. |
| editContent | css=.editor | text | uiv.browser.click('css=.editor'); uiv.browser.type('text') |
Rich text editors (contenteditable) want real keystrokes. |
| XClick / XType / XMove / XMouseWheel | uiv.desktop.click(...) / .type(...) / .move(...) |
Real OS input in screen pixels, via the XModule. For OS dialogs and desktop apps. Visual targets: uiv.desktop.click(uiv.findImage('ok.png', {scope: 'desktop'})). |
Finding Things: DOM, Vision, OCR and AI
The modern API separates finding from acting. Every finder returns a match
{x, y, rect, text, value, ...} that feeds any input tier — and every finder auto-waits.
This goes beyond Selenium: images, OCR text and AI-located elements are found the same way DOM elements are.
| Selenium-derived (classic) | Modern uiv.* API | Comment |
|---|---|---|
| (locator in a command's Target) | uiv.$('css=#buy') — first match; uiv.$$('css=tr') — all matches |
Finds in all frames and open shadow roots. @POS=3 becomes an array index: uiv.$$('link=read more')[2]. |
| visualSearch / visualAssert | button.png | uiv.findImage('button.png') / uiv.findImages(...) |
[email protected]#2 becomes uiv.findImages('button.png', {minScore: 0.8})[1]. The finder throws if nothing appears — that IS the assert. |
| OCRSearch | Checkout | n | uiv.ocr.findTexts('Checkout', {required: false}).length |
And uiv.ocr.findText(...) returns the first match to click or hover: uiv.browser.click(uiv.ocr.findText('Checkout')). |
| OCRExtract / OCRExtractRelative | uiv.ocr.read() for the viewport, uiv.ocr.read({area: ...}) for a region |
"The number next to 'Total'": find the anchor with uiv.ocr.findText('Total'), then read an area next to its rect. |
| Relative targets: word#R120,0 and green/pink relative images | uiv.offset(match, dx, dy) |
Compose it: uiv.browser.click(uiv.offset(uiv.ocr.findText('Email:'), 120, 0)). With an image anchor, fractions of the anchor's own rect make the offset scale-proof. |
| visionLimitSearchArea | {area: match | rect} option on any visual finder |
Per-call instead of hidden state: uiv.findImage('handle.png', {area: uiv.$('css=#slider')}). |
| aiPrompt / aiScreenXY / aiComputerUse | uiv.ai.ask(prompt, {images, json}) / uiv.ai.find('the blue Buy button') / uiv.ai.computerUse(task) |
uiv.ai.find returns a match like any finder: uiv.browser.click(uiv.ai.find('the search icon')). |
Reading & Scraping
| Selenium-derived (classic) | Modern uiv.* API | Comment |
|---|---|---|
| storeText | css=h1 | myvar | const title = uiv.$('css=h1').text |
The match already carries the text. |
| storeValue | id=email | myvar | uiv.$('id=email').value |
|
| storeAttribute | id=link@href | myvar | uiv.eval("return document.querySelector('#link').href") |
uiv.eval runs JavaScript inside the website and returns the result. |
| storeTitle | uiv.eval('return document.title') |
|
| storeXpathCount | uiv.$$('xpath=...').length |
Also the clean existence test: 0 means not present, no error. |
| storeChecked | uiv.eval("return document.querySelector('#box').checked") |
|
| sourceSearch / sourceExtract | uiv.eval('return document.documentElement.outerHTML') + a JS regex |
One fetch of the source, then normal String/RegExp methods. |
| executeScript / executeScript_Sandbox / storeEval | Plain JavaScript — or uiv.eval(code) when the code must run inside the page |
Most executeScript_Sandbox commands simply disappear: the script IS JavaScript. |
| assertText / assertTitle / assertValue / assert... | if (h1.text !== 'expected') throw new Error('...') |
An if plus throw — and the error message can include the actual value. |
Data: CSV, Downloads, Screenshots
| Selenium-derived (classic) | Modern uiv.* API | Comment |
|---|---|---|
| csvRead + !COL1..N + !csvReadLineNumber loop | const rows = uiv.csv.read('data.csv') |
The whole file as a 2D array — loop with for (const row of rows). No line-number bookkeeping. |
| store into !csvLine + csvSave | uiv.csv.append('log.csv', [timestamp, value]) |
A row is just an array. uiv.csv.write(...) overwrites, uiv.csv.read(...) reads back. |
| csvReadArray / csvSaveArray | uiv.csv.read(...) / uiv.csv.write(...) |
Arrays are native to JavaScript. |
| onDownload + saveItem | const file = uiv.download('css=a.installer', {as: 'setup.exe'}) |
Downloads, renames, waits for completion and returns the on-disk name. Also takes a plain URL, or a trigger function for JS-generated downloads. |
| captureScreenshot | uiv.shot.viewport('name') |
|
| captureEntirePageScreenshot | uiv.shot.page('name') |
Whole page, scroll-stitched. Pipes into OCR: uiv.ocr.read({image: uiv.shot.page()}). |
| storeImage | locator | name | uiv.shot.element('css=#chart', 'name') |
|
| captureDesktopScreenshot | uiv.shot.desktop('name') |
Needs the XModule. |
| localStorageExport | uiv.exportToDownloads(name) |
Copies a .png, .csv or 'log' from Ui.Vision storage into the browser's Downloads folder. |
Tabs, Windows, Waiting, Logging
| Selenium-derived (classic) | Modern uiv.* API | Comment |
|---|---|---|
| selectWindow | tab=1 / tab=open / tab=close | uiv.tabs.select(n) / uiv.tabs.open(url) / uiv.tabs.close() / uiv.tabs.list() |
Indexes are absolute (1..N, what the tab bar shows) and every call returns {index, title, url} so the script can verify where it landed. For title=... matching the classic form remains available via uiv.run. |
| selectFrame | (not needed) | Finders pierce all frames automatically. |
| waitForElementVisible / waitForElementPresent | uiv.$(locator) — auto-waits and throws on timeout |
Optional elements: uiv.$(loc, {required: false, timeout: 2}) returns null instead of throwing. |
| waitForElementNotVisible | poll: uiv.findElements(loc, {required: false, timeout: 1}).length === 0 |
|
| pause | 3000 | uiv.sleep(3000) or uiv.sleep('3s') |
Last resort — finders auto-wait, so most pauses simply disappear in conversion. |
| echo | hello | green | uiv.log('hello', 'green') |
Same colors, including '#shownotification'. |
| prompt | Enter value | uiv.banner('Your turn: ...') + a poll loop |
The on-page banner asks the human without blocking the page; the script polls until the input is complete. Great for attended automation and captcha hand-offs. |
| comment | // a JS comment |
|
| throwError | message | throw new Error('message') |
|
| run | subMacro | // @include path/to/Sub.js + a function call |
The include is spliced in before the script compiles; uiv.main is true only in the file that was started, so an included file's self-test does not run. |
The Legacy Bridge: uiv.run()
A few rarely-used commands have no dedicated uiv.* method — by design, because they are one-liners either way.
uiv.run(command, target, value) runs any classic command from inside a script:
uiv.run('setProxy', ...), uiv.run('XRun', ...), uiv.run('deleteCookies'),
uiv.run('bringBrowserToForeground'), uiv.run('visualGetPixelColor', '100,200', 'px'),
uiv.run('selectWindow', 'title=Invoice*'). So the conversion table above is complete by construction —
anything not listed rides through uiv.run unchanged.
Try It: Ask the AI to Convert Your Macro
The fastest conversion is no conversion at all: open your classic macro in Ui.Vision, open the AI sidebar and ask it to "fix" or "convert this macro to a JS script". The AI reads the table, translates every command to the uiv.* API (keeping your targeting technique — visual macros stay visual), runs the result and verifies it. Your original table macro is never touched: the JS version is saved as a new copy in the "AI Generated" folder.
If a conversion question is not answered here — or you find a Selenium-style construct that resists translation — please post it in the RPA forum. We read everything and expand this page from your feedback.
See also
The uiv.* API overview, Ui.Vision RPA docs, Selenium IDE style command reference, iMacros to Ui.Vision migration, XModules for desktop automation, AI integration docs
Anything wrong or missing on this page? Suggestions?
...then please contact us.