Article

Selenium for mobile testing: where it works, and where Appium takes over

19 min read
Selenium for mobile testing

Teams that already run Selenium for web almost always ask the same question when mobile lands on the roadmap: is Selenium for mobile testing a realistic option, or do they need a different tool?

Selenium and Appium share a protocol and a mental model, but they solve different problems. Selenium drives web browsers. Appium drives mobile apps. The trouble starts when people assume the first can quietly do the second.

The short answer: can Selenium be used for mobile app testing?

Not for native apps. Selenium implements the W3C WebDriver protocol against browsers: Chrome, Firefox, Safari, Edge. It has no concept of an Android Activity or an iOS UIView. It cannot tap a native button, read a native accessibility ID, or interact with anything rendered outside a web view.

Where Selenium does fit mobile is the mobile web: your responsive site or web app running in a mobile browser. You can point Selenium at a mobile-emulated Chrome session, set a device viewport and user agent, and exercise the same DOM your desktop suite already knows. We walk through that workflow in testing mobile websites with Selenium.

That counts as mobile app testing only when the app is a website, meaning a Progressive Web App or a mobile browser flow, not a .apk or .ipa.

If your target is a native or hybrid app, Selenium alone will not reach it. That is exactly the gap Appium was built to close.

How Appium relates to Selenium

Appium extends Selenium by design. It speaks the same WebDriver protocol and exposes the same client-facing API. If you know driver.findElement(…) and driver.click() in Selenium, you already know most of Appium.

The difference is what sits behind the protocol:

  • Selenium translates WebDriver commands into browser automation via each browser’s driver (chromedriver, geckodriver, and so on).
  • Appium translates the same commands into native automation via platform drivers (the UiAutomator2 driver for Android, the XCUITest driver for iOS), and can also drive web views inside an app.

Because the client API is shared, an Appium test reads like a Selenium test. You still use Selenium’s client libraries under the hood. Appium adds mobile-specific capabilities (device name, platform version, app path, automation name) and mobile gestures (tap, swipe, long-press, scroll-to-element).

The examples and driver names in this guide assume Appium 2.x and Selenium 4. One thing to know if you last used Appium 1.x: in Appium 2.x the platform drivers are no longer bundled with the server. You install them explicitly (for example, appium driver install uiautomator2), which keeps the core lean and lets you version each platform driver independently of Appium itself.

Appium vs Selenium: head-to-head

Appium vs Selenium: head-to-head

DimensionSeleniumAppium
AutomatesWeb browsersNative, hybrid, and mobile-web apps
ProtocolW3C WebDriverW3C WebDriver (extends Selenium)
Android/iOS native UINoYes (UiAutomator2 / XCUITest)
Mobile web (browser)YesYes
Real devicesOnly via a browser/grid (for example, a real device cloud)Yes, first-class
Gestures (swipe, tap, pinch)No native supportYes
Hybrid apps (native shell + web views)NoYes; switches between native and web-view contexts in one session
Device behavior (rotation, hardware buttons, OS permission dialogs)No; the browser cannot reach the deviceYes, through driver commands and native UI automation
Setup footprintA language binding and a browser; Selenium Manager fetches driversNode.js, the Appium server, platform drivers, the Android SDK and/or Xcode
Speed per testFast; sessions start in secondsSlower; device allocation and app install add time
Parallel runsMany browser sessions per Grid nodeOne session per device
Language bindingsJava, Python, C#, JS, RubySame bindings via Appium clients
Best fitWeb at browser scaleEverything on-device

The split is web-only vs. web-plus-device. Appium is a superset of Selenium’s reach for mobile, at the cost of heavier setup and slower execution than a pure browser session.

Which one is right for your target?

“Better” depends entirely on what you are testing. Asking whether Appium is better than Selenium is like asking whether a truck is better than a sedan. It depends on what you’re hauling.

  • Testing a native Android or iOS app? Appium wins by default, because Selenium cannot do the job at all.
  • Testing a responsive website across mobile browsers? Selenium is the leaner, faster choice. You get browser-grade speed, mature grid infrastructure, and no device provisioning overhead.
  • Testing a hybrid app (native shell plus web views)? Appium, because it can move between the native context and the web-view context in a single session. Selenium cannot orchestrate that.

