Skip to main content

Selenium Activities

Twenty-three activities drive a Chrome browser through WebDriver: open a session, navigate, interact with elements, read the page, and close it.

Playwright activities cover the same ground with a different engine. Prefer Playwright unless you specifically need Selenium — it needs no separate driver binary and its waiting is more reliable. Use Selenium where an existing WebDriver setup or a Selenium-only capability requires it.

The two providers differ in more than names: Selenium takes an object selector ({type, value}) where Playwright takes a string plus selector_type, and its timeouts are in seconds where Playwright's are in milliseconds.

Sessions

selenium.browser.create returns a session_id; every other activity takes it. A session is a live browser owned by one worker process, so the whole script — from browser.create to browser.close — must stay on that worker.

This is why every activity on this page runs locally by default (execute_locally: true). A local activity always runs in the calling workflow's own worker, which pins the session.

Do not set execute_locally: false

The workflow will still validate and start, but the session is no longer pinned to one worker and any step after browser.create can fail with an unknown session.

Always close the session

Sessions are per user and expire on a timer, but the per-user cap means leaked sessions eventually make browser.create fail. A worker restart destroys every live session; there is no reconnection.

Setup

No credentials. The worker needs Chrome or Chromium plus a matching chromedriver — the heavier of the two browser providers to provision.

VariableDefaultEffect
MOCO_CHROME_PATHPath to the Chrome binary
MOCO_CHROME_DRIVER_PATHPath to chromedriver
MOCO_SELENIUM_SESSION_TIMEOUT_SEC3600Idle time before a session is reaped
MOCO_SELENIUM_MAX_SESSIONS_PER_USER5Concurrent sessions one user may hold
MOCO_SELENIUM_SCREENSHOT_DIRWhere page.screenshot writes in file mode
MOCO_HTTP_PROXY, MOCO_HTTP_PROXY_BYPASSDefaults for the browser's proxy settings

Defaults

60 s timeout for browser.create, nav.goto and wait.element; 300 s for wait.time; 30 s for everything else. All default to 3 attempts and to local execution.

Retries replay interactions

max_attempts is 3 throughout, so an element.click that times out after the click landed will be clicked again. Set max_attempts: 1 on any interaction that is not safe to repeat.

Common input fields

Most activities take these. They are not repeated in every table below.

FieldTypeRequiredDefaultDescription
session_idstryesThe session from browser.create
selectorElementSelectoryesWhich element to act on
wait_timeoutintno10Seconds to wait for the element

ElementSelector

FieldTypeRequiredDefaultDescription
valuestryesThe selector itself
typeenumno"css"css, xpath, id, name, class_name or tag_name
selector:
type: css
value: "button.submit"

Browser lifecycle

selenium.browser.create

Launches Chrome and returns a session id.

Input

FieldTypeRequiredDefaultDescription
browser_typestrno"chrome"Browser to launch; only chrome is supported
optionsBrowserOptionsnonullLaunch options

BrowserOptions

FieldTypeRequiredDefaultDescription
headlessboolnotrueRun without a visible window
window_widthintno1920Window width
window_heightintno1080Window height
user_agentstrnonullCustom user agent
disable_gpuboolnotrueDisable GPU acceleration
disable_dev_shmboolnotrueDisable /dev/shm, needed in many containers
no_sandboxboolnofalseDisable the Chrome sandbox, required in some Docker environments
proxystrnoMOCO_HTTP_PROXYProxy URL, e.g. http://proxy:8080
proxy_bypass_liststrnoMOCO_HTTP_PROXY_BYPASSSemicolon-separated bypass patterns, e.g. localhost;127.0.0.1;*.local

Output

FieldTypeDescription
session_idstrPass this to every other activity
browser_typestrThe browser launched

Example

- activity:
name: open-browser
type: selenium.browser.create
input_data:
browser_type: chrome
options:
headless: true
window_width: 1440
window_height: 900
output_name: session

selenium.browser.close

Closes the session.

Inputsession_id. Output{success: bool}.

- activity:
name: close-browser
type: selenium.browser.close
input_data:
session_id: "{{ session['session_id'] }}"

selenium.browser.get_info

Inputsession_id.

Output

FieldTypeDescription
browser_typestrThe browser in use
created_atstrWhen the session was created
last_accessedstrWhen it was last used
window_handleslist[str]Open window/tab handles

selenium.nav.goto

Navigates to a URL.

Input

FieldTypeRequiredDefaultDescription
session_idstryesSession
urlstryesURL to open
timeoutintno30Navigation timeout in seconds

Output{current_url: str, status: str}.

