Migrate Selenium browser journeys to Monito

Move brittle Selenium WebDriver journeys to Monito with Python conversions, explicit outcomes and a CI cutover. Keep isolated tests and Grid coverage.

Selenium WebDriver drives a browser locally or on a remote machine through the Selenium server. Source · checked 2026-10-23.

Move only the brittle full-browser journeys whose expected results you can review. Keep unit, component, API and fast isolated tests in their existing runners. A WebDriver migration starts with the test assertions and account setup, including behavior hidden inside page objects. Identify what the journey protects before deciding that replacing its locator code is worthwhile. Source 1 · checked 2026-10-23. Source 2 · checked 2026-10-23.

Our team uses illustrative Selenium Python examples below because the actions and explicit waits fit beside the resulting scenario. They use Selenium 4 APIs and fictional app selectors, not recovered customer specs. Configure BASE_URL and WAIT_SECONDS in your test environment and replace the fixture values. The benchmark reports show comparable behavior; they do not execute these examples. Source 1 · checked 2026-10-23. Source 2 · checked 2026-10-23.

What the source documentation says

WebDriver needs a test framework for assertions and reporting. Source · checked 2026-10-23.

Selenium's documentation lists pytest and unittest for Python. Source · checked 2026-10-23.

Explicit waits poll for a specific condition before continuing. Selenium warns against mixing implicit and explicit waits. Source · checked 2026-10-23.

Page objects keep knowledge of the page structure in one place. Assertions generally belong in the tests, with an exception for checking that a page loaded correctly. Source · checked 2026-10-23.

Selenium Manager ships with Selenium and discovers, downloads and caches drivers when none is supplied. It also supports automated browser management. Source · checked 2026-10-23.

Selenium Grid runs WebDriver scripts on remote machines and supports parallel testing across browsers, browser versions and operating systems. Source · checked 2026-10-23.

SeleniumHQ does not publish an official GitHub Action. Keep track of the test runner and browser setup your own CI job uses. Source · checked 2026-10-23.

What translates and what changes

Selenium concepts mapped to Monito
 SeleniumMonito
WebDriver test and page objectsPage objects keep knowledge of the page structure in one place. Assertions generally belong in the tests, with an exception for checking that a page loaded correctly. Source · checked 2026-10-23.Turn each selected user journey into a named scenario. Keep its starting path, actions and expected outcome together. There is no WebDriver spec importer or code export.

Read the test and its page objects together. A method name can hide account setup, navigation or assertions you still need to preserve.

LocatorsSelenium supports element locators including ID, name, CSS selector and XPath. Source · checked 2026-10-23.Describe the visible control and the action in plain English. Keep details that distinguish similar controls, such as the item name or the settings section.
Explicit waits and assertionsExplicit waits poll for a specific condition before continuing. Selenium warns against mixing implicit and explicit waits. Source · checked 2026-10-23.Put each required outcome in What to test. Preserve arithmetic and reload checks. Reaching a page or seeing a toast does not prove the saved state.

Keep useful Selenium tests in code. For a timing failure, identify the missing condition before deciding to migrate the journey.

Login and fixture setupInventory the credentials, cookies and prepared account state used by the test. Separate login from non-login data setup.Store email, password and any TOTP setup key in an environment login. Protected-preview request headers are also stored on the environment. These settings do not implement general prompt-variable substitution.

Save the authenticator setup key in the login's Advanced settings. Monito generates TOTP when signing in. HOTP is not supported.

Base URLRecord the target URL passed to driver.get and the environment your CI job selects.Create the environment with your app's base URL and set the scenario's starting path. Use --base-url on project run for a deployed preview. A preview URL does not authorize sending saved logins to a new origin; use an approved origin for an authenticated journey.
Retries and flake handlingInspect retries supplied by your test runner and the conditions that failed to become true. Source 1 · checked 2026-10-23. Source 2 · checked 2026-10-23.The agent chooses browser actions during each run. It can retry an inconclusive action within bounded limits and recover from transient model-provider errors while time remains. A measured mismatch of required behavior is a failure to report, not a reason to retry until green. Missing access or evidence remains an error. Read the report before rerunning; do not weaken the expected outcome to hide a failure.
CI jobSeleniumHQ does not publish an official GitHub Action. Keep track of the test runner and browser setup your own CI job uses. Source · checked 2026-10-23.A deploy webhook queues runs after deployment. For a blocking GitHub check, use the documented CLI project run workflow. Both integrations require Pro or Team.
Grid and parallel executionSelenium Grid runs WebDriver scripts on remote machines and supports parallel testing across browsers, browser versions and operating systems. Source 1 · checked 2026-10-23. Source 2 · checked 2026-10-23.Suite members launch side by side, with up to 5 launches in progress at once. This limits launch work, not the number of already running browsers. You do not configure CI shards. Give each journey independent test data so concurrent runs cannot overwrite the same cart or profile.