So Appium is not universally better. It is better where Selenium physically cannot go, and heavier where Selenium is already sufficient. The teams that get this wrong tend to force everything through one tool and then fight the tooling instead of the bugs.

What you need before your first mobile test

Setup is where the two paths differ most. Selenium for mobile web needs almost nothing your desktop suite doesn’t already have. Anything that touches a real device, including a real mobile browser, goes through Appium and brings its own toolchain.

ComponentSelenium: emulated mobile webAppium: real mobile browser or native app
Client librarySelenium for your language (for example, pip install selenium)The Appium client for your language (for example, pip install Appium-Python-Client), which builds on Selenium’s
Browser driverSelenium Manager (Selenium 4.6+) downloads chromedriver for youNone for native apps; for mobile Chrome, a chromedriver that matches the device’s Chrome
ServerNone locallyNode.js and the Appium server (npm install -g appium)
Platform driversNoneappium driver install uiautomator2 for Android, appium driver install xcuitest for iOS
Platform toolingDesktop ChromeAndroid SDK platform-tools (adb) for Android; a Mac with Xcode for iOS
Something to run onYour machine or CI runnerA real device, Android emulator or iOS simulator, locally or in a real device cloud
Finding locatorsBrowser DevToolsAppium Inspector for native screens; DevTools still works for web content

In a real device cloud, the device, platform-driver and Xcode rows are handled by the provider, which leaves only the client library to install on your side.

Before you write a test, confirm the device side is healthy. These checks catch most first-run failures:

  1. Run adb devices and confirm your Android device or emulator is listed as device, not unauthorized. If it is unauthorized, enable Developer Options and USB debugging, then accept the debugging prompt on the phone.
  2. Run appium driver list --installed and confirm the drivers you need are there.
  3. On recent Appium releases, run appium driver doctor uiautomator2 (or xcuitest) to catch missing dependencies such as an unset ANDROID_HOME.
  4. Start the server with appium and confirm it is listening on port 4723, the default.

Mobile automation testing using Selenium: what it looks like

When your target is genuinely mobile web, this is straightforward. You configure Chrome with a mobile emulation profile and run your normal Selenium suite against it:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

mobile_emulation = {"deviceName": "Pixel 7"}
options = Options()
options.add_experimental_option("mobileEmulation", mobile_emulation)

driver = webdriver.Chrome(options=options)
driver.get("https://your-mobile-web-app.example")
driver.find_element("css selector", "[data-testid='menu']").click()

This gives you a mobile viewport and a mobile user agent, enough to validate responsive layout, touch-friendly navigation, and mobile-specific web flows. What it does not give you is real device behavior: no real GPU rendering, no actual touch pressure or multi-finger gestures, no OS-level dialogs, no true device fragmentation, and no native components. Emulated mobile web is a fast first pass. It does not replace on-device coverage.

From emulation to a real mobile browser

Mobile emulation still runs your tests in desktop Chrome: Blink rendering, a desktop GPU and desktop memory, behind a phone-sized viewport. Your iPhone users never see that engine. Safari on iOS renders with WebKit, and other iOS browsers have historically been required to use WebKit too. A layout or JavaScript bug that only shows up in mobile Safari will pass every emulated run.

You can close that gap without leaving Selenium’s world. Your test stays a WebDriver test and your locators stay CSS. Only the session changes: instead of launching desktop Chrome, you ask an Appium server, local or in a real device cloud, for a browser session on a device.

Chrome on a real Android device

from appium import webdriver
from appium.options.android import UiAutomator2Options

options = UiAutomator2Options()
options.set_capability("browserName", "Chrome")
options.set_capability("appium:udid", "<device-serial>")  # from: adb devices

