← all articles

uiautomator2 vs Appium: which to use for Android automation

uiautomator2 appium android automation

First, the naming mess. Appium’s Android driver is called UiAutomator2. There’s also a Python library called uiautomator2, from the openatx project, which has nothing to do with Appium. The name keeps coming up because both are built on UI Automator, Google’s framework for driving any app’s UI from outside the app.

So under the hood they do the same thing: read the accessibility hierarchy, find a node, tap it. The differences are everything around that. How much you install, what languages you can write in, how many network hops each command takes, and what the rest of your team already uses.

The short answer: for Python scripts against phones you control, use uiautomator2. For a test suite that a QA team maintains, runs in CI, may need iOS later, or has to run on a commercial device cloud, use Appium.

Versions at the time of writing: uiautomator2 3.7.0 on PyPI (June 2026), needing Python 3.8 or later and Android 4.4 or later. Appium 3.7.0 on npm (August 2026) with UiAutomator2 driver 8.6.3, needing Node.js ^20.19.0 || ^22.12.0 || >=24.0.0 and npm 10 or later.

TL;DR comparison table

uiautomator2 Appium with the UiAutomator2 driver
What it is A Python library A WebDriver server plus installable drivers
Languages Python only Official clients for Java, Python, Ruby and C#; JavaScript (WebdriverIO) and others are community maintained
Install pip install uiautomator2 and adb Node.js, npm, a JDK, the Android SDK, then the driver
Path of one command Python, HTTP to a server jar on the phone Client, HTTP to the Appium server, driver, HTTP to server apps on the phone
iOS No Yes, through the XCUITest driver
Commercial device clouds Only where you get raw adb access The protocol most of them accept
Element inspector uiautodev Appium Inspector
Where it fits Scripts, RPA, data collection, your own phones QA suites, CI, cross-platform teams

uiautomator2 at a glance

You install one package and you’re done:

pip install uiautomator2
uiautomator2 version

Version 3 was a big cleanup. The old atx-agent daemon is gone, and so is the python -m uiautomator2 init step that older tutorials start with. The library now starts the UI Automator service on the phone at runtime, from a server jar that’s also open source (openatx/android-uiautomator-server-jar). According to the project’s 2-to-3 upgrade notes, connect() now only handles USB devices and devices already attached with adb connect, and connect_wifi() was removed. For a phone on Wi-Fi, connect it with adb first (see the ADB over Wi-Fi guide) and pass the ip:port serial.

A short script:

import uiautomator2 as u2

d = u2.connect("R58M12ABCDE")        # or an adb-connected "192.168.1.42:5555"
d.implicitly_wait(10.0)               # element lookups wait up to 10 s

d.app_start("com.android.settings", stop=True)
d(text="Network & internet").click()
if d.xpath('//*[@text="Internet"]').wait(timeout=5):
    d.screenshot("internet.png")

xml = d.dump_hierarchy(compressed=False, pretty=True)

Selectors take the familiar UiSelector fields (text, resourceId, className, description) and chain with .child() and .sibling(). d.xpath() handles XPath. There’s d.session("com.example.app") for scoping work to one app, d.settings['operation_delay'] for adding a pause around every click, and d.settings['wait_timeout'] for the global wait.

For finding selectors, the project recommends its own inspector: pip install uiautodev, then run uiautodev.

One honest caveat. The README is in English, but some of the docs, including the 2-to-3 upgrade notes, are mostly Chinese. It’s a well-used project, and you’ll still end up reading source code now and then.

Appium at a glance

Appium is a server that speaks the W3C WebDriver protocol, the same protocol Selenium uses for browsers. Since Appium 2, drivers are installed separately, so a fresh Appium install can’t drive anything until you add one.

Setup, following the Appium quickstart:

npm install -g appium
appium driver install uiautomator2
appium driver doctor uiautomator2
appium

The UiAutomator2 driver needs the Android SDK (Platform and Platform-Tools) with ANDROID_HOME set, and a JDK with JAVA_HOME set. appium driver doctor uiautomator2 checks both and tells you what’s missing. By default the server listens on port 4723. On first use the driver installs its own server apps on the phone (the io.appium.uiautomator2.server pair and io.appium.settings).

The same Settings test in Python, with the official client:

from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy

opts = UiAutomator2Options()
opts.udid = "R58M12ABCDE"
opts.app_package = "com.android.settings"
opts.app_activity = ".Settings"
opts.no_reset = True

driver = webdriver.Remote("http://127.0.0.1:4723", options=opts)
driver.implicitly_wait(10)
driver.find_element(
    AppiumBy.ANDROID_UIAUTOMATOR,
    'new UiSelector().text("Network & internet")',
).click()
driver.quit()

That ANDROID_UIAUTOMATOR locator is a UiSelector expression handed straight to UI Automator on the phone, which shows how close the two tools are underneath.