- activity:
name: open-login
type: selenium.nav.goto
input_data:
session_id: "{{ session['session_id'] }}"
url: "https://app.example.com/login"
timeout: 30
output_name: landed

selenium.nav.back / selenium.nav.forward / selenium.nav.refresh

Move through history, or reload the current page.

Inputsession_id. Output{current_url: str}.


Element interaction

selenium.element.click

Clicks the matched element.

Input — common fields, plus scroll_into_view (bool, default true). Output{success: bool}.

- activity:
name: submit-login
type: selenium.element.click
input_data:
session_id: "{{ session['session_id'] }}"
selector:
type: css
value: "button[type=submit]"
retry_policy:
max_attempts: 1 # submitting twice would be wrong

selenium.element.type

Types text into an element, clearing it first by default.

Input — common fields, plus text (str, required) and clear_first (bool, default true). Output{success: bool}.

- activity:
type: selenium.element.type
input_data:
session_id: "{{ session['session_id'] }}"
selector:
type: id
value: "username"
text: "{{ username }}"

selenium.element.clear

Empties an input. Input — common fields. Output{success: bool}.


Reading elements

selenium.element.find

Locates one element or counts several.

Input — common fields, plus multiple (bool, default false).

Output

FieldTypeDescription
foundboolWhether anything matched
element_countintNumber of matches
elementslistMatched element descriptors
- activity:
name: count-rows
type: selenium.element.find
input_data:
session_id: "{{ session['session_id'] }}"
selector:
type: css
value: "table.results tbody tr"
multiple: true
output_name: rows # -> found, element_count, elements

selenium.element.get_text

Input — common fields. Output{text: str}.

- activity:
name: read-total
type: selenium.element.get_text
input_data:
session_id: "{{ session['session_id'] }}"
selector:
type: css
value: ".order-total"
output_name: total # -> text

selenium.element.get_attribute

Reads an HTML attribute as written in the markup.

Input — common fields, plus attribute_name (str, required). Output{value: str \| null}.

selenium.element.get_property

Reads a live DOM property, which can differ from the attribute — value on an input the user has typed into, for instance.

Input — common fields, plus property_name (str, required). Output{value: any}.

selenium.element.is_visible

Input — common fields. Output{visible: bool}.

selenium.element.is_enabled

Input — common fields. Output{enabled: bool}.


Page operations

selenium.page.get_html

Returns the rendered page source. Inputsession_id. Output{html: str}.

This is the usual hand-off point: render with Selenium, then parse the HTML elsewhere.

selenium.page.get_title

Inputsession_id. Output{title: str}.

selenium.page.get_url

Inputsession_id. Output{url: str}.

selenium.page.screenshot

Captures the page, or one element.

Input

FieldTypeRequiredDefaultDescription
session_idstryesSession
element_selectorElementSelectornonullCapture just this element; omit for the whole page
output_formatenumno"base64"base64 returns the image inline; file writes it to disk
file_pathstrnonullDestination path, required with output_format: file

Output{data: str, format: str} — the base64 image, or the path written to.

- activity:
name: capture
type: selenium.page.screenshot
input_data:
session_id: "{{ session['session_id'] }}"
output_format: base64
output_name: shot # -> data, format
Prefer file for large captures

A base64 image travels through workflow context and history. Writing to MOCO_SELENIUM_SCREENSHOT_DIR keeps it out, at the cost of the file only existing on that worker.

selenium.page.execute_script

Runs JavaScript in the page and returns its result.

Inputsession_id, script (str, required), args (list, optional, passed to the script). Output{result: any}.

- activity:
name: read-app-state
type: selenium.page.execute_script
input_data:
session_id: "{{ session['session_id'] }}"
script: "return window.__APP_STATE__.orders.length;"
output_name: order_count # -> result

Waiting

selenium.wait.element

Waits for an element to reach a condition.

Input

FieldTypeRequiredDefaultDescription
session_idstryesSession
selectorElementSelectoryesElement to wait for
conditionenumno"present"present (in the DOM), visible, or clickable (visible and enabled)
timeoutintno30Wait timeout in seconds

Output{success: bool, waited_seconds: number}.

- activity:
name: wait-for-results
type: selenium.wait.element
input_data:
session_id: "{{ session['session_id'] }}"
selector:
type: css
value: "table.results"
condition: visible
timeout: 15

selenium.wait.time

Waits a fixed number of seconds.

Inputsession_id, seconds (number, required). Output{success: bool}.

Prefer waiting for a condition

A fixed wait is either too short on a slow day or wasted time on a fast one. Use wait.element where you can.