driver = webdriver.Remote("http://127.0.0.1:4723", options=options)
driver.get("https://your-mobile-web-app.example")
driver.find_element("css selector", "[data-testid='menu']").click()
driver.quit()

Safari on a real iPhone

from appium import webdriver
from appium.options.ios import XCUITestOptions

options = XCUITestOptions()
options.set_capability("browserName", "Safari")
options.set_capability("appium:udid", "<device-udid>")

driver = webdriver.Remote("http://127.0.0.1:4723", options=options)
driver.get("https://your-mobile-web-app.example")
driver.find_element("css selector", "[data-testid='menu']").click()
driver.quit()

Everything after the session is created is identical to the emulated test above. That is the point: you are still writing Selenium-style web tests, and Appium is only the bridge that gets a WebDriver session into a mobile browser.

Two things to know before you run these locally:

  • On Android, Appium drives Chrome through a chromedriver that has to match the Chrome version on the device. Point Appium at the right binary with the appium:chromedriverExecutable capability, or let it fetch a matching one by enabling its chromedriver_autodownload feature when you start the server.
  • On a real iPhone, Appium’s XCUITest driver needs WebDriverAgent built and signed with your Apple developer team, which means a Mac with Xcode. In a real device cloud, that provisioning is already done for you.

To run the same scripts on Kobiton’s real Android and iOS devices, swap the local Appium URL for your Kobiton endpoint. The test body does not change.

The moment your test needs to install an app, handle a permission prompt, switch between apps, or verify anything outside the DOM, you’ve hit the ceiling of Selenium and it’s time for Appium.

When to choose Selenium for mobile testing vs. Appium

Use this quick heuristic:

  • Native or hybrid app: Appium.
  • Mobile website, speed matters, no device-level behavior: Selenium.
  • Both (many teams have a web app and a native app): run both, sharing client libraries and CI patterns so the skills transfer.

Appium is the general-purpose default, but framework-specific tools like Playwright, Cypress, Maestro, and Detox can be a better fit for certain stacks. For a side-by-side of where each one lands, see the current landscape of mobile automation tools, and the Robot Framework paired with Appium walkthrough for a keyword-driven approach.

Migrating from Selenium to Appium without a rewrite

Because Appium reuses Selenium’s WebDriver client libraries, teams rarely start from zero. A common path looks like this:

  1. Keep your mobile-web suite on Selenium. Your existing responsive-layout and mobile-browser tests don’t change.
  2. Add an Appium session for native flows. Point a new set of tests at an Appium server with mobile capabilities (platformName, appium:deviceName, appium:app, appium:automationName). The driver object behaves the way you already expect from Selenium.
  3. Share the plumbing. Page-object patterns, explicit waits, assertions, and CI wiring carry over directly. Only the locators (accessibility IDs and native selectors instead of CSS) and the capabilities differ.

The same test, pointed at a native app

Here is the menu tap from the mobile-web example above, rewritten for a native Android build of the same app. Read it line by line against the Selenium version.

from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

options = UiAutomator2Options()
options.device_name = "Pixel 7"
options.app = "/path/to/your-app.apk"

driver = webdriver.Remote("http://127.0.0.1:4723", options=options)

menu = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "menu"))
)
menu.click()
driver.quit()

Four things changed, and none of them is test logic:

  • The import. webdriver now comes from the Appium client, which wraps Selenium’s.
  • The options. UiAutomator2Options replaces ChromeOptions and carries the mobile capabilities: platform, automation engine, device and the app to install.
  • The endpoint. The session is created on an Appium server instead of a local browser driver.
  • The locator. An accessibility ID replaces the CSS selector, because a native screen has no DOM.

The wait, the expected condition, click() and quit() are unchanged Selenium. That is why page objects and helper layers usually port with only their locators and session setup rewritten.

Adopting Appium is an additive step. The language bindings, test architecture, and CI patterns your team already has transfer, which is why “Appium vs Selenium” is rarely an either/or decision in a mature suite.

Hybrid apps: where your Selenium locators work again