Monito does not run on your Selenium Grid. Keep Grid coverage when its browsers, versions or operating systems are part of the requirement.

Runner locationRecord any private network or runner location required by your existing browser sessions.Runs execute in us-east. You cannot select multiple regions. An environment selects the target app and login, not the runner's region. Monito has no private-location worker.
Scheduled CI jobsInspect your own CI configuration for recurring jobs that select these tests.Monito offers a single us-east region and an hourly minimum schedule. Schedule presets are hourly, every 6 hours, daily and weekly, in UTC.
Failure reportingRecord how your test runner reports failures and who responds to them. Source · checked 2026-10-23.Failed automated runs can email you when run-alert emails are enabled. Email is available on Free, Pro and Team; Slack notifications require Team. Failure emails go to your account's email address; turn them on or off under Settings, Run alerts. Connect Slack channels on Team.

Read the run report's measured checks, screenshots, network and console evidence. Recording is off for signed-in runs; masked screenshots are captured instead. Keep old traces, videos and screenshots separately; a new scenario starts its own run history.

Set up the scenario and its login

Create a project and an environment with your app's base URL. Give the scenario a Name and a Where value, either a starting path or a full URL. In What to test, put the instructions and expected outcome together. The examples separate those two parts for review; they are not an import file or separate required form fields. Select the environment you intend to run against. Replace the illustrative paths, account names and fixture data with values your application actually has.

Add the email and password as an environment login, then select its role in the scenario. For authenticator login, open Advanced and save the setup key; Monito generates the TOTP code during sign-in. Login secrets stay encrypted in server storage. Protected-preview request headers also belong on the environment, with encrypted values tied to its origin. These settings do not implement general prompt-variable substitution. A disposable email login needs your own Resend receiving domain, API key, expected sender and subject prefix. It reads a code or magic link for a new disposable address, not an existing fixed-email account.

Writing a scenario

Three converted browser journeys

These examples show how to rewrite intent. Each report link is a run of a comparable journey from our benchmark. It is not a run of your check or a validation of these illustrative configurations.

Replace login locators with the dashboard outcome

Before · python
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait


def test_account_dashboard_access():
    driver = webdriver.Chrome()
    try:
        wait = WebDriverWait(driver, float(os.environ["WAIT_SECONDS"]))
        base_url = os.environ["BASE_URL"].rstrip("/")
        driver.get(base_url + "/login")
        wait.until(EC.element_to_be_clickable((By.NAME, "email"))).send_keys(os.environ["QA_EMAIL"])
        wait.until(EC.element_to_be_clickable((By.NAME, "password"))).send_keys(os.environ["QA_PASSWORD"])
        wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[type='submit']"))).click()
        wait.until(EC.url_to_be(base_url + "/dashboard"))
        wait.until(EC.visibility_of_element_located((By.ID, "account-menu")))
        wait.until(EC.visibility_of_element_located((By.XPATH, "//h2[normalize-space()='Recent activity']")))
        assert not driver.find_elements(By.CSS_SELECTOR, "[role='alert'].login-error")
    finally:
        driver.quit()

Illustrative Selenium 4 Python test for pytest. Supply BASE_URL, WAIT_SECONDS, QA_EMAIL and QA_PASSWORD. The account uses password login without an authenticator challenge; the app removes the login error element on success. The test creates a fresh browser and leaves implicit waits unset. Source 1 · checked 2026-10-23. Source 2 · checked 2026-10-23. Source 3 · checked 2026-10-23. Source 4 · checked 2026-10-23.

