how to use Selenium Mobile with cloud Android devices
how to use Selenium Mobile with cloud Android devices
if you want to use Selenium with cloud Android devices in 2026, the architecture matters more than the test code. Selenium itself does not drive Android devices natively; it speaks the WebDriver protocol against a server that does. for mobile, that server is Appium, which exposes the same W3C WebDriver endpoints as Selenium Grid. that means any Selenium-shaped test runner (TestNG, JUnit, pytest, mocha, Robot Framework) can drive a cloud Android phone with minor capability changes and the same wait, click, sendKeys vocabulary.
this guide covers the bridge: install Appium as a Selenium-compatible WebDriver server, point your Selenium client at it, drive both mobile-web (Chrome on Android) and hybrid app contexts, and parallelize across a fleet of real Singapore cloud phones.
why Selenium for mobile is really Appium underneath
Selenium drives desktop browsers via browser-specific drivers (chromedriver, geckodriver, msedgedriver). for mobile, the equivalent is Appium with the chromedriver bundled inside Appium for in-WebView automation, and the UiAutomator2 driver for native UI. Appium speaks the W3C WebDriver protocol, so every Selenium client library can talk to it.
practically, “Selenium Mobile” almost always means “Appium with a Selenium-shaped client.” the test code looks the same. the difference is in the capabilities (you specify platformName=Android instead of browserName=chrome) and the locator strategies (mobile UI uses resource-id and content-desc instead of CSS selectors, except in WebView contexts).
prerequisites
on your laptop or CI runner: Java 17 or newer, Node.js 20, Selenium client library for your language, Appium 2 with the UiAutomator2 driver.
# install Appium 2 and the UiAutomator2 driver
npm install -g appium
appium driver install uiautomator2
# install Selenium for Python
pip install selenium
# install Selenium for Java (Maven)
# add to pom.xml:
# <dependency>
# <groupId>org.seleniumhq.selenium</groupId>
# <artifactId>selenium-java</artifactId>
# <version>4.18.1</version>
# </dependency>
verify the install:
appium --version
appium driver list --installed
step 1: connect to your cloud phone
log in to cloudf.one and copy the ADB endpoint for your test phone.
adb connect adb-sg.cloudf.one:5555
adb devices
this is the same ADB endpoint pattern used by every other cloud-phone tool. our ADB setup guide covers troubleshooting if the connection fails.
step 2: start Appium
appium server --port 4723 --base-path /wd/hub
leave it running. Appium listens on http://localhost:4723/wd/hub, which is the URL Selenium clients will hit.
step 3: write a Selenium-style mobile-web test
mobile-web testing means automating Chrome on the cloud phone. this is the closest to traditional Selenium because the locators are CSS and the API is mostly identical to desktop Chrome.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
caps = {
"platformName": "Android",
"appium:automationName": "UiAutomator2",
"appium:deviceName": "cloudf-sg-01",
"appium:udid": "adb-sg.cloudf.one:5555",
"browserName": "chrome",
"appium:chromedriverExecutable": "/usr/local/bin/chromedriver",
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
driver.get("https://cloudf.one")
WebDriverWait(driver, 10).until(EC.title_contains("cloud"))
print("page title:", driver.title)
driver.quit()
this is a standard Selenium test. the only mobile-specific lines are the capabilities. everything else (find_element, WebDriverWait, send_keys) is identical to desktop Selenium.
step 4: write a native mobile test (UiAutomator2)
for native Android apps, switch to UiAutomator2 capabilities and use mobile locators.
from appium.webdriver.common.appiumby import AppiumBy
caps = {
"platformName": "Android",
"appium:automationName": "UiAutomator2",
"appium:udid": "adb-sg.cloudf.one:5555",
"appium:appPackage": "com.android.settings",
"appium:appActivity": ".Settings",
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,
'new UiSelector().text("Network and internet")').click()
driver.quit()
native locators include AppiumBy.ID (resource-id), AppiumBy.ACCESSIBILITY_ID (content-desc), AppiumBy.ANDROID_UIAUTOMATOR (Java DSL), and AppiumBy.XPATH (slow, last resort).
step 5: hybrid apps and context switching
hybrid apps embed WebViews inside a native shell. Selenium-style mobile tests can switch context between the native UI and the WebView.
contexts = driver.contexts # ["NATIVE_APP", "WEBVIEW_com.example.app"]
driver.switch_to.context("WEBVIEW_com.example.app")
# now CSS selectors work
driver.find_element(By.CSS_SELECTOR, "#submit-button").click()
driver.switch_to.context("NATIVE_APP")
# back to UiAutomator2 locators
for hybrid context switching to work, the WebView must be debuggable. enable WebView.setWebContentsDebuggingEnabled(true) in your app’s debug build.
step 6: parallelize via Selenium Grid 4
for parallel test execution, use Selenium Grid 4 with Appium nodes.
# grid-config.toml on the hub
[node]
detect-drivers = false
[[node.driver-configuration]]
display-name = "android-cloud"
max-sessions = 4
[[node.driver-configuration.stereotype]]
platformName = "Android"
appium:automationName = "UiAutomator2"
start the hub:
java -jar selenium-server.jar hub --config grid-config.toml
start an Appium node that registers with the hub:
appium server --port 4723 --use-drivers uiautomator2 \
--plugins-args '{"selenium-grid":{"hubUrl":"http://localhost:4444"}}'
now your tests can target the grid URL http://localhost:4444 and the hub will route to an available Appium node. with multiple cloud phones each driven by an Appium node, you parallelize across the fleet.
handling slow networks and flaky tests
the same patterns that apply to desktop Selenium apply here, with longer waits because cloud phones are remote.
# always use explicit waits
wait = WebDriverWait(driver, 30)
wait.until(EC.element_to_be_clickable((By.ID, "submit"))).click()
# avoid time.sleep
# avoid implicit waits (they conflict with explicit waits)
ADB-over-network adds 150 to 250 ms per call from outside Singapore. for tight timing, run tests from an Asia-Pacific runner.
if you want context on infrastructure decisions, see cloud phones for QA testing teams and CI/CD integration.
Selenium 4 vs Selenium 3 for mobile
Selenium 4 introduced standard W3C capabilities (appium: prefix, no more desiredCapabilities). Selenium 3 used the older JSON-Wire protocol. all examples in this post use Selenium 4 because Selenium 3 is end-of-life. the official Selenium docs cover the migration.
try Selenium on a real Singapore cloud phone
register for a free trial for a one-hour cloud phone token. that’s enough time to run the mobile-web example above and confirm Selenium drives the cloud phone end to end. then scale to a paid plan for ongoing test execution.
frequently asked questions
what’s the difference between Selenium and Appium for mobile?
Appium is a WebDriver server that drives mobile devices. Selenium is a client library that speaks WebDriver. for mobile testing, you use Selenium client + Appium server. the test code looks Selenium-shaped; the server underneath is Appium.
can I use the Selenium IDE recorder for mobile?
no, Selenium IDE records browser events, not mobile UI events. for mobile recording, use Appium Inspector (bundled with Appium) or Maestro Studio.
does Selenium Grid 4 support mobile nodes natively?
yes, Selenium Grid 4 added Appium support via the Selenium Grid plugin shipped with Appium 2. older Grid versions required a custom node, which is no longer needed.
can I run mobile-web and desktop Chrome tests in the same Selenium suite?
yes. use capabilities to route each test to the right node. mobile-web tests get platformName=Android, desktop Chrome tests get browserName=chrome and platformName=Linux. both run against the same hub URL.
how do I find element locators for native Android apps?
use Appium Inspector to inspect the live UI hierarchy. it shows resource-id, content-desc, and class for every visible element. avoid xpath when possible (slow on UiAutomator2).