A hybrid app is a native shell that renders some screens in a web view, such as a help center, a checkout page or a terms screen. Selenium cannot reach those screens, because the web view lives inside an app, not a browser. Appium can, and once it is inside, you are back on familiar ground.

Appium exposes each surface as a context. NATIVE_APP is the native UI, and each inspectable web view appears as a WEBVIEW_ context. Switch into the web view and the session behaves like a Selenium browser session: CSS selectors, the DOM and JavaScript execution all work.

# Native context: open the in-app help center
driver.find_element(AppiumBy.ACCESSIBILITY_ID, "Help").click()

# Find the web view and switch into it
print(driver.contexts)  # e.g. ['NATIVE_APP', 'WEBVIEW_com.example.app']
webview = next(c for c in driver.contexts if c.startswith("WEBVIEW"))
driver.switch_to.context(webview)

# Inside the web view, your Selenium habits apply
driver.find_element("css selector", "[data-testid='search']").send_keys("refunds")

# Back to the native UI
driver.switch_to.context("NATIVE_APP")

Web view contexts can take a moment to appear after a screen opens, so poll driver.contexts with a short wait rather than reading it once. If it only ever returns NATIVE_APP, the web view is not inspectable. That is a build setting, not a test problem:

  • Android: the app has to enable WebView debugging ( WebView.setWebContentsDebuggingEnabled(true)), usually in debug or test builds only.
  • iOS 16.4 and later: the WKWebView has to be marked inspectable ( isInspectable = true) in the build you test.

Ask your developers to turn both on for test builds once. After that, hybrid tests can reuse the web locators your team already maintains for that content.

What doesn’t transfer: Selenium habits to change on mobile

The API carries over. Some web-testing habits do not, and these are the ones behind most of the flakiness Selenium teams hit in their first month of mobile automation.

Web habitWhat happens on mobileDo this instead
CSS selectors and long XPathNative screens have no CSS. XPath works, but Appium has to serialize the whole screen’s UI tree to evaluate it, so deep XPath is slow and breaks when layouts shift.Ask developers for accessibility IDs (content-desc on Android, accessibilityIdentifier on iOS) and reach for AppiumBy.ACCESSIBILITY_ID first.
Implicit waits or sleep()Animations, app launch and slower devices make timing vary far more than in a desktop browser.Use explicit waits on the condition you need, such as clickable or visible, and keep implicit waits off so the two do not stack.
A fresh browser per testStarting an app session means allocating a device and often installing the build, which takes far longer than launching a browser.Where test independence allows, reuse a session across a test class and reset state deliberately, for example with terminate_app and activate_app. Use appium:noReset or appium:fullReset to control what persists between sessions.
Mouse-style actionsSwipes, long-presses and scrolls are gestures, and the legacy TouchAction API is deprecated in current Appium clients.Use W3C Actions, or the drivers’ mobile: gesture commands such as mobile: swipeGesture on Android.
Treating platform updates as background noiseA new Android or iOS release can break driver compatibility until the driver catches up.Pin driver versions (appium driver install uiautomator2@<version>) and run a smoke suite on the next OS version before it reaches your users.

None of these change your test architecture. They change locators, waits and session lifecycle, the same short list the migration section names as what differs.

Running Selenium and Appium at scale on real devices

Both Selenium mobile-web sessions and Appium native sessions run against the same WebDriver protocol, which means both can target a real device cloud without rewriting your tests. A real device cloud simply means your tests run on actual phones and tablets rather than emulators.

That matters, because emulators and mobile-emulated browsers miss the failures that only appear on actual hardware: vendor skins, low-memory throttling, real network conditions, and OS-version fragmentation.

Running mobile tests in parallel

Scaling mobile tests is not like scaling browser tests. A Selenium Grid node can run several browser sessions at once on one machine, but an Appium session owns its device for as long as it runs. Parallelism is a device count, not a thread count: ten parallel tests need ten devices, emulators or simulators.