After · Monito scenario
Name: Account dashboard access
Starting path: /login
Environment: Staging

Instructions: Sign in with the saved QA login and open the account dashboard.

Expected: The account menu and recent activity are visible. A sign-in error or unresolved login challenge does not pass.

Save the account as an environment login instead of pasting credentials into What to test. When the sign-in challenge itself is under test, select Start logged out under Options, or leave Reuse login sessions off on the login. Session reuse is off by default. If your actual flow uses an authenticator, save its setup key and include that challenge in the scenario. The benchmark below did not complete sign-in.

The run ended with an Error status, which our benchmark scores as cannot verify: the security check failed and no credentials were supplied. It illustrates an unresolved login prerequisite, not a successful sign-in or proof that your authentication will work.

Preserve checkout arithmetic after the explicit waits

Before · python
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait


def test_checkout_total_includes_shipping():
    driver = webdriver.Chrome()
    try:
        wait = WebDriverWait(driver, float(os.environ["WAIT_SECONDS"]))
        driver.get(os.environ["BASE_URL"].rstrip("/") + "/catalog")
        wait.until(EC.visibility_of_element_located((By.ID, "cart-empty")))
        wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "[data-product='test-mug'] button"))).click()
        wait.until(EC.element_to_be_clickable((By.LINK_TEXT, "Checkout"))).click()
        for field in ("address", "city", "postalCode"):
            wait.until(EC.element_to_be_clickable((By.NAME, field))).send_keys(os.environ[field])
        wait.until(EC.element_to_be_clickable((By.ID, "review-order"))).click()
        wait.until(EC.text_to_be_present_in_element((By.ID, "order-items"), "Test mug"))
        for field in ("subtotal", "shipping", "total"):
            wait.until(EC.visibility_of_element_located((By.ID, field)))
        wait.until(lambda browser: all(
            (browser.find_element(By.ID, field).get_attribute("data-cents") or "").isdigit()
            for field in ("subtotal", "shipping", "total")
        ))
        amounts = {
            field: int(driver.find_element(By.ID, field).get_attribute("data-cents"))
            for field in ("subtotal", "shipping", "total")
        }
        assert amounts["total"] == amounts["subtotal"] + amounts["shipping"]
        # Stop at review. Do not submit the order.
    finally:
        driver.quit()

Illustrative Selenium 4 Python test for guest checkout. Supply BASE_URL, WAIT_SECONDS and the non-secret address, city and postalCode environment values. The fictional app starts with an empty cart and exposes final review amounts as integer data-cents attributes. The test uses explicit waits only and a fresh browser. Source 1 · checked 2026-10-23. Source 2 · checked 2026-10-23. Source 3 · checked 2026-10-23. Source 4 · checked 2026-10-23.

After · Monito scenario
Name: Checkout review includes delivery
Starting path: /catalog
Environment: Staging

Instructions: Start with an empty cart, add the test mug and enter the staging shipping details supplied in the scenario. Open checkout review without submitting an order.

Expected: The review contains the item and shipping charge, and the displayed total equals their sum.

Copy the non-secret shipping fixture values into the scenario before saving it. The code reads app-specific amount attributes; the scenario checks the displayed amounts. Confirm that they express the same requirement before retiring the assertion. Keep the empty-cart prerequisite and stop-at-review instruction. Prepare or reset the cart outside the scenario when needed so a later run does not inherit another run's purchases.

The benchmark includes a working checkout and a cart whose total omits shipping. These reports exercise checkout behavior and arithmetic. They do not execute the illustrative example above.

Keep the saved profile check after a fresh page load

Before · python
import os
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait


def test_display_name_survives_reload():
    driver = webdriver.Chrome()
    try:
        wait = WebDriverWait(driver, float(os.environ["WAIT_SECONDS"]))
        base_url = os.environ["BASE_URL"].rstrip("/")
        driver.get(base_url + "/login")
        wait.until(EC.element_to_be_clickable((By.NAME, "email"))).send_keys(os.environ["PROFILE_EMAIL"])
        wait.until(EC.element_to_be_clickable((By.NAME, "password"))).send_keys(os.environ["PROFILE_PASSWORD"])
        wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[type='submit']"))).click()
        wait.until(EC.url_to_be(base_url + "/dashboard"))
        driver.get(base_url + "/settings/profile")
        name = wait.until(EC.element_to_be_clickable((By.NAME, "displayName")))
        assert name.get_attribute("value") not in (None, "Migration sample")
        name.clear()
        name.send_keys("Migration sample")
        wait.until(EC.element_to_be_clickable((By.ID, "save-profile"))).click()
        wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, "[role='status']"), "Profile saved"))
        wait.until(EC.text_to_be_present_in_element((By.ID, "member-list"), "Migration sample"))
        driver.refresh()
        wait.until(EC.visibility_of_element_located((By.NAME, "displayName")))
        wait.until(lambda browser: browser.find_element(By.NAME, "displayName").get_attribute("value") == "Migration sample")
        wait.until(EC.text_to_be_present_in_element((By.ID, "member-list"), "Migration sample"))
    finally:
        driver.quit()

Illustrative Selenium 4 Python test for a disposable profile account with password login. Supply BASE_URL, WAIT_SECONDS, PROFILE_EMAIL and PROFILE_PASSWORD. Reset the display name before each run. The fresh browser does not reset server-side data; elements are found again after refresh. Source 1 · checked 2026-10-23. Source 2 · checked 2026-10-23. Source 3 · checked 2026-10-23. Source 4 · checked 2026-10-23.

After · Monito scenario
Name: Display name survives reload
Starting path: /settings/profile
Environment: Staging

Instructions: Use the disposable profile account's saved login, starting with a different display name. Change it to Migration sample, save, inspect the member list and reload.

Expected: The success notice appears, the member list updates and Migration sample remains the display name after reload.

Keep the reload assertion and the account reset. A new WebDriver session supplies browser isolation, not a fresh profile value on the server. Recreate the data preparation in your own setup and give this scenario an account that other suite members do not modify. Check the report after reload; the success notice alone does not establish persistence.

The benchmark profile saves show both a persistent update and an update lost after reload. The latter still shows a success toast. Read the reload evidence before treating the visible confirmation as success.

Ask your coding agent to recreate the checks

You can ask your coding agent to recreate the checks through the hosted MCP server. Give it the public target URL, environment and non-secret intent. The check tool runs a URL and expectation. After reviewing the result, save_check saves that check under a name without starting another run. Use run_scenario for the saved scenario afterward. A check or run_scenario call spends credits. These tools do not import the source vendor's project.

Connect the hosted MCP server and provide the journey you reviewed above.

Agent prompt
Recreate this browser journey in Monito using the hosted MCP server. Use the intended project's environment and saved login. Call check with the public URL and the instructions plus expected outcome. Read the report and identify any missing prerequisites. If the scenario is correct, call save_check with its checkId and name. Use run_scenario with the saved scenarioId for subsequent runs. Keep credentials out of the expectation.

Cut over the trigger and schedule

  1. Select the browser journeys to move. Read their assertions, page objects, fixture setup, retry settings and CI selection. Keep unit, component, API and fast isolated tests in their existing runners. Keep browser tests that require Grid or particular browser versions and operating systems in the current job. Source 1 · checked 2026-10-23. Source 2 · checked 2026-10-23.
  2. Create the Monito environment, saved logins and a suite for the moved journeys. Preserve the observable assertions and prepare independent accounts and data. Run the old tests and new scenarios against the same deployed build. Investigate disagreements and confirm that a known broken outcome is detected before removing the old test selection.
  3. Replace the Python runner step for the moved journeys, for example python -m pytest tests/browser/test_migrated_journeys.py, with the blocking project run step below, after successful deployment. That path is illustrative; use your actual CI selection. Use the generated GitHub Actions authentication setup under Automations. Set PROJECT_ID to the destination project. Set SUITE_NAME to the suite containing the migrated journeys. Source 1 · checked 2026-10-23. Source 2 · checked 2026-10-23.
  4. Keep the rest of the suite running, including the driver setup, Grid services and fixture preparation that retained tests still use. Remove only the migrated tests from the old job after reviewing reports from the replacement trigger. Preserve old artifacts separately. Add recurring coverage with an appropriate schedule preset if these journeys also need checks between deployments. Source 1 · checked 2026-10-23. Source 2 · checked 2026-10-23.