The Appium team maintains clients for Java, Python, Ruby and .NET (C#). JavaScript through WebdriverIO, and several others, are community maintained, according to Appium’s client list.

Head-to-head

Setup cost

uiautomator2 wins by a mile. pip install, a phone in adb devices, and your first script runs. Appium needs Node in a specific version range, a JDK, the Android SDK, environment variables, a driver, and a server process that has to be running before any test starts. None of it is hard. It’s a lot of moving parts on a fresh CI runner, though, and each one has a version to keep up to date.

Speed

I’m not going to quote timings. They depend far more on your app’s view hierarchy than on the framework, and any number I gave you would come from a different app.

What I can describe is the architecture. A uiautomator2 command goes from Python over HTTP to the jar on the phone. An Appium command goes from your client to the Appium server, into the driver, then over HTTP to the server app on the phone, and back the same way. So Appium adds a hop and a protocol translation to every call. In practice the slow parts of both are the same ones: dumping a big hierarchy, XPath searches over it, waiting for animations, and cold app starts.

The biggest speed-up for either tool costs nothing. Turn off system animations on your test phones:

adb shell settings put global window_animation_scale 0
adb shell settings put global transition_animation_scale 0
adb shell settings put global animator_duration_scale 0

And prefer resource IDs over XPath wherever the app gives you one.

Flakiness

Neither tool is flaky in itself. Tests get flaky because of animations, pop-ups that appear some of the time, slow networks, soft keyboards covering buttons, and phones that go to sleep. Both frameworks give you the same basic defence, which is waiting for an element instead of sleeping for a fixed time.

uiautomator2 has implicitly_wait(), per-call wait(timeout=...) and exists. It also has a watch_context() for auto-dismissing pop-ups, but the README now marks it deprecated and suggests checking for the pop-up before you click.

Appium has WebDriver’s implicit and explicit waits, plus driver capabilities for common annoyances, such as appium:autoGrantPermissions. One Appium behaviour catches people out: a session that receives no command for appium:newCommandTimeout seconds (60 by default) is ended by the server. Sit on a breakpoint for two minutes and your session is gone.

One rule applies to both. Don’t point them at the same phone at the same time. Both rely on Android’s UI Automator service, the two connections collide, and one of your scripts will fail with an error that doesn’t mention the other tool at all.

Language support

uiautomator2 is Python. That’s the whole list.

Appium’s language support is its strongest selling point, and still a weaker argument than it looks. It matters a lot if your QA team writes Java or C# and wants mobile tests in the same codebase as everything else. It matters very little if the person writing the automation already knows Python.

iOS and device clouds

This is where Appium is simply the answer. If there’s any chance you’ll need iOS, the same client code, test runner and reporting can drive iPhones through the XCUITest driver. And most commercial device clouds accept Appium sessions, because WebDriver gives them a clean remote protocol. uiautomator2 needs raw adb access to the phone, which you have on your own hardware and rarely get from a cloud vendor.

Running many phones in parallel

With uiautomator2 you create one Device object per serial and run each in its own thread or process. Every phone has its own server, so there’s no shared coordinator.

With Appium, each phone gets its own session. When one Appium server handles several Android sessions at once, give each session a distinct appium:udid and a distinct appium:systemPort (the local port the driver uses to reach that phone’s server), or sessions will trip over each other. Running one Appium server per phone is the other common layout.

Where Espresso fits

Both tools are black-box: they drive the app from outside, the same way a user would, and they can also touch system UI, notifications and other apps. If you own the app’s source and only want to test that app, Espresso is usually the better tool. It runs inside the app’s process and synchronises with the UI thread, which removes a whole class of timing flakiness, but it can’t leave your app. Appium also has an Espresso driver, if you want Espresso’s speed behind the WebDriver API.

Use-case verdicts

  • Automating a third-party app on phones you own, for RPA or data collection: uiautomator2. Less setup, direct Python, no server to babysit.
  • A QA team with an existing Java or C# test framework and a CI pipeline: Appium.
  • Anything that has to run on iOS as well, now or next year: Appium.
  • Running tests on a commercial device cloud: Appium.
  • A prototype or a one-off script you need working this afternoon: uiautomator2.

Who should pick uiautomator2

Pick it if you write Python, the phones are physically yours or at least reachable over adb, and the job is automation more than formal testing. That includes RPA flows, app-store checks, data collection, and scripted setup on a rack of phones. Pick it if you want to read the whole stack in an afternoon, too. The library plus one jar is small enough to understand end to end, and that pays off the first time something breaks in a way the docs don’t cover.

Who should pick Appium

Pick Appium if the automation is a product in its own right: a test suite with owners, reports and a CI gate. Pick it if your team writes Java, Ruby or C#, if iOS is on the roadmap, or if the phones live in someone else’s device cloud. The setup cost is real, but it’s paid once, and you get a standard protocol that most tools, vendors and new hires already know.

Verdict overall

There’s no universal winner, and it’s not a close call either once you know your situation. For scripting phones you control, start with uiautomator2 and move only when you hit a wall it can’t get past. For a team test suite, start with Appium and don’t try to save a day of setup by building on a Python-only library that the rest of the team can’t extend.

Whichever you choose, the device matters as much as the framework. A script tuned on an emulator can still fall over on a real Samsung or Xiaomi build, and what emulators miss compared with real devices covers why. To watch a run live while you debug selectors, scrcpy mirrors the phone to your desktop in read-only mode with --no-control.

Primary sources: the uiautomator2 repository, the Appium documentation and Android’s UI Automator guide.

Written by Xavier Fok

disclosure: ADB Handbook is published by the team that runs cloudf.one. This article contains no sponsored links. Last reviewed by Xavier Fok on 2026-09-11.

from the team behind cloudf.one
Passes on the emulator, fails on a real phone?

cloudf.one rents real Android phones in Singapore that you control from the browser, each on a persistent Singapore mobile IP. Real hardware, a real OEM build and a real carrier network, without buying and racking the phones yourself.

test on a real phone →
read on
More from ADB Handbook

adb commands, scrcpy flags, automation frameworks, and why a test passes on one phone and fails on the next.

browse all articles →