If you run Appium in parallel yourself, give each session its own ports so they do not collide:

  • Android (UiAutomator2): a unique appium:systemPort per session, plus a unique appium:chromedriverPort if the session drives Chrome or a web view.
  • iOS (XCUITest): a unique appium:wdaLocalPort per session.
  • If you already run Selenium Grid 4, you can register Appium servers as Grid nodes through Grid’s relay configuration, so one endpoint serves desktop browsers and devices.

Then decide what runs where. A cadence that works for most teams:

WhenWhat runsWhere
Every commit or pull requestEmulated mobile-web checks and a native smoke suiteSelenium with Chrome mobile emulation; Android emulators and iOS simulators
NightlyFull mobile-web and native regressionReal devices across your priority OS versions and screen sizes
Before each releaseFull suite plus device-dependent checks such as permissions, interruptions and performanceReal devices, including your oldest supported OS and lowest-spec hardware

Kobiton runs your existing Appium and Selenium scripts on real Android and iOS devices without changing your test code. You keep the scripts. You swap the endpoint. 

For a broader survey of where each framework sits, see our survey of mobile testing tools and frameworks.

Bottom line

Selenium and Appium are two ends of one protocol. Selenium for mobile testing means mobile web, and it does that job well and fast. Appium uses an API you already know to reach everything Selenium can’t: native components, gestures, and real-device behavior. Map the tool to the target, run both against real devices, and the “Appium vs Selenium” debate stops being a debate.

Run your existing Appium and Selenium suites on real iPhones and Android devices. Start testing for free.

Frequently asked questions

Is Appium better than Selenium?

For native and hybrid mobile apps, yes. Selenium cannot automate them at all, so Appium is the only option. For responsive mobile-web testing, Selenium is lighter and faster and is often the better choice. They share the WebDriver protocol, so the “better” tool is simply the one that matches your target.

Can Selenium be used for mobile app testing?

Selenium can test mobile web apps, meaning websites and PWAs in a mobile browser. It cannot test native or hybrid apps, because it only speaks to browsers. For native app testing you use Appium, which extends the same Selenium WebDriver API to on-device automation.

Can Selenium test a mobile website on a real iPhone or Android phone?

Yes, through Appium. You request a browser session (Chrome on Android, Safari on iOS) from an Appium server, locally or in a real device cloud, and your Selenium-style web test runs unchanged in the real mobile browser. Desktop Chrome mobile emulation is faster, but it cannot reproduce real device behavior or Safari WebKit rendering.

Is Selenium still relevant for mobile testing in 2026?

For mobile web, yes. Selenium 4 is built on the W3C WebDriver standard and is still a fast way to check responsive layouts and mobile web flows in an emulated browser. It was never the tool for native apps. The WebDriver protocol Selenium standardized lives on in Appium, which is how most teams automate native and hybrid apps across Android and iOS.

What replaced Selendroid?

Appium. Selendroid was an early Selenium-style framework for Android that targeted old Android versions, and it has not been actively developed for years. Current Android automation uses the Appium UiAutomator2 driver, so Selendroid is not a practical choice for a new project.

Can Playwright or Cypress replace Selenium for mobile testing?

For emulated mobile web, Playwright is a strong alternative: it ships device profiles and can run tests on a WebKit build, which is closer to Safari than Chrome emulation is. Cypress can set the viewport and user agent but runs desktop browsers. Neither automates native or hybrid apps, so they compete with Selenium for the mobile-web part of your suite, not with Appium.

Do I need a Mac to test iOS with Selenium or Appium?

To run iOS simulators or real iPhones yourself, yes. The Appium XCUITest driver depends on Xcode, which only runs on macOS. A real device cloud removes that requirement, because the Macs and devices are on the provider side, and your tests can run from Windows or Linux CI.

Which tool is best for mobile test automation?

It depends on the target. Appium is the default for cross-platform native and hybrid apps, because it uses the WebDriver API your team may already know. Espresso on Android and XCUITest on iOS are faster platform-native options when developers own the tests and you only need one platform. For mobile web, Selenium or Playwright cover most needs.