For asynchronous checks, the deploy webhook returns 202 when runs are queued. That response does not mean they passed. Results appear in the dashboard; this request does not block the pipeline for a verdict. Deploy webhooks require Pro or Team.

For a blocking pipeline, configure GitHub Actions under Automations and use its generated authentication setup before adding this run step. Set GITHUB_TOKEN and grant checks: write. PROJECT_ID identifies the Monito project; PREVIEW_URL is the deployed target. The CLI waits for results and exits with code 1 if a scenario fails or errors. --github-check publishes the Monito GitHub check; the check is neutral when every test that didn't pass errored for a reason Monito caused, or when the CLI stops before it collects every result; other errors and failures mark it failed. The CLI exits 1 either way. The example pins the published CLI 4.8.1. A preview URL does not authorize sending saved logins to a new origin; use an approved origin for an authenticated journey.

Blocking GitHub check · shell
npx -y @monitodev/cli@4.8.1 project run "$PROJECT_ID" \
  --base-url "$PREVIEW_URL" --wait --github-check --suite "$SUITE_NAME"

Follow the GitHub Actions setup for authentication and permissions. The project run reference documents the command. GitHub Actions requires Pro or Team.

Without --suite, the command runs every scenario in the project, or the suite selected on the GitHub Actions automation. Pass --suite <name> or select a suite on the automation to limit it to the migrated journeys. Do not also fire a deploy webhook for the same deployment unless you intend duplicate runs. An asynchronous webhook is an alternative when the pipeline does not need to wait for a verdict.

Schedule allowance, regions and alerts

Schedule presets are hourly, every 6 hours, daily and weekly, in UTC. Runs execute in us-east; there is no region selector or multi-region execution. Failed automated runs can send email when run-alert emails are enabled. Email is available on Free, Pro and Team. Slack notifications require Team. Check the chosen environment, suite and notification preferences before relying on the schedule.

50 free test credits every month. Your balance refills to 50 on the 1st of each month (UTC), counting credits reserved by running tests. Unused credits are not added again; purchased credits are kept. Your signup credits count as the first month. Free includes one daily schedule. Verify your email to receive monthly refills. Any schedule other than that one daily schedule, a deploy webhook, GitHub Actions, and a public status page need Pro.

Check pricing before enabling the recurring workload. A slower schedule leaves a longer gap between checks; it changes the coverage you are buying.

When staying on Selenium fits better

Keep Selenium when the executable test and direct control over its assertions are what your team needs to review. A locator or wait problem can often be addressed in the existing test. Inspect the condition that failed to become true and the page object that owns the locator before deciding to change tools. Preserve useful tests that already express the requirement clearly. Source 1 · checked 2026-10-23. Source 2 · checked 2026-10-23.

Keep Grid when coverage across browsers, versions or operating systems is required. Monito runs desktop Chromium. It does not run component tests, provide multiple browser engines or export executable test code. Moving a browser journey does not preserve a Grid matrix, even if the same business outcome appears in both test descriptions. Source · checked 2026-10-23.

Review Selenium Manager before treating manual driver downloads as a reason to migrate. It already supplies driver and browser management. Keep executable fixture preparation, request mocks and assertions about internal state in code when they are part of the requirement. A scenario checks the browser outcome; it does not translate every line of a spec or prove that the entire old suite has moved. Source · checked 2026-10-23.

What to keep outside this migration

Keep unit, component, API and fast isolated tests in their existing runners. Move only brittle full-browser journeys such as signup, login, checkout, onboarding and settings persistence when their expected outcomes are observable.

Monito runs desktop Chromium. It does not run component tests, provide multiple browser engines or export executable test code. Monito does not run on your Selenium Grid.

Keep required account setup and internal-state assertions in code. Do not remove a login or email requirement to obtain a pass. A blocked challenge leaves this journey unverified; it does not establish that the dashboard works.

Validate your first scenario

Run the scenario against your own app and inspect the result before switching its trigger. Our team publishes the benchmark method and its limits on the reliability page. The reports above show comparable behavior; your application still needs its own validation.