About Appium

Introduction to Appium

Appium is an open-source tool for automating native, mobile web, and hybrid applications on iOS and Android platforms. Native apps are those written using the iOS or Android SDKs. Mobile web apps are web apps accessed using a mobile browser (Appium supports Safari on iOS and Chrome or the built-in ‘Browser’ app on Android). Hybrid apps have a wrapper around a “webview” – a native control that enables interaction with web content. Projects like Phonegap, make it easy to build apps using web technologies that are then bundled into a native wrapper, creating a hybrid app.

Importantly, Appium is “cross-platform”: it allows you to write tests against multiple platforms (iOS, Android), using the same API. This enables code reuse between iOS and Android testsuites.

For specific information about what it means for Appium to “support” its platforms, and automation modalities, please see the platform support doc.

Appium Philosophy

Appium was designed to meet mobile automation needs according to a philosophy outlined by the following four tenets:

  1. You shouldn’t have to recompile your app or modify it in any way in order to automate it.
  2. You shouldn’t be locked into a specific language or framework to write and run your tests.
  3. A mobile automation framework shouldn’t reinvent the wheel when it comes to automation APIs.
  4. A mobile automation framework should be open source, in spirit and practice as well as in name!

Appium Design

So how does the structure of the Appium project live out this philosophy? We meet requirement #1 by using vendor-provided automation frameworks under the hood. That way, we don’t need to compile in any Appium-specific or third-party code or frameworks to your app. This means you’re testing the same app you’re shipping. The vendor-provided frameworks we use are:

We meet requirement #2 by wrapping the vendor-provided frameworks in one API, the WebDriver API. WebDriver (aka “Selenium WebDriver”) specifies a client-server protocol (known as the JSON Wire Protocol). Given this client-server architecture, a client written in any language can be used to send the appropriate HTTP requests to the server. There are already clients written in every popular programming language. This also means that you’re free to use whatever test runner and test framework you want; the client libraries are simply HTTP clients and can be mixed into your code any way you please. In other words, Appium & WebDriver clients are not technically “test frameworks” – they are “automation libraries”. You can manage your test environment any way you like!

We meet requirement #3 in the same way: WebDriver has become the de facto standard for automating web browsers, and is a W3C Working Draft. Why do something totally different for mobile? Instead we have extended the protocol with extra API methods useful for mobile automation.

It should be obvious that requirement #4 is a given – you’re reading this because Appium is open source.

Appium Concepts

Client/Server Architecture
Appium is at its heart a webserver that exposes a REST API. It receives connections from a client, listens for commands, executes those commands on a mobile device, and responds with an HTTP response representing the result of the command execution. The fact that we have a client/server architecture opens up a lot of possibilities: we can write our test code in any language that has a http client API, but it is easier to use one of the Appium client libraries. We can put the server on a different machine than our tests are running on. We can write test code and rely on a cloud service like Sauce Labs to receive and interpret the commands.

Automation is always performed in the context of a session. Clients initiate a session with a server in ways specific to each library, but they all end up sending a POST /session request to the server, with a JSON object called the 'desired capabilities’ object. At this point the server will start up the automation session and respond with a session ID which is used for sending further commands.

Desired Capabilities
Desired capabilities are a set of keys and values (i.e., a map or hash) sent to the Appium server to tell the server what kind of automation session we’re interested in starting up. There are also various capabilities which can modify the behavior of the server during automation. For example, we might set the platformName capability to iOS to tell Appium that we want an iOS session, rather than an Android one. Or we might set the safariAllowPopups capability to true in order to ensure that, during a Safari automation session, we’re allowed to use JavaScript to open up new windows. See the capabilities doc for the complete list of capabilities available for Appium.

Appium Server
Appium is a server written in Node.js. It can be built and installed from source or installed directly from NPM: $ npm install -g appium $ appium

Appium Clients
There are client libraries (in Java, Ruby, Python, PHP, JavaScript, and C#) which support Appium’s extensions to the WebDriver protocol. When using Appium, you want to use these client libraries instead of your regular WebDriver client. You can view the full list of libraries here.

Appium.app, Appium.exe
There exist GUI wrappers around the Appium server that can be downloaded. These come bundled with everything required to run the Appium server, so you don’t need to worry about Node. They also come with an Inspector, which enables you to check out the hierarchy of your app. This can come in handy when writing tests.

Getting Started

Congratulations! You are now armed with enough knowledge to begin using Appium. Why not head to the getting started doc for more detailed requirements and instructions?


Appium is an open source, cross-platform test automation tool for native, hybrid and mobile web apps, tested on simulators (iOS, FirefoxOS), emulators (Android), and real devices (iOS, Android, FirefoxOS).

Supported Platforms

See the platform support doc for more detailed information.

Why Appium?

  1. You don’t have to recompile your app or modify it in any way, due to use of standard automation APIs on all platforms.
  2. You can write tests with your favorite dev tools using any WebDriver-compatible language such as Java, Objective-C, JavaScript with Node.js (in promise, callback or generator flavors), PHP, Python, Ruby, C#, Clojure, or Perl with the Selenium WebDriver API and language-specific client libraries.
  3. You can use any testing framework.

Investing in the WebDriver protocol means you are betting on a single, free and open protocol for testing that has become a defacto standard. Don’t lock yourself into a proprietary stack.

If you use Apple’s UIAutomation library without Appium you can only write tests using JavaScript and you can only run tests through the Instruments application. Similarly, with Google’s UiAutomator you can only write tests in Java. Appium opens up the possibility of true cross-platform native mobile automation. Finally!

I don’t get it yet…

If you’re new to Appium, or want a fuller description of what this is all about, please read our Introduction to Appium Concepts.


Your environment needs to be setup for the particular mobile platforms that you want to run tests on. See below for particular platform requirements.

If you want to run Appium via an npm install, hack with or contribute to Appium, you will need node.js and npm 0.12 or greater (use n or brew install node to install Node.js. Make sure you have not installed Node or Appium with sudo, otherwise you’ll run into problems). We recommend the latest stable version.

To verify that all of Appium’s dependencies are met you can use appium-doctor. Install it with npm install -g appium-doctor (or run it from source), then run appium-doctor and supply the --ios or --android flags to verify that all of the dependencies are set up correctly.

You also need to download the Appium client for your language so you can write tests. The Appium clients are simple extensions to the WebDriver clients. You can see the list of clients and links to download instructions at the Appium clients list.

iOS Requirements

Android Requirements

FirefoxOS Requirements

Quick Start

Kick up an Appium server, and then run a test written in your favorite WebDriver-compatible language! You can run an Appium server using node.js or using the application, see below.

Using Node.js

$ npm install -g appium
$ appium

Using the App

Writing Tests for Appium

The main guide for getting started writing and running tests is the running tests.

Essentially, we support a subset of the Selenium WebDriver JSON Wire Protocol, and extend it so that you can specify mobile-targeted desired capabilities to run your test through Appium.

You find elements by using a subset of WebDriver’s element-finding strategies. See finding elements like tap, flick, and swipe.

You can also automate web views in hybrid apps! See the hybrid app guide

This repository contains many examples of tests in a variety of different languages!

For the full list of Appium doc pages, visit this directory.

How It Works

Appium drives various native automation frameworks and provides an API based on Selenium’s WebDriver JSON wire protocol.

Appium drives Apple’s UIAutomation library for iOS support, which is based on Dan Cuellar’s work on iOS Auto.

Android support uses the UiAutomator framework for newer platforms and Selendroid for older Android platforms.

FirefoxOS support leverages Marionette, an automation driver that is compatible with WebDriver and is used to automate Gecko-based platforms.


Please take a look at our contribution documentation for instructions on how to build, test and run Appium from source.


Interested in where Appium is heading in the future? Check out the Roadmap

Project Credits & Inspiration


Mailing List

Announcements and debates often take place on the Discussion Group, be sure to sign up!


We put together a troubleshooting guide. Please have a look here first if you run into any problems. It contains instructions for checking a lot of common errors and how to get in touch with the community if you’re stumped.

Using Robots

Using Appium with Tapster and other robots is possible, check out the Appium Robots project!

List of client libraries with Appium server support

These libraries wrap standard Selenium client libraries to provide all the regular selenium commands dictated by the JSON Wire protocol, and add extra commands related to controlling mobile devices, such as multi-touch gestures and screen orientation.

Appium client libraries implement the Mobile JSON Wire Protocol (an official draft extension to the standard protocol), and elements of the W3C Webdriver spec (a transport-agnostic automation spec; this is where the MultiAction API is defined).

The Appium server itself defines custom extensions to the official protocols, giving Appium users helpful access to various device behaviors (such as installing/uninstalling apps during the course of a test session). This is why we need Appium-specific clients, not just the 'vanilla’ Selenium clients. Of course, Appium client libraries only add functionality (in fact, they simply extend the standard Selenium clients), so they can still be used to run regular Selenium sessions.

Language/Framework Github Repo and Installation Instructions
Ruby https://github.com/appium/ruby_lib
Python https://github.com/appium/python-client
Java https://github.com/appium/java-client
JavaScript (Node.js) https://github.com/admc/wd
Objective C https://github.com/appium/selenium-objective-c
PHP https://github.com/appium/php-client
C# (.NET) https://github.com/appium/appium-dotnet-driver
RobotFramework https://github.com/jollychang/robotframework-appiumlibrary

Setting up Appium

Appium Platform Support

Appium supports a variety of platforms and testing modalities (native, hybrid, web, real devices, simulators, etc…). This document is designed to make explicit the level of support and requirements for each of these.

iOS Support

See Running on OS X: iOS for iOS requirements and setup instructions.

Android Support

See Running on OS X: Android, Running on Windows, or Running on Linux for Android requirements and setup instructions.

Appium on real iOS devices

Appium has support for real device testing.

To get started on a real device, you will need the following:

Provisioning Profile

A valid iOS Development Distribution Certificate and Provisioning Profile are necessary to test on a real device. Your app will also need to be signed. You can find information about this in the Apple documentation.

Appium will attempt to install your app using Fruitstrap, but it is often easier to pre-install your app using Xcode to ensure there are no problems (see the iOS deploy doc for more information).

Running your tests with Appium

Once your device and app are configured, you can run tests on that device by passing the -U or --udid flag to the server or the udid desired capability, and the bundle ID (if the app is installed on the device) or the path to the .ipa or .apk file via the --app flag or the app desired capability.

Server Arguments

For example, if you are prelaunching your app and wish for Appium to force use a specific UDID, then you may use the below command:

appium -U <udid> --app <path or bundle>

This will start Appium and have Appium use the device to test the app.

Refer to the Appium server arguments page for more detail on the arguments that you can use.

Desired Capabilities

You can launch the app on a device by including the following desired capabilities in your tests:

Refer to the Appium server capabilities page for more detail on the capabilities that you can use.

Troubleshooting ideas

  1. Make sure UDID is correct by checking it in Xcode Organizer or iTunes. It is a long string (20+ chars).
  2. Make sure that you can run your tests against the Simulator.
  3. Double check that you can invoke your automation from Instruments.
  4. Make sure Instruments is not already running.
  5. Make sure UI Automation is enabled on your device. Settings -> Developer -> Enable UI Automation

Appium on real Android devices

Hooray! There’s nothing extra to know about testing real Android devices: it works exactly the same as testing on emulators. Make sure that your device can connect to ADB and has Developer Mode enabled. For testing Chrome on a real device, you’re responsible for ensuring that Chrome of an appropriate version is installed.

Also, you’ll want to make sure that “Verify Apps” in settings is disabled/unchecked, otherwise it can prevent some of Appium’s helper apps from launching and doing their job correctly.

Running Appium on Mac OS X

Appium on OS X supports iOS and Android testing.

System setup (iOS)

Authorizing iOS on the computer

You need to authorize use of the iOS Simulator by running the authorize-ios binary made available through npm. If you installed globally, by running npm install -g appium, use

sudo authorize-ios

If you installed locally, the binary will be installed within the node_modules/.bin directory, so use

sudo node_modules/.bin/authorize-ios

# alternatively
sudo $(npm bin)/authorize-ios

If you are running Appium.app, you can authorize iOS through the GUI.

You need to do this every time you install a new version of Xcode.

Testing against multiple iOS SDKs

Xcode version 7.1 allows for automatic testing against iOS versions 7.1 and later.

If you’re using multiple Xcode versions, you can switch between them using:

sudo xcode-select –switch <path to required xcode>

System setup (Android)

Instructions for setting up Android and running tests on Mac OS X are the same as those on Linux. See the Android setup docs.

Running iOS tests on OS X using Jenkins

First download the jenkins-cli.jar and verify the Mac successfully connects to Jenkins master. Ensure you’ve run the authorize_ios command mentioned above.

wget https://jenkins.ci.cloudbees.com/jnlpJars/jenkins-cli.jar

java -jar jenkins-cli.jar \
 -s https://team-appium.ci.cloudbees.com \
 -i ~/.ssh/id_rsa \
 on-premise-executor \ 
 -fsroot ~/jenkins \
 -labels osx \
 -name mac_appium

Next define a LaunchAgent for Jenkins to launch automatically on login. A LaunchDaemon will not work because daemons don’t have GUI access. Make sure the plist doesn’t contain the SessionCreate or User key as that may prevent tests from running. You’ll see a Failed to authorize rights error if misconfigured.

$ sudo nano /Library/LaunchAgents/com.jenkins.ci.plist 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">

Finally set the owner, permissions, and then start the agent.

sudo chown root:wheel /Library/LaunchAgents/com.jenkins.ci.plist
sudo chmod 644 /Library/LaunchAgents/com.jenkins.ci.plist

launchctl load /Library/LaunchAgents/com.jenkins.ci.plist
launchctl start com.jenkins.ci

Running Appium on Windows


If you are running Appium on Windows, you can use the Appium.exe client, which will allow you to quickly launch an Appium server and use the Inspector. You will not be able to test iOS apps on a locally hosted server, because Appium relies on OS X-only libraries to support iOS testing. You can however use the Remote Server option to connect to an Appium server running on a Mac.


To get started:

  1. Install node.js (v.0.12 or greater). Use the installer from nodejs.org.
  2. Install appium-doctor in order to check your system: npm install appium-doctor -g. Then run by typing appium-doctor.
  3. Install the Android SDK. You will need to run the 'android’ tool (included in the SDK, in the tools folder) and make sure you have an API Level 17 or greater API installed. Set ANDROID_HOME to be your Android SDK path and add the tools and platform-tools folders to your PATH variable.
  4. Install the Java JDK and set JAVA_HOME to your JDK’s bin folder.
  5. Install Apache Ant or use the one that comes with the Android Windows SDK in the eclipse\plugins folder. Be sure to add the folder containing Ant to your PATH variable.
  6. Install Apache Maven and set the M2HOME and M2 environment variables. Set M2HOME to the directory maven is installed in, and set M2 to %M2HOME\bin. Add the path you used for M2 to your PATH.
  7. Install Git Be sure to install Git for windows to run in the regular command prompt.
  8. Install cURL.

Now that you’ve downloaded everything, if you’re running from source, run the following in the folder where you cloned appium:

rm -rf node_modules npm install

Running Appium

To run tests on Windows, you will need to have the Android Emulator booted or an Android Device connected that is running an AVD with API Level 17 or greater. Then run Appium on the command line (via the appium command), or if you’re running from source, inside the folder where you installed appium, using node.js:

node .

See the server documentation for all the command line arguments.


Running Appium on Linux


If you are running Appium on Linux, you cannot use the prebuilt ’.app’, which is built for OS X only. Additionally, you will not be able to test iOS apps because Appium relies on OS X-only libraries to support iOS testing.

Setup (Android)

Instructions for setting up Android and running tests on Linux are the same as those on Mac OS X. See the Android setup docs.

Android Setup

To get started, you’ll need to install node.js (v0.12 or greater). Just follow the instructions for your flavor of linux.

Once you’ve got node.js installed, install the Android SDK. You will need to run the 'android’ tool (included in the SDK, under the 'tools’ directory).

Run the 'android’ tool and use it to install an API Level 17 or greater.

(If you want to run Appium from source, you will also need Apache Ant to build the bootstrap jar that Appium uses for running against Android simulators/devices.)

Finally, set $ANDROID_HOME to be your Android SDK path. If you unzipped the Android SDK to /usr/local/adt/, for example, you should add this to your shell startup:

export ANDROID_HOME=“/usr/local/adt/sdk”

Now you’re set up to run Appium! If you’re running Appium from source, run npm install from your Appium checkout to install all the dependencies.

Additional Setup for Older Versions of Android

Appium uses, and comes prepackaged with, Selendroid for running Android versions 2.3 to 4.1. Appium switches to using Selendroid automatically when it detects older versions, but there is some additional setup required if you’re running from source.

Running Appium Android Tests

To run tests on Linux, you will need to have the Android Emulator booted and running an AVD with API Level 17 or greater. Then run Appium (appium) after installing via NPM, or node . in the source directory if running from source.

See the server documentation for all the command line arguments.


Intel® Hardware Accelerated Execution Manager

If you find the android emulator a slow and your system runs on an Intel® cpu, you can check out HAXM. HAXM lets you leverage your hardware for virtualization, accelerating the emulator.

Deploying an iOS app to a real device

To prepare for your Appium tests to run on a real device, you will need to:

  1. Build your app with specific device-targeted parameters
  2. Use fruitstrap, a 3rd-party tool, to deploy this build to your device

Xcodebuild with parameters:

A newer xcodebuild now allows settings to be specified. Taken from developer.apple.com:

xcodebuild [-project projectname] [-target targetname ...] [-configuration configurationname] [-sdk [sdkfullpath | sdkname]] [buildaction ...] [setting=value ...] [-userdefault=value ...]

This is a resource to explore the available settings

CODE_SIGN_IDENTITY (Code Signing Identity) Description: Identifier. Specifies the name of a code signing identity. Example value: iPhone Developer

PROVISIONING_PROFILE is missing from the index of available commands, but may be necessary.

Specify “CODE_SIGN_IDENTITY” & “PROVISIONING_PROFILE” settings in the xcodebuild command:

xcodebuild -sdk <iphoneos> -target <target_name> -configuration <Debug> CODE_SIGN_IDENTITY="iPhone Developer: Mister Smith" PROVISIONING_PROFILE="XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX"

On success, the app will be built to your <app_dir>/build/<configuration>-iphoneos/<app_name>.app

Deploy using Fruitstrap

Go clone a forked version of fruitstrap as the ghughes version is no longer maintained. Success has been confirmed with the unprompted fork, but others are reportedly functional.

Once cloned, run make fruitstrap Now, copy the resulting fruitstrap executable to your app’s project or a parent directory.

Execute fruitstrap after a clean build by running (commands available depend on your fork of fruitstrap):

./fruitstrap -d -b <PATH_TO_APP> -i <Device_UDID>

If you are aiming to use continuous integration in this setup, you may find it useful to want to log the output of fruitstrap to both command line and log, like so:

./fruitstrap -d -b <PATH_TO_APP> -i <Device_UDID> 2>&1 | tee fruit.out

Since fruitstrap will need to be killed before the node server can be launched, an option is to scan the output of the fruitstrap launch for some telling sign that the app has completed launching. This may prove useful if you are doing this via a Rakefile and a go_device.sh script:

bundle exec rake ci:fruit_deploy_app | while read line ; do echo "$line" | grep "text to identify successful launch" if [ $? = 0 ] then # Actions echo "App finished launching: $line" sleep 5 kill -9 `ps -aef | grep fruitstrap | grep -v grep | awk '{print $2}'` fi done

Once fruitstrap is killed, node server can be launched and Appium tests can run!

Next: Running Appium on Real Devices

Parallel Android Tests

Appium provides a way for users to automate multiple Android sessions on a single machine. All it involves is starting multiple Appium servers with different flags.

The important flags for automating multiple Android sessions are:

More information on these flags can be found here.

If we had two devices with the ID’s 43364 and 32456, we would start two different Appium servers with the following commands:

node . -p 4492 -bp 2251 -U 32456

node . -p 4491 -bp 2252 -U 43364

As long as your Appium and Appium bootstrap ports are between 0 and 65536, all they have to be is different so that two Appium servers aren’t trying to listen on the same port. Be sure that your -u flag corresponds with the correct device ID. This is how Appium knows which device to communicate with, so it must be accurate.

If you are using chromedriver or selendroid, set a different port for each server.

Parallel iOS Tests

Unfortunately, running local parallel iOS tests aren’t possible. Unlike Android, only one version of the iOS simulator can be launched at a time, making it run multiple tests at once.

If you do want to run parallel iOS tests, you need to use Sauce. Simply upload your Appium test to Sauce, and it can run as many parallel iOS or Android tests as your account allows. See more about running your tests on Sauce here.

Troubleshooting Appium

Here’s what to do if you’re experiencing problems, before you submit a ticket to github or write to the appium-discuss discussion group.


If you’re running Appium.app

If you’re running Appium from source



[myCustomView setAccessibilityEnabled:YES];

### Workaround 1 NSLog is a macro and can be redefined. E.g., “`objectivec // You’ll need to define TEST or TEST2 and then recompile.

#ifdef TEST #define NSLog(…) BlackHoleTestLogger(VA_ARGS); #endif // TEST #ifdef TEST2 #define NSLog(…) _StdoutTestLogger(VA_ARGS_); #endif // TEST2

void _BlackHoleTestLogger(NSString *format, …) { // }

void _StdoutTestLogger(NSString *format, …) { va_list argumentList; va_start(argumentList, format); NSMutableString * message = [[NSMutableString alloc] initWithFormat:format arguments:argumentList];


va_end(argumentList); [message release]; } ”`

### Workaround 2 Manually replace the underlying function that NSLog wraps. This method was recommended by Apple in a similar context.

  extern void _NSSetLogCStringFunction(void(*)(const char *, unsigned, BOOL));

  static void _GarbageFreeLogCString(const char *message, unsigned length, BOOL withSyslogBanner) {
     fprintf(stderr, "%s\\n", message);

  int main (int argc, const char *argv[]) {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
     int exitCode;

     setbuf(stderr, NULL);

     exitCode = WOApplicationMain(@"Application", argc, argv);
     [pool release];
     return exitCode;

Webview/Hybrid/Safari app support


Let the community know

Once you’ve tried the above steps and your issue still isn’t resolved, here’s what you can do:

If you’re having trouble getting Appium working and the error messages Appium provides are not clear, join the discussion group and send a message. Please include the following:

If you’ve found what you believe is a bug, go straight to the issue tracker and submit an issue describing the bug and a repro case.

Known Issues

Specific Errors

Action Error Resolution
Running ios test [INST STDERR] posix spawn failure; aborting launch Your app is not compiled correctly for the simulator or device.
Running mobile safari test error: Could not prepare mobile safari with version '7.1' You probably need to run the authorize script again to make the iOS SDK files writeable. See running on OSX documentation

Running Appium tests

Appium server arguments

Many Appium 1.5 server arguments have been deprecated in favor of the –default-capabilities flag.

Usage: node . [flags]

Server flags

All flags are optional, but some are required in conjunction with certain others.

Flag Default Description Example
--shell null Enter REPL mode
--ipa null (IOS-only) abs path to compiled .ipa file --ipa /abs/path/to/my.ipa
-a, --address IP Address to listen on --address
-p, --port 4723 port to listen on --port 4723
-ca, --callback-address null callback IP Address (default: same as –address) --callback-address
-cp, --callback-port null callback port (default: same as port) --callback-port 4723
-bp, --bootstrap-port 4724 (Android-only) port to use on device to talk to Appium --bootstrap-port 4724
-r, --backend-retries 3 (iOS-only) How many times to retry launching Instruments before saying it crashed or timed out --backend-retries 3
--session-override false Enables session override (clobbering)
-l, --pre-launch false Pre-launch the application before allowing the first session (Requires –app and, for Android, –app-pkg and –app-activity)
-g, --log null Also send log output to this file --log /path/to/appium.log
--log-level debug log level; default (console[:file]): debug[:debug] --log-level debug
--log-timestamp false Show timestamps in console output
--local-timezone false Use local timezone for timestamps
--log-no-colors false Do not use colors in console output
-G, --webhook null Also send log output to this HTTP listener --webhook localhost:9876
--safari false (IOS-Only) Use the safari app
--default-device, -dd false (IOS-Simulator-only) use the default simulator that instruments launches on its own
--force-iphone false (IOS-only) Use the iPhone Simulator no matter what the app wants
--force-ipad false (IOS-only) Use the iPad Simulator no matter what the app wants
--tracetemplate null (IOS-only) .tracetemplate file to use with Instruments --tracetemplate /Users/me/Automation.tracetemplate
--instruments null (IOS-only) path to instruments binary --instruments /path/to/instruments
--nodeconfig null Configuration JSON file to register appium with selenium grid --nodeconfig /abs/path/to/nodeconfig.json
-ra, --robot-address IP Address of robot --robot-address
-rp, --robot-port -1 port for robot --robot-port 4242
--selendroid-port 8080 Local port used for communication with Selendroid --selendroid-port 8080
--chromedriver-port 9515 Port upon which ChromeDriver will run --chromedriver-port 9515
--chromedriver-executable null ChromeDriver executable full path
--show-config false Show info about the appium server configuration and exit
--no-perms-check false Bypass Appium’s checks to ensure we can read/write necessary files
--strict-caps false Cause sessions to fail if desired caps are sent in that Appium does not recognize as valid for the selected device
--isolate-sim-device false Xcode 6 has a bug on some platforms where a certain simulator can only be launched without error if all other simulator devices are first deleted. This option causes Appium to delete all devices other than the one being used by Appium. Note that this is a permanent deletion, and you are responsible for using simctl or xcode to manage the categories of devices used with Appium.
--tmp null Absolute path to directory Appium can use to manage temporary files, like built-in iOS apps it needs to move around. On *nix/Mac defaults to /tmp, on Windows defaults to C:\Windows\Temp
--trace-dir null Absolute path to directory Appium use to save ios instruments traces, defaults to /appium-instruments
--debug-log-spacing false Add exaggerated spacing in logs to help with visual inspection
--suppress-adb-kill-server false (Android-only) If set, prevents Appium from killing the adb server instance
--async-trace false Add long stack traces to log entries. Recommended for debugging only.
--webkit-debug-proxy-port 27753 (IOS-only) Local port used for communication with ios-webkit-debug-proxy --webkit-debug-proxy-port 27753
-dc, --default-capabilities {} Set the default desired capabilities, which will be set on each session unless overridden by received capabilities. `–default-capabilities [ ’{"app”: “myapp.app”, “deviceName”: “iPhone Simulator”}’
--command-timeout 60 [DEPRECATED] No effect. This used to be the default command timeout for the server to use for all sessions (in seconds and should be less than 2147483). Use newCommandTimeout cap instead
-k, --keep-artifacts false [DEPRECATED] - no effect, trace is now in tmp dir by default and is cleared before each run. Please also refer to the –trace-dir flag.
--platform-name null [DEPRECATED] - Name of the mobile platform: iOS, Android, or FirefoxOS --platform-name iOS
--platform-version null [DEPRECATED] - Version of the mobile platform --platform-version 7.1
--automation-name null [DEPRECATED] - Name of the automation tool: Appium or Selendroid --automation-name Appium
--device-name null [DEPRECATED] - Name of the mobile device to use --device-name iPhone Retina (4-inch), Android Emulator
--browser-name null [DEPRECATED] - Name of the mobile browser: Safari or Chrome --browser-name Safari
--app null [DEPRECATED] - IOS: abs path to simulator-compiled .app file or the bundle_id of the desired target on device; Android: abs path to .apk file --app /abs/path/to/my.app
-lt, --launch-timeout 90000 [DEPRECATED] - (iOS-only) how long in ms to wait for Instruments to launch
--language null [DEPRECATED] - Language for the iOS simulator / Android Emulator --language en
--locale null [DEPRECATED] - Locale for the iOS simulator / Android Emulator --locale en_US
-U, --udid null [DEPRECATED] - Unique device identifier of the connected physical device --udid 1adsf-sdfas-asdf-123sdf
--orientation null [DEPRECATED] - (IOS-only) use LANDSCAPE or PORTRAIT to initialize all requests to this orientation --orientation LANDSCAPE
--no-reset false [DEPRECATED] - Do not reset app state between sessions (IOS: do not delete app plist files; Android: do not uninstall app before new session)
--full-reset false [DEPRECATED] - (iOS) Delete the entire simulator folder. (Android) Reset app state by uninstalling app instead of clearing app data. On Android, this will also remove the app after the session is complete.
--app-pkg null [DEPRECATED] - (Android-only) Java package of the Android app you want to run (e.g., com.example.android.myApp) --app-pkg com.example.android.myApp
--app-activity null [DEPRECATED] - (Android-only) Activity name for the Android activity you want to launch from your package (e.g., MainActivity) --app-activity MainActivity
--app-wait-package false [DEPRECATED] - (Android-only) Package name for the Android activity you want to wait for (e.g., com.example.android.myApp) --app-wait-package com.example.android.myApp
--app-wait-activity false [DEPRECATED] - (Android-only) Activity name for the Android activity you want to wait for (e.g., SplashActivity) --app-wait-activity SplashActivity
--device-ready-timeout 5 [DEPRECATED] - (Android-only) Timeout in seconds while waiting for device to become ready --device-ready-timeout 5
--android-coverage false [DEPRECATED] - (Android-only) Fully qualified instrumentation class. Passed to -w in adb shell am instrument -e coverage true -w --android-coverage com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation
--avd null [DEPRECATED] - (Android-only) Name of the avd to launch --avd @default
--avd-args null [DEPRECATED] - (Android-only) Additional emulator arguments to launch the avd --avd-args -no-snapshot-load
--use-keystore false [DEPRECATED] - (Android-only) When set the keystore will be used to sign apks.
--keystore-path <user>/.android/debug.keystore [DEPRECATED] - (Android-only) Path to keystore
--keystore-password android [DEPRECATED] - (Android-only) Password to keystore
--key-alias androiddebugkey [DEPRECATED] - (Android-only) Key alias
--key-password android [DEPRECATED] - (Android-only) Key password
--intent-action android.intent.action.MAIN [DEPRECATED] - (Android-only) Intent action which will be used to start activity --intent-action android.intent.action.MAIN
--intent-category android.intent.category.LAUNCHER [DEPRECATED] - (Android-only) Intent category which will be used to start activity --intent-category android.intent.category.APP_CONTACTS
--intent-flags 0x10200000 [DEPRECATED] - (Android-only) Flags that will be used to start activity --intent-flags 0x10200000
--intent-args null [DEPRECATED] - (Android-only) Additional intent arguments that will be used to start activity --intent-args 0x10200000
--dont-stop-app-on-reset false [DEPRECATED] - (Android-only) When included, refrains from stopping the app before restart
--calendar-format null [DEPRECATED] - (IOS-only) calendar format for the iOS simulator --calendar-format gregorian
--native-instruments-lib false [DEPRECATED] - (IOS-only) IOS has a weird built-in unavoidable delay. We patch this in appium. If you do not want it patched, pass in this flag.
--keep-keychains false [DEPRECATED] - (iOS-only) Whether to keep keychains (Library/Keychains) when reset app between sessions
--localizable-strings-dir en.lproj [DEPRECATED] - (IOS-only) the relative path of the dir where Localizable.strings file resides --localizable-strings-dir en.lproj
--show-ios-log false [DEPRECATED] - (IOS-only) if set, the iOS system log will be written to the console

The –default-capabilities flag

Appium 1.5 does away with most CLI flags; the remainder can be converted into JSON and made part of the --default-capabilities flag. For example:

# raw JSON as an argument
--default-capabilities '{"app": "myapp.app", "deviceName": "iPhone Simulator"}'
# or the name of a JSON file
--default-capabilities /path/to/file.json

Windows users will need to escape the quotes in JSON passed on the command line: --default-capabilities "{\"app\": \"myapp.app\"}"

Flag JSON key
–keep-artifacts keepArtifacts
–platform-name platformName
–platform-version platformVersion
–automation-name automationName
–device-name deviceName
–browser-name browserName
–app app
–launch-timeout launchTimeout
–language language
–locale locale
–udid udid
–orientation orientation
–no-reset noReset
–full-reset rullReset
–app-pkg appPackage
–app-activity appActivity
–app-wait-package appWaitPackage
–app-wait-activity appWaitActivity
–device-ready-timeout deviceReadyTimeout
–android-coverage androidCoverage
–avd avd
–avd-args avdArgs
–use-keystore useKeystore
–keystore-path keystorePath
–keystore-password keystorePassword
–key-alias keyAlias
–key-password keyPassword
–intent-action intentAction
–intent-category intentCategory
–intent-flags intentFlags
–intent-args optionalIntentArguments
–dont-stop-app-on-reset dontStopAppOnReset
–calendar-format calendarFormat
–native-instruments-lib nativeInstrumentsLib
–keep-keychains keepKeyChains
–localizable-strings-dir localizableStringsDir
–show-ios-log showIOSLog

Appium server capabilities

Capability Description Values
automationName Which automation engine to use Appium (default) or Selendroid
platformName Which mobile OS platform to use iOS, Android, or FirefoxOS
platformVersion Mobile OS version e.g., 7.1, 4.4
deviceName The kind of mobile device or emulator to use iPhone Simulator, iPad Simulator, iPhone Retina 4-inch, Android Emulator, Galaxy S4, etc…. On iOS, this should be one of the valid devices returned by instruments with instruments -s devices. On Android this capability is currently ignored.
app The absolute local path or remote http URL to an .ipa or .apk file, or a .zip containing one of these. Appium will attempt to install this app binary on the appropriate device first. Note that this capability is not required for Android if you specify appPackage and appActivity capabilities (see below). Incompatible with browserName. /abs/path/to/my.apk or http://myapp.com/app.ipa
browserName Name of mobile web browser to automate. Should be an empty string if automating an app instead. 'Safari’ for iOS and 'Chrome’, 'Chromium’, or 'Browser’ for Android
newCommandTimeout How long (in seconds) Appium will wait for a new command from the client before assuming the client quit and ending the session e.g. 60
language (Sim/Emu-only) Language to set for the simulator / emulator e.g. fr
locale (Sim/Emu-only) Locale to set for the simulator / emulator e.g. fr_CA
udid Unique device identifier of the connected physical device e.g. 1ae203187fc012g
orientation (Sim/Emu-only) start in a certain orientation LANDSCAPE or PORTRAIT
autoWebview Move directly into Webview context. Default false true, false
noReset Don’t reset app state before this session. Default false true, false
fullReset (iOS) Delete the entire simulator folder. (Android) Reset app state by uninstalling app instead of clearing app data. On Android, this will also remove the app after the session is complete. Default false true, false

Android Only

Capability Description Values
appActivity Activity name for the Android activity you want to launch from your package. This often needs to be preceded by a . (e.g., .MainActivity instead of MainActivity) MainActivity, .Settings
appPackage Java package of the Android app you want to run com.example.android.myApp, com.android.settings
appWaitActivity Activity name for the Android activity you want to wait for SplashActivity
appWaitPackage Java package of the Android app you want to wait for com.example.android.myApp, com.android.settings
deviceReadyTimeout Timeout in seconds while waiting for device to become ready 5
androidCoverage Fully qualified instrumentation class. Passed to -w in adb shell am instrument -e coverage true -w com.my.Pkg/com.my.Pkg.instrumentation.MyInstrumentation
enablePerformanceLogging (Chrome and webview only) Enable Chromedriver’s performance logging (default false) true, false
androidDeviceReadyTimeout Timeout in seconds used to wait for a device to become ready after booting e.g., 30
adbPort Port used to connect to the ADB server (default 5037) 5037
androidDeviceSocket Devtools socket name. Needed only when tested app is a Chromium embedding browser. The socket is open by the browser and Chromedriver connects to it as a devtools client. e.g., chrome_devtools_remote
avd Name of avd to launch e.g., api19
avdLaunchTimeout How long to wait in milliseconds for an avd to launch and connect to ADB (default 120000) 300000
avdReadyTimeout How long to wait in milliseconds for an avd to finish its boot animations (default 120000) 300000
avdArgs Additional emulator arguments used when launching an avd e.g., -netfast
useKeystore Use a custom keystore to sign apks, default false true or false
keystorePath Path to custom keystore, default ~/.android/debug.keystore e.g., /path/to.keystore
keystorePassword Password for custom keystore e.g., foo
keyAlias Alias for key e.g., androiddebugkey
keyPassword Password for key e.g., foo
chromedriverExecutable The absolute local path to webdriver executable (if Chromium embedder provides its own webdriver, it should be used instead of original chromedriver bundled with Appium) /abs/path/to/webdriver
autoWebviewTimeout Amount of time to wait for Webview context to become active, in ms. Defaults to 2000 e.g. 4
intentAction Intent action which will be used to start activity (default android.intent.action.MAIN) e.g.android.intent.action.MAIN, android.intent.action.VIEW
intentCategory Intent category which will be used to start activity (default android.intent.category.LAUNCHER) e.g. android.intent.category.LAUNCHER, android.intent.category.APP_CONTACTS
intentFlags Flags that will be used to start activity (default 0x10200000) e.g. 0x10200000
optionalIntentArguments Additional intent arguments that will be used to start activity. See Intent arguments e.g. --esn <EXTRA_KEY>, --ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE>, etc.
dontStopAppOnReset Doesn’t stop the process of the app under test, before starting the app using adb. If the app under test is created by another anchor app, setting this false, allows the process of the anchor app to be still alive, during the start of the test app using adb. In other words, with dontStopAppOnReset set to true, we will not include the -S flag in the adb shell am start call. With this capability omitted or set to false, we include the -S flag. Default false true or false
unicodeKeyboard Enable Unicode input, default false true or false
resetKeyboard Reset keyboard to its original state, after running Unicode tests with unicodeKeyboard capability. Ignored if used alone. Default false true or false
noSign Skip checking and signing of app with debug keys, will work only with UiAutomator and not with selendroid, default false true or false
ignoreUnimportantViews Calls the setCompressedLayoutHierarchy() uiautomator function. This capability can speed up test execution, since Accessibility commands will run faster ignoring some elements. The ignored elements will not be findable, which is why this capability has also been implemented as a toggle-able setting as well as a capability. Defaults to false true or false
disableAndroidWatchers Disables android watchers that watch for application not responding and application crash, this will reduce cpu usage on android device/emulator. This capability will work only with UiAutomator and not with selendroid, default false true or false
chromeOptions Allows passing chromeOptions capability for ChromeDriver. For more information see chromeOptions chromeOptions: {args: ['--disable-popup-blocking']}
recreateChromeDriverSessions Kill ChromeDriver session when moving to a non-ChromeDriver webview. Defaults to false true or false
nativeWebScreenshot In a web context, use native (adb) method for taking a screenshot, rather than proxying to ChromeDriver. Defaults to false true or false

iOS Only

Capability Description Values
calendarFormat (Sim-only) Calendar format to set for the iOS Simulator e.g. gregorian
bundleId Bundle ID of the app under test. Useful for starting an app on a real device or for using other caps which require the bundle ID during test startup. To run a test on a real device using the bundle ID, you may omit the 'app’ capability, but you must provide 'udid’. e.g. io.appium.TestApp
udid Unique device identifier of the connected physical device e.g. 1ae203187fc012g
launchTimeout Amount of time in ms to wait for instruments before assuming it hung and failing the session e.g. 20000
locationServicesEnabled (Sim-only) Force location services to be either on or off. Default is to keep current sim setting. true or false
locationServicesAuthorized (Sim-only) Set location services to be authorized or not authorized for app via plist, so that location services alert doesn’t pop up. Default is to keep current sim setting. Note that if you use this setting you MUST also use the bundleId capability to send in your app’s bundle ID. true or false
autoAcceptAlerts Accept all iOS alerts automatically if they pop up. This includes privacy access permission alerts (e.g., location, contacts, photos). Default is false. true or false
autoDismissAlerts Dismiss all iOS alerts automatically if they pop up. This includes privacy access permission alerts (e.g., location, contacts, photos). Default is false. true or false
nativeInstrumentsLib Use native intruments lib (ie disable instruments-without-delay). true or false
nativeWebTap (Sim-only) Enable “real”, non-javascript-based web taps in Safari. Default: false. Warning: depending on viewport size/ratio this might not accurately tap an element true or false
safariInitialUrl (Sim-only) (>= 8.1) Initial safari url, default is a local welcome page e.g. https://www.github.com
safariAllowPopups (Sim-only) Allow javascript to open new windows in Safari. Default keeps current sim setting true or false
safariIgnoreFraudWarning (Sim-only) Prevent Safari from showing a fraudulent website warning. Default keeps current sim setting. true or false
safariOpenLinksInBackground (Sim-only) Whether Safari should allow links to open in new windows. Default keeps current sim setting. true or false
keepKeyChains (Sim-only) Whether to keep keychains (Library/Keychains) when appium session is started/finished true or false
localizableStringsDir Where to look for localizable strings. Default en.lproj en.lproj
processArguments Arguments to pass to the AUT using instruments e.g., -myflag
interKeyDelay The delay, in ms, between keystrokes sent to an element when typing. e.g., 100
showIOSLog Whether to show any logs captured from a device in the appium logs. Default false true or false
sendKeyStrategy strategy to use to type test into a test field. Simulator default: oneByOne. Real device default: grouped oneByOne, grouped or setValue
screenshotWaitTimeout Max timeout in sec to wait for a screenshot to be generated. default: 10 e.g., 5
waitForAppScript The ios automation script used to determined if the app has been launched, by default the system wait for the page source not to be empty. The result must be a boolean e.g. true;, target.elements().length > 0;, $.delay(5000); true;
webviewConnectRetries Number of times to send connection message to remote debugger, to get webview. Default: 8 e.g., 12
appName The display name of the application under test. Used to automate backgrounding the app in iOS 9+. e.g., UICatalog

Finding and interacting with elements

Appium supports a subset of the WebDriver locator strategies:

Appium additionally supports some of the Mobile JSON Wire Protocol locator strategies


There’s a known issue with table cell elements becoming invalidated before there’s time to interact with them. We’re working on a fix

Using The Appium Inspector To Locate Elements

Appium provides you with a neat tool that allows you to find the the elements you’re looking for without leaving the Appium app. With the Appium Inspector (the i symbol next to the start test button) you can find any element and it’s name by either clicking the element on the preview page provided, or locating it in the UI navigator.


The Appium inspector has a simple layout, complete with a UI navigator, a preview, and record and refresh buttons, and interaction tools.

Step 1


After launching the Appium Inspector (you can do this by clicking the small “i” button in the top right of the app) you can locate any element in the preview. In this test, I’m looking for the id of the “show alert” button.

Step 1

To find the id of this button, I click the “show alert” button in the inspector preview. The Appium inspector then highlights the element in the UI navigator, showing me both the id and element type of the button I clicked.

Step 1

Automating mobile web apps

If you’re interested in automating your web app in Mobile Safari on iOS or Chrome on Android, Appium can help you. Basically, you write a normal WebDriver test, and use Appium as the Selenium server with a special set of desired capabilities.

Mobile Safari on Simulator

First of all, make sure developer mode is turned on in your Safari preferences so that the remote debugger port is open.

If you are using the simulator or a real device, you MUST run Safari before attempting to use Appium.

Then, use desired capabilities like these to run your test in mobile Safari:

// javascript
  platformName: 'iOS'
  , platformVersion: '7.1'
  , browserName: 'Safari'
  , deviceName: 'iPhone Simulator'
# python
  'platformName': 'iOS',
  'platformVersion': '7.1',
  'browserName': 'Safari',
  'deviceName': 'iPhone Simulator'
// php
public static $browsers = array(
        'desiredCapabilities' => array(
            'platformName' => 'iOS',
            'platformVersion' => '7.1',
            'browserName' => 'Safari',
            'deviceName' => 'iPhone Simulator'
// java
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "iOS");
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Safari");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");

Mobile Safari on a Real iOS Device

We use the SafariLauncher App to launch Safari and run tests against mobile Safari. Once Safari has been launched the Remote Debugger automatically connects using the ios-webkit-debug-proxy. When working with ios-webkit-debug-proxy, you have to trust the machine before you can can run tests against your iOS device.

For instruction on how to install and run ios-webkit-debugger-proxy see iOS webKit debug proxy documentation.


Before you can run your tests against Safari on a real device you will need to:

To create a profile for the launcher go into the Apple Developers Member Center and:

Now simply include your UDID and device name in your desired capabilities:

{ "udid": '...', "deviceName": '...', "browserName": "Safari" }

Running your test

To configure you test to run against safari simply set the “browserName” to be “Safari”.

Java Example

// java
//setup the web driver and launch the webview app.
DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
desiredCapabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Safari");
URL url = new URL("");
AppiumDriver driver = new AppiumDriver(url, desiredCapabilities);

// Navigate to the page and interact with the elements on the guinea-pig page using id.
WebElement div = driver.findElement(By.id("i_am_an_id"));
Assert.assertEquals("I am a div", div.getText()); //check the text retrieved matches expected value
driver.findElement(By.id("comments")).sendKeys("My comment"); //populate the comments field by id.

//close the app.

Python Example

# python
# setup the web driver and launch the webview app.
capabilities = { 'browserName': 'Safari' }
driver = webdriver.Remote('http://localhost:4723/wd/hub', capabilities)

# Navigate to the page and interact with the elements on the guinea-pig page using id.
div = driver.find_element_by_id('i_am_an_id')
# check the text retrieved matches expected value
assertEqual('I am a div', div.text)

# populate the comments field by id
driver.find_element_by_id('comments').send_keys('My comment')

# close the driver
// php
class ContextTests extends PHPUnit_Extensions_AppiumTestCase
    public static $browsers = array(
            'desiredCapabilities' => array(
                'platformName' => 'iOS',
                'platformVersion' => '7.1',
                'browserName' => 'Safari',
                'deviceName' => 'iPhone Simulator'

    public function testThings()

        $div = $this->byId('i_am_an_id');
        $this->assertEquals('I am a div', $div->text());

        $this->byId('comments')->sendKeys('My comment');

Mobile Chrome on Emulator or Real Device


Then, use desired capabilities like these to run your test in Chrome:

// javascript
  platformName: 'Android'
  , platformVersion: '4.4'
  , deviceName: 'Android Emulator'
  , browserName: 'Chrome'
# python
  'platformName': 'Android',
  'platformVersion': '4.4',
  'deviceName': 'Android Emulator',
  'browserName': 'Chrome'
// php
public static $browsers = array(
        'desiredCapabilities' => array(
            'platformName' => 'Android',
            'platformVersion' => '4.4',
            'browserName' => 'Chrome',
            'deviceName' => 'Android Emulator'
// java
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "4.4");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Chrome");

Note that on 4.4+ devices, you can also use the 'Browser’ browserName cap to automate the built-in browser. On all devices you can use the 'Chromium’ browserName cap to automate a build of Chromium.

Troubleshooting chromedriver

As of Chrome version 33, a rooted device is no longer required. If running tests on older versions of Chrome, devices needed to be rooted as ChromeDriver required write access to the /data/local directory to set Chrome’s command line arguments.

If testing on Chrome app prior to version 33, ensure adb shell has read/write access to /data/local directory on the device:

$ adb shell su -c chmod 777 /data/local

For more chromedriver specific documentation see ChromeDriver documentation.

Running Tests

Preparing your app for test (iOS)

Test apps run on the simulator have to be compiled specifically for the simulator, for example by executing the following command in the Xcode project:

> xcodebuild -sdk iphonesimulator6.0

This creates a build/Release-iphonesimulator directory in your Xcode project that contains the .app package that you’ll need to communicate with the Appium server.

If you want, you can zip up the .app directory into a .zip file! Appium will unpack it for you. Nice if you’re not using Appium locally.

Preparing your app for test (Android)

Nothing in particular needs to be done to run your .apk using Appium. If you want to zip it up, you can.

Running your test app with Appium (iOS)

The best way to see what to do currently is to look at the example tests:

Node.js | Python | PHP | Ruby | Java

Basically, first make sure Appium is running:

node .

Then script your WebDriver test, sending in the following desired capabilities:

// javascript
    platformName: 'iOS',
    platformVersion: '7.1',
    deviceName: 'iPhone Simulator',
    app: myApp
# python
    'platformName': 'iOS',
    'platformVersion': '7.1',
    'deviceName': 'iPhone Simulator',
    'app': myApp
// php
public static $browsers = array(
        'desiredCapabilities' => array(
            'platformName' => 'iOS',
            'platformVersion' => '7.1',
            'deviceName' => 'iPhone Simulator',
            'app' => $myApp
// java
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "iOS");
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "7.1");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "iPhone Simulator");
capabilities.setCapability(MobileCapabilityType.APP, myApp);

In this set of capabilities, myApp must be either:

Using your WebDriver library of choice, set the remote session to use these capabilities and connect to the server running at port 4723 of localhost (or whatever host and port you specified when you started Appium). You should be all set now!

Running your test app with Appium (Android)

First, make sure you have one and only one Android emulator or device connected. If you run adb devices, for example, you should see one device connected. This is the device Appium will use for tests. Of course, to have a device connected, you’ll need to have made an Android AVD (see system setup (Windows, Mac, or Linux) for more information). If the Android SDK tools are on your path, you can simply run:

emulator -avd

And wait for the android emulator to finish launching. Sometimes, for various reasons, adb gets stuck. If it’s not showing any connected devices or otherwise failing, you can restart it by running:

adb kill-server && adb devices

Now, make sure Appium is running:

node .

There are several ways to start an Appium application (it works exactly the same as when the application is started via adb):

Activities may be specified in the following way:

If the 'appWaitPackage’ and 'appWaitActivity’ caps are specified, Appium automatically spins until those activities are launched. You may specify multiple wait activities for instance:

If you are not sure what activity are configured in your apk, you can proceed in one of the following ways:

Then script your WebDriver test, sending in the following desired capabilities:

// javascript
    platformName: 'Android',
    platformVersion: '4.4',
    deviceName: 'Android Emulator',
    app: myApp
# python
    'platformName': 'Android',
    'platformVersion': '4.4',
    'deviceName': 'Android Emulator',
    'app': myApp
// php
public static $browsers = array(
        'desiredCapabilities' => array(
            'platformName' => 'Android',
            'platformVersion' => '4.4',
            'deviceName' => 'Android Emulator',
            'app' => $myApp
// java
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "4.4");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.APP, myApp);

In this set of capabilities, myApp must be either:

Using your WebDriver library of choice, set the remote session to use these capabilities and connect to the server running at port 4723 of localhost (or whatever host and port you specified when you started Appium). You should be all set now!

Running your test app with Appium (Android devices < 4.2, and hybrid tests)

Android devices before version 4.2 (API Level 17) do not have Google’s UiAutomator framework installed. This is what Appium uses to perform the automation behaviors on the device. For earlier devices or tests of hybrid (webview-based) apps, Appium comes bundled with another automation backend called Selendroid.

To use Selendroid, all that is required is to slightly change the set of desired capabilities mentioned above, by adding the automationName capability and specifying the Selendroid automation backend. It is usually the case that you also need to use a . before your activity name (e.g., .MainActivity instead of MainActivity for your appActivity capability).

// javascript
    automationName: 'Selendroid',
    platformName: 'Android',
    platformVersion: '2.3',
    deviceName: 'Android Emulator',
    app: myApp,
    appPackage: 'com.mycompany.package',
    appActivity: '.MainActivity'
# python
    'automationName': 'Selendroid',
    'platformName': 'Android',
    'platformVersion': '2.3',
    'deviceName': 'Android Emulator',
    'app': myApp,
    'appPackage': 'com.mycompany.package',
    'appActivity': '.MainActivity'
// php
public static $browsers = array(
        'desiredCapabilities' => array(
            'automationName' => 'Selendroid',
            'platformName' => 'Android',
            'platformVersion' => '2.3',
            'deviceName' => 'Android Emulator',
            'app' => $myApp,
            'appPackage' => 'com.mycompany.package',
            'appActivity'=> '.MainActivity'
// java
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "Selendroid");
capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "2.3");
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android Emulator");
capabilities.setCapability(MobileCapabilityType.APP, myApp);
capabilities.setCapability(MobileCapabilityType.APP_PACKAGE: "com.mycompany.package");
capabilities.setCapability(MobileCapabilityType.APP_ACTIVITY: ".MainActivity");

Now Appium will start up a Selendroid test session instead of the default test session. One of the downsides to using Selendroid is that its API differs sometimes significantly with Appium’s. Therefore we recommend you thoroughly read Selendroid’s documentation before writing your scripts for older devices or hybrid apps.

Automating mobile gestures

While the Selenium WebDriver spec has support for certain kinds of mobile interaction, its parameters are not always easily mappable to the functionality that the underlying device automation (like UIAutomation in the case of iOS) provides. To that end, Appium implements the new TouchAction / MultiAction API defined in the newest version of the spec (https://w3c.github.io/webdriver/webdriver-spec.html#multiactions-1). Note that this is different from the earlier version of the TouchAction API in the original JSON Wire Protocol.

These APIs allow you to build up arbitrary gestures with multiple actuators. Please see the Appium client docs for your language in order to find examples of using this API.

An Overview of the TouchAction / MultiAction API


TouchAction objects contain a chain of events.

In all the appium client libraries, touch objects are created and are given a chain of events.

The available events from the spec are: * press * release * moveTo * tap * wait * longPress * cancel * perform

Here’s an example of creating an action in pseudocode:


The above simulates a user pressing down on an element, sliding their finger to another position, and removing their finger from the screen.

Appium performs the events in sequence. You can add a wait event to control the timing of the gesture.

moveTo coordinates are relative to the current position. For example, dragging from 100,100 to 200,200 can be achieved by: “` .press(100,100) // Start at 100,00 .moveTo(100,100) // Increase X & Y by 100 each, ending up at 200,200

The appium client libraries have different ways of implementing this, for example:
you can pass in coordinates or an element to a `moveTo` event. Passing both
coordinates _and_ an element will treat the coordinates as relative to the
element's position, rather than relative to the current position.

Calling the `perform` event sends the entire sequence of events to appium,
and the touch gesture is run on your device.

Appium clients also allow one to directly execute a TouchAction through the
driver object, rather than calling the `perform` event on the TouchAction

In pseudocode, both of the following are equivalent:

<p class="centercode"><code>TouchAction().tap(el).perform()


### MultiTouch

*MultiTouch* objects are collections of TouchActions.

MultiTouch gestures only have two methods, `add`, and `perform`.

`add` is used to add another TouchAction to this MultiTouch.

When `perform` is called, all the TouchActions which were added to the
MultiTouch are sent to appium and performed as if they happened at the
same time. Appium first performs the first event of all TouchActions together,
then the second, etc.

Pseudocode example of tapping with two fingers:

<p class="centercode"><code>action0 = TouchAction().tap(el)
action1 = TouchAction().tap(el)

### Bugs and Workarounds

An unfortunate bug exists in the iOS 7.0 - 8.x Simulators where ScrollViews,
CollectionViews, and TableViews don't recognize gestures initiated by
UIAutomation (which Appium uses under the hood for iOS). To work around this,
we have provided access to a different function, `scroll`, which in many cases
allows you to do what you wanted to do with one of these views, namely, scroll


To allow access to this special feature, we override the `execute` or
`executeScript` methods in the driver, and prefix the command with `mobile: `.
See examples below:

To scroll, pass direction in which you intend to scroll as parameter.

// javascript
driver.execute("mobile: scroll", [{direction: 'down'}])
// java
JavascriptExecutor js = (JavascriptExecutor) driver;
HashMap<String, String> scrollObject = new HashMap<String, String>();
scrollObject.put("direction", "down");
js.executeScript("mobile: scroll", scrollObject);
# ruby
execute_script 'mobile: scroll', direction: 'down'
# python
driver.execute_script("mobile: scroll", {"direction": "down"})
// c#
Dictionary<string, string> scrollObject = new Dictionary<string, string>();
scrollObject.Add("direction", "down");
((IJavaScriptExecutor)driver).ExecuteScript("mobile: scroll", scrollObject));
$params = array(array('direction' => 'down'));
$driver->executeScript("mobile: scroll", $params);

Sample to scroll using direction and element.

// javascript
driver.execute("mobile: scroll", [{direction: 'down', element: element.value}]);
// java
JavascriptExecutor js = (JavascriptExecutor) driver;
HashMap<String, String> scrollObject = new HashMap<String, String>();
scrollObject.put("direction", "down");
scrollObject.put("element", ((RemoteWebElement) element).getId());
js.executeScript("mobile: scroll", scrollObject);
# ruby
execute_script 'mobile: scroll', direction: 'down', element: element.ref
# python
driver.execute_script("mobile: scroll", {"direction": "down", element: element.getAttribute("id")})
// c#
Dictionary<string, string> scrollObject = new Dictionary<string, string>();
scrollObject.Add("direction", "down");
scrollObject.Add("element", <element_id>);
((IJavaScriptExecutor)driver).ExecuteScript("mobile: scroll", scrollObject));
$params = array(array('direction' => 'down', 'element' => element.GetAttribute("id")));
$driver->executeScript("mobile: scroll", $params);

Automating Sliders


// java
// slider values can be string representations of numbers between 0 and 1
// e.g., "0.1" is 10%, "1.0" is 100%
WebElement slider =  driver.findElement(By.xpath("//window[1]/slider[1]"));


The best way to interact with the slider on Android is with TouchActions.

Appium Client Libraries

Appium has libraries for:

Language Source
Ruby GitHub
Python GitHub
Java GitHub
JavaScript GitHub
PHP GitHub
C# GitHub
Objective-C GitHub

Note that some methods such as endTestCoverage() are not generally useful. Proper coverage support will be added once this issue is resolved. If you want to use them anyway, consult the documentation for the bindings on GitHub.


Lock the screen.

# ruby
lock 5
# python
// java
// javascript
// php
// c#
// objective c
[driver lockDeviceScreen:3];

Background app

Send the currently active app to the background.

# ruby
background_app 5
# python
// java
// javascript
// php
// c#
// objective c
[driver runAppInBackground:3];

Hide Keyboard

Hide the keyboard. Note: on iOS, this helper function is not guaranteed to work. There is no automation hook for hiding the keyboard, and apps are free to allow the user to hide the keyboard using any of a variety of different strategies, whether that is tapping outside the keyboard, swiping down, etc… We encourage you, rather than using this method, to think about how a user would hide the keyboard in your app, and tell Appium to do that instead (swipe, tap on a certain coordinate, etc…). That being said, the default behavior here might help you.

# ruby
# python
// java
// javascript
// php
$this->hideKeyboard(array('strategy' => 'pressKey', 'key' => 'Done'));
// c#
// objective c
[driver hideKeyboard];

Start Activity

Open an activity in the current app or start a new app and open an activity Android only

// java
driver.startActivity("appPackage","com.example.android.apis", null, null);
// javascript
driver.startActivity({appPackage: 'com.example.android.apis', appActivity: '.Foo'}, cb);
# python
driver.start_activity('com.example.android.apis', '.Foo')
# ruby
start_activity app_package: 'io.appium.android.apis', app_activity: '.accessibility.AccessibilityNodeProviderActivity'
// c#
driver.StartActivity("com.example.android.apis", ".Foo");
// php
$this->startActivity(array("appPackage" => "com.example.android.apis",
                            "appActivity" => ".Foo"));
// objective c
[driver startActivity:@"com.example.android.apis" package:@".Foo"];

Open Notifications

Open the notification shade Android only

// java
// javascript
# python
# ruby
// c#
// php
// objective c
[driver openNotifications];

Is installed

Check if an app is installed

# ruby
is_installed? "com.example.android.apis"
# python
// java
// javascript
  .then(function (isAppInstalled) { /*...*/ })
// php
// c#
// objective c
[driver isAppInstalled:@"com.example.android.apis-"];

Install App

Install an app to the device.

# ruby
install 'path/to/my.apk'
# python
// java
// javascript
// php
// c#
// objective c
[driver installAppAtPath:@"path/to/my.apk"];

Remove App

Remove an app from the device.

# ruby
remove 'com.example.android.apis'
# python
// java
// javascript
// php
// c#
// objective c
[driver removeApp:@"com.example.android.apis"];


Simulate the device shaking.

# ruby
# python
// java
// javascript
// php
// c#
// objective c
[driver shakeDevice];

Close app

Close the app

# ruby
# python
// java
// javascript
// php
// c#
// objective c
[driver closeApp];


Launch the session for the desired capabilities. Note that this is the companion to the autoLaunch=false capability. This is not for launching arbitrary apps/activities—for that use start_activity. This is for continuing the initialization ("launch”) process if you have used autoLaunch=false.

# ruby
# python
// java
// javascript
// php
// c#
// objective c
[driver launchApp];


Reset the app.

# ruby
# python
// java
// javascript
// php
// c#
// objective c
[driver resetApp];

Available Contexts

List all available contexts

# ruby
context_array = available_contexts
# python
// java
// javascript
driver.contexts().then(function (contexts) { /*...*/ })
// php
// c#
// objective c
NSArray *contexts = driver.allContexts;

Current context

List the current context

# ruby
context = current_context
# python
// java
// javascript
driver.currentContext().then(function (context) { /*...*/ })
// php
// c#
// objective c
NSString *context = driver.context;

Switch to default context

Change the context to the default.

# ruby
# python
// java
// javascript
// php
// c#
// objective c
[driver setContext:nil];

App Strings

Get the app’s strings.

# ruby
strings = app_strings
# python
// java
// javascript
driver.getAppStrings().then(function (appStrings) { /*...*/ })
// php
// c#
// objective c
[driver appStrings];
[driver appStringsForLanguage:"@ru"];

Key Event

Send a key event to the device.

# ruby
key_event 176
# python
// java
// javascript
// php
// c#
// objective c
NSError *err;
[driver triggerKeyEvent:176 metastate:0 error:&err];

Current Activity

Android only. Get the current activity.

# ruby
# python
// java
// javascript
driver.getCurrentActivity().then(function (activity) { /*...*/ })
// php
// c#
// objective c
NSError *err;
[driver currentActivity];

TouchAction / MultiTouchAction

An API for generating touch actions. This section of the documentation will be expanded upon soon.

# ruby
touch_action = Appium::TouchAction.new
element  = find_element :name, 'Buttons, Various uses of UIButton'
touch_action.press(element: element, x: 10, y: 10).perform
# python
action = TouchAction(driver)
action.press(element=el, x=10, y=10).release().perform()
// java
TouchAction action = new TouchAction(driver)
.press(mapview, 10, 10)
// javascript
var action = new wd.TouchAction(driver);
  .tap({el: el, x: 10, y: 10})
return action.perform(); // returns a promise
// php
$action = $this->initiateTouchAction();
               ->press(array('element' => $el))

$action1 = $this->initiateTouchAction();
$action1->press(array('element' => $els[0]))
        ->moveTo(array('x' => 10, 'y' => 0))
        ->moveTo(array('x' => 10, 'y' => -75))
        ->moveTo(array('x' => 10, 'y' => -600))

$action2 = $this->initiateTouchAction();
$action2->press(array('element' => $els[1]))
        ->moveTo(array('x' => 10, 'y' => 10))
        ->moveTo(array('x' => 10, 'y' => -300))
        ->moveTo(array('x' => 10, 'y' => -600))

$multiAction = $this->initiateMultiAction();
// c#
ITouchAction action = new TouchAction(driver);
action.Press(el, 10, 10).Release();
action.Perform ();


Simulate a user swipe.

# ruby
swipe start_x: 75, start_y: 500, end_x: 75, end_y: 0, duration: 0.8
# python
driver.swipe(start_x=75, start_y=500, end_x=75, end_y=0, duration=800)
// java
driver.swipe(75, 500, 75, 0, 0.8)
// javascript
function swipe(opts) {
  var action = new wd.TouchAction(this);
    .press({x: opts.startX, y: opts.startY})
    .moveTo({x: opts.endX, y: opts.endY})
  return action.perform();
wd.addPromiseChainMethod('swipe', swipe);
// ...
return driver.swipe({ startX: 75, startY: 500,
  endX: 75,  endY: 0, duration: 800 });
// php
$this->swipe(75, 500, 75, 0, 800);
// c#
todo: c#


Pinch the screen.

# ruby
pinch 75
# python
// java
// javascript
function pinch(el) {
  return Q.all([
  ]).then(function(res) {
    var size = res[0];
    var loc = res[1];
    var center = {
      x: loc.x + size.width / 2,
      y: loc.y + size.height / 2
    var a1 = new wd.TouchAction(this);
    a1.press({el: el, x: center.x, y:center.y - 100}).moveTo({el: el}).release();
    var a2 = new wd.TouchAction(this);
    a2.press({el: el, x: center.x, y: center.y + 100}).moveTo({el: el}).release();
    var m = new wd.MultiAction(this);
    m.add(a1, a2);
    return m.perform();
wd.addPromiseChainMethod('pinch', pinch);
wd.addElementPromiseChainMethod('pinch', function() {
  return this.browser.pinch(this);
// ...
return driver.pinch(el);
// ...
return el.pinch();
// c#
driver.Pinch(25, 25)


Zoom the screen.

# ruby
zoom 200
# python
// java
// javascript
function zoom(el) {
  return Q.all([
  ]).then(function(res) {
    var size = res[0];
    var loc = res[1];
    var center = {
      x: loc.x + size.width / 2,
      y: loc.y + size.height / 2
    var a1 = new wd.TouchAction(this);
    a1.press({el: el}).moveTo({el: el, x: center.x, y: center.y - 100}).release();
    var a2 = new wd.TouchAction(this);
    a2.press({el: el}).moveTo({el: el, x: center.x, y: center.y + 100}).release();
    var m = new wd.MultiAction(this);
    m.add(a1, a2);
    return m.perform();
wd.addPromiseChainMethod('zoom', zoom);
wd.addElementPromiseChainMethod('zoom', function() {
  return this.browser.zoom(this);
// ...
return driver.zoom(el);
// ...
return el.zoom();
// php
// c#
driver.Zoom(100, 200);

Scroll To

Scroll to an element.

# ruby
element = find_element :name, "Element Name"
execute_script "mobile: scroll", direction: "down", element: element.ref
# python
driver.execute_script("mobile: scroll", {"direction": "down", element: element.id})
// java
JavascriptExecutor js = (JavascriptExecutor) driver;
HashMap<String, String> scrollObject = new HashMap<String, String>();
scrollObject.put("direction", "down");
scrollObject.put("element", ((RemoteWebElement) element).getId());
js.executeScript("mobile: scroll", scrollObject);
// javascript
return driver.elementByName().then(function (el) {
  driver.execute("mobile: scroll", [{direction: "down", element: el.value}]);
// php
$els = $this->elements($this->using('class name')->value('android.widget.TextView'));
$this->scroll($els[count($els) - 1], $els[0]);
// c#
Dictionary<string, string> scrollObject = new Dictionary<string, string>();
scrollObject.Add("direction", "down");
scrollObject.Add("element", <element_id>);
((IJavaScriptExecutor)driver).ExecuteScript("mobile: scroll", scrollObject));

Pull file

Pulls a file from the device.

# ruby
pull_file 'Library/AddressBook/AddressBook.sqlitedb'
# python
// java
// javascript
  .then(function (base64File) { /*...*/ })
// php
// c#

Push File

Pushes a file to the device.

# ruby
data = "some data for the file"
path = "/data/local/tmp/file.txt"
push_file path, data
# python
data = "some data for the file"
path = "/data/local/tmp/file.txt"
driver.push_file(path, data.encode('base64'))
// java
byte[] data = Base64.encodeBase64("some data for the file".getBytes());
String path = "/data/local/tmp/file.txt";
driver.pushFile(path, data)
// javascript
driver.pushFile(path, data)
// php
$path = 'data/local/tmp/test_push_file.txt';
$data = 'This is the contents of the file to push to the device.';
$this->pushFile($path, base64_encode($data));
// c#
driver.PushFile("/data/local/tmp/file.txt", "some data for the file");


Here you will find sample code for getting/setting appium serverSetting. For more information on how they work, and which settings are supported, see [the settings docs][/docs/en/advanced-concepts/settings.md]

current_settings = get_settings
update_settings someSetting: true
current_settings = driver.get_settings()
driver.update_settings({"someSetting": true})
JsonObject settings = driver.getSettings()
// java-client doesn't support setting arbitrary settings, just settings which are already provided by appium.
// So for the 'ignoreUnimportantViews' setting, the following method exists:
var settings = driver.settings();
browser.updateSettings({'someSetting': true});
$settings = $this->getSettings();
$this->updateSettings(array('cyberdelia' => "open"));
Dictionary<String, Object>settings = driver.GetSettings();
// dotnet-driver doesn't support setting arbitrary settings, just settings which are already provided by appium.
// So for the 'ignoreUnimportantViews' setting, the following method exists:

Appium Desktop Apps

Appium’s desktop app supports OS X and Windows.

iOS Predicate

It is worth looking at ’-ios uiautomation’ search strategy with Predicates. UIAutomation JavaScript API has following methods which can are very useful.

(UIAElement) UIAElementArray.firstWithPredicate(PredicateString predicateString) (UIAElementArray) UIAElementArray.withPredicate(PredicateString predicateString)

Native JS search strategy (powered by Apple) provides much more flexibility and is like Xpath. Predicates can be used to restrict an elements set to select only those ones for which some condition is true.

For example:

// java
appiumDriver.findElementsByIosUIAutomation("collectionViews()[0].cells().withPredicate(\"ANY staticTexts.isVisible == TRUE\")")

- will select only those UIACollectionCell elements that have visible UIAStaticText child elements, and themselves are childs of 1st UIACollectionView element that should be located under the main app window. Here staticTexts() and isVisible() are methods available in UIAElementArray and UIAElement classes respectively. Note that UIAElementArray numbering begins with 0 unlike Xpath where indexes counting starts from 1

Here’s a list of available Predicates (mostly taken from Predicates Programming Guide)

Basic Comparisons

= , == - The left-hand expression is equal to the right-hand expression:

tableViews()1.cells().firstWithPredicate("label == 'Olivia' ")

same in Xpath: /UIATableView[2]/UIATableCell@label = 'Olivia'

>= , => - The left-hand expression is greater than or equal to the right-hand expression.

<= , =< - The left-hand expression is less than or equal to the right-hand expression.

> - The left-hand expression is greater than the right-hand expression.

< - The left-hand expression is less than the right-hand expression.

!= , <> - The left-hand expression is not equal to the right-hand expression.

BETWEEN - The left-hand expression is between, or equal to either of, the values specified in the right-hand side. The right-hand side is a two value array (an array is required to specify order) giving upper and lower bounds. For example, 1 BETWEEN { 0 , 33 }, or $INPUT BETWEEN { $LOWER, $UPPER }. In Objective-C, you could create a BETWEEN predicate as shown in the following example:

NSPredicate *betweenPredicate = [NSPredicate predicateWithFormat: @"attributeName BETWEEN %@", @[@1, @10]];

This creates a predicate that matches ( ( 1 <= attributeValue ) && ( attributeValue <= 10 ) )

Boolean Value Predicates

TRUEPREDICATE - A predicate that always evaluates to TRUE .

FALSEPREDICATE - A predicate that always evaluates to FALSE.

Basic Compound Predicates

AND , && - Logical AND.

OR , || - Logical OR.

NOT , ! - Logical NOT.

String Comparisons

String comparisons are by default case and diacritic sensitive. You can modify an operator using the key characters c and d within square braces to specify case and diacritic insensitivity respectively, for example firstName BEGINSWITH[cd] $FIRST_NAME

BEGINSWITH - The left-hand expression begins with the right-hand expression.

scrollViews()[3].buttons().firstWithPredicate("name BEGINSWITH 'results toggle' ") same in Xpath: /UIAScrollView[4]/UIAButton[starts-with(@name, 'results toggle')][1]

CONTAINS - The left-hand expression contains the right-hand expression.

tableViews()[1].cells().withPredicate("ANY collectionViews[0].buttons.name CONTAINS 'opera'") same in Xpath: /UIATableView[2]/UIATableCell[UIACollectionView[1]/UIAButton[contains(@name, 'opera')]]

ENDSWITH - The left-hand expression ends with the right-hand expression.

LIKE - The left hand expression equals the right-hand expression: ? and * are allowed as wildcard characters, where ? matches 1 character and * matches 0 or more characters. In Mac OS X v10.4, wildcard characters do not match newline characters.

tableViews()[0].cells().firstWithPredicate("name LIKE '*Total: $*' ") same in Xpath: /UIATableView[1]/UIATableCell[matches(@name, '.*Total: \$.*')][1]

MATCHES - The left hand expression equals the right hand expression using a regex -style comparison according to ICU v3 (for more details see the ICU User Guide for Regular Expressions).

tableViews().firstWithPredicate("value MATCHES '.*of 7' ") same in Xpath: /UIATableView[matches(@value, '.*of 7')][1]

Aggregate Operations

ANY , SOME - Specifies any of the elements in the following expression. For example ANY children.age < 18 .

tableViews()[0].cells().firstWithPredicate("SOME staticTexts.name = 'red'").staticTexts().withName('red') same in Xpath: /UIATableView[1]/UIATableCell[[email protected] = 'red'][1]/UIAStaticText[@name = 'red']

ALL - Specifies all of the elements in the following expression. For example ALL children.age < 18 .

NONE - Specifies none of the elements in the following expression. For example, NONE children.age < 18 . This is logically equivalent to NOT (ANY ...) .

IN - Equivalent to an SQL IN operation, the left-hand side must appear in the collection specified by the right-hand side. For example, name IN { 'Ben', 'Melissa', 'Matthew' } . The collection may be an array, a set, or a dictionary—in the case of a dictionary, its values are used.

array[index] - Specifies the element at the specified index in the array.

array[FIRST] - Specifies the first element in the array.

array[LAST] - Specifies the last element in the array.

array[SIZE] - Specifies the size of the array

elements()[0].tableViews()[0].cells().withPredicate("staticTexts[SIZE] > 2") same in Xpath: /*1/UIATableView1/UIATableCell[count(UIAStaticText) > 2]


C style identifier - Any C style identifier that is not a reserved word.

#symbol - Used to escape a reserved word into a user identifier.

[\]{octaldigit}{3} - Used to escape an octal number ( \ followed by 3 octal digits).

[\][xX]{hexdigit}{2} - Used to escape a hex number ( \x or \X followed by 2 hex digits).

[\][uU]{hexdigit}{4} - Used to escape a Unicode number ( \u or \U followed by 4 hex digits).


Single and double quotes produce the same result, but they do not terminate each other. For example, "abc" and 'abc' are identical, whereas "a'b'c" is equivalent to a space-separated concatenation of a, 'b', c.

FALSE , NO - Logical false.

TRUE , YES - Logical true.

NULL , NIL - A null value.

SELF - Represents the object being evaluated.

“text” - A character string.

'text’ - A character string.

Comma-separated literal array - For example, { 'comma', 'separated', 'literal', 'array' } .

Standard integer and fixed-point notations - For example, 1 , 27 , 2.71828 , 19.75 .

Floating-point notation with exponentiation - For example, 9.2e-5 .

0x - Prefix used to denote a hexadecimal digit sequence.

0o - Prefix used to denote an octal digit sequence.

0b - Prefix used to denote a binary digit sequence.

Reserved Words

The following words are reserved:


Appium predicate helpers

Appium has helpers for predicate search in app.js:

Here’s a Ruby example:

# Ruby example
text = 'Various uses'
predicate = "name contains[c] '#{text}' || label contains[c] '#{text}' || value contains[c] '#{text}'"
element = execute_script(%Q(au.mainApp().getFirstWithPredicate("#{predicate}");))

puts element.name # Buttons, Various uses of UIButton

Adjusting Network Connection

The Selenium Mobile JSON Wire Protocol Specification supports an API for getting and setting the network connection for a device. The API works through a bitmask, assigning an integer to each possible state:

Value (Alias) Data Wifi Airplane Mode
0 (None) 0 0 0
1 (Airplane Mode) 0 0 1
2 (Wifi only) 0 1 0
4 (Data only) 1 0 0
6 (All network on) 1 1 0


Unfortunately, at the moment Appium does not support the Selenium network connection API for iOS.


Choose the setting you would like to use, and then send the correct bitmask from the table above.

// javascript
// set airplane mode

// set wifi only

// set data only

// set wifi and data

Retrieving the network connection settings returns the same bitmask, from which the status can be decoded.

// javascript
driver.getNetworkConnection().then(function (connectionType) {
  switch (connectionType) {
    case 0:
      // no network connection
    case 1:
      // airplane mode
    case 2:
      // wifi
    case 4:
      // data
    case 6:
      // wifi and data

uiautomator UiSelector

Appium enables searching using UiSelectors. UiScrollable is also supported.

Note that the index selector is unreliable so prefer instance instead. The following examples are written against the api demos apk using Ruby.

Find the first textview.

# ruby
first_textview = find_element(:uiautomator, 'new UiSelector().className("android.widget.TextView").instance(0)');

Find the first element by text.

# ruby
first_text = find_element(:uiautomator, 'new UiSelector().text("Animation")')
first_text.text # "Animation"

Find the first scrollable element, then find a TextView with the text “Tabs”. The “Tabs” element will be scrolled into view.

# ruby
element = find_element(:uiautomator, 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).getChildByText(new UiSelector().className("android.widget.TextView"), "Tabs")')

As a special case, scrollIntoView returns the element that is scrolled into view. scrollIntoView allows scrolling to any UiSelector.

# ruby
element = find_element(:uiautomator, 'new UiScrollable(new UiSelector().scrollable(true).instance(0)).scrollIntoView(new UiSelector().text("WebView").instance(0));')
element.text # "WebView"

Multi-lingual Support

One problem with dealing with non-Latin characters programmatically is that, for characters with accents, there can be multiple ways of encoding the form. So, for the letter é, there are two encodings: a single combining character é (Unicode’s LATIN SMALL LETTER E WITH ACUTE), and the combination of the letter e followed by the accent, ́ (COMBINING ACUTE ACCENT). In order to deal with this, there is normalization, an operation that makes “equivalent strings have a unique binary representation”.

Luckily, normalizing ASCII text (i.e., text that doesn’t need to be normalized) does not cause any changes, and performing the operation multiple times does not have an effect. Thus a normalization function can be called on text without risking adverse effects.

// javascript
var unorm = require('unorm');

'some ASCII text' === unorm.nfd('some ASCII text');
unorm.nfd('Adélaïde Hervé') === unorm.nfd(unorm.nfd('Adélaïde Hervé'));

So, when dealing with unicode text within a test, you need to normalize, preferably on both the text expected and that received from Appium. There are a number of ways to do the normalization, so be sure to perform the same operation on both strings!

// javascript
var unorm = require('unorm');
    .then(function (txt) {
      unorm.nfd(txt).should.be(unorm.nfd("é Œ ù ḍ"));

One tell-tale sign that the problem is with the encoding of the unicode text is an assertion that fails but reports what look to be the same string:

AssertionError: expected 'François Gérard' to deeply equal 'François Gérard'
      + expected - actual

      +"François Gérard"
      -"François Gérard"

Since the error is just encoding, the output looks the same. Normalized, these should equal programmatically as well as visually.


Finding by text can also require normalization. For instance, if you have a button in an iOS app with the name Найти you may need to normalize the text within the find command.

// javascript
var unorm = require('unorm');

Otherwise the elements may not be found.

Text Fields

By default the automation tools for both iOS and Android do not support non-ASCII characters sent to editable fields through the keyboard.


Appium sends non-ASCII characters to iOS editable fields directly, bypassing the keyboard altogether. While this allows the text to be inputted in tests, it should be kept in mind that any business logic triggered by keyboard input will therefore not be tested.

As above, the text received may need to be normalized before asserting on it.

// javascript
var unorm = require('unorm');
var testText = unorm.nfd("é Œ ù ḍ");


Android tests allow for Unicode input by installing and using a specialized keyboard that allows the text to be passed as ASCII text between Appium and the application being tested.

In order to utilize this functionality, set the unicodeKeyboard desired capability is set to true. If the keyboard should be returned to its original state, the resetKeyboard desired capability should also be set to true. Otherwise Appium’s Unicode keyboard will remain enabled on the device after the tests are completed.

Then tests can pass Unicode text to editable fields using send_keys.

// javascript
var desired = {
  app: '/path/to/app',
  deviceName: 'Android Emulator',
  deviceVersion: '4.4',
  platformName: 'Android',
  unicodeKeyboard: true,
  resetKeyboard: true
var testText = 'é Œ ù ḍ';

Advanced Concepts

Selenium Grid

You are able to register your appium server with a local Selenium grid (setup docs) by using the --nodeconfig server parameter.

> appium --nodeconfig /path/to/nodeconfig.json # or, if running from source: > node . --nodeconfig /path/to/nodeconfig.json

In the node config file you have to define the browserName, version and platform and based on these parameters the grid will re-direct your test to the right device. You will also need to configure your host details and the selenium grid details. For a full list of all parameters and descriptions look here

Once you start the appium server and it registers with the grid, you will see your device on the grid console page:


Grid Node Configuration Example json file

          "browserName": "<e.g._iPhone5_or_iPad4>",
          "maxInstances": 1,
    "proxy": "org.openqa.grid.selenium.proxy.DefaultRemoteProxy",
    "host": <host_name_appium_server_or_ip-address_appium_server>,
    "port": <appium_port>,
    "maxSession": 1,
    "register": true,
    "registerCycle": 5000,
    "hubPort": <grid_port>,
    "hubHost": "<Grid_host_name_or_grid_ip-address>"

Valid platforms are listed here

If url, host, and port are not given, the config will be auto updated to point to localhost:whatever-port-Appium-started-on.

If your Appium server is running on a different machine to your Selenium Grid server, make sure you use an external name/IP address in your host & url docs; localhost and will prevent Selenium Grid from connecting correctly.

Automating hybrid apps

One of the core principles of Appium is that you shouldn’t have to change your app to test it. In line with that methodology, it is possible to test hybrid web apps (e.g., the UIAWebView elements in an iOS app) the same way you can with Selenium for web apps. There is a bit of technical complexity required so that Appium knows whether you want to automate the native aspects of the app or the web views, but thankfully, we can stay within the WebDriver protocol for everything.

Here are the steps required to talk to a web view in your Appium test:

  1. Navigate to a portion of your app where a web view is active
  2. Call GET session/:sessionId/contexts
  3. This returns a list of contexts we can access, like 'NATIVE_APP’ or 'WEBVIEW_1’
  4. Call POST session/:sessionId/context with the id of the context you want to access
  5. (This puts your Appium session into a mode where all commands are interpreted as being intended for automating the web view, rather than the native portion of the app. For example, if you run getElementByTagName, it will operate on the DOM of the web view, rather than return UIAElements. Of course, certain WebDriver methods only make sense in one context or another, so in the wrong context you will receive an error message).
  6. To stop automating in the web view context and go back to automating the native portion of the app, simply call context again with the native context id to leave the web frame.
// javascript
// assuming we have an initialized `driver` object for an app
    .contexts().then(function (contexts) { // get list of available views. Returns array: ["NATIVE_APP","WEBVIEW_1"]
        return driver.context(contexts[1]); // choose the webview context

    // do some web testing

    .context('NATIVE_APP') // leave webview context

    // do more native stuff here if we want

    .quit() // stop webdrivage
// java
// assuming we have a set of capabilities
driver = new AppiumDriver(new URL(""), capabilities);

Set<String> contextNames = driver.getContextHandles();
for (String contextName : contextNames) {
    System.out.println(contextNames); //prints out something like NATIVE_APP \n WEBVIEW_1
driver.context(contextNames.toArray()[1]); // set context to WEBVIEW_1

//do some web testing
String myText = driver.findElement(By.cssSelector(".green_button")).click();


// do more native testing if we want

# ruby
# assuming we have a set of capabilities
@driver = Selenium::WebDriver.for(:remote, :desired_capabilities => capabilities, :url => SERVER_URL)

# I switch to the last context because its always the webview in our case, in other cases you may need to specify a context
# View the appium logs while running @driver.contexts to figure out which context is the one you want and find the associated ID
# Then switch to it using @driver.switch_to.context("WEBVIEW_6")

Given(/^I switch to webview$/) do
    webview = @driver.contexts.last

Given(/^I switch out of webview$/) do

# Now you can use CSS to select an element inside your webview

And(/^I click a webview button $/) do
    @driver.find_element(:css, ".green_button").click
# python
# assuming we have an initialized `driver` object for an app

# switch to webview
webview = driver.contexts.last

# do some webby stuff
driver.find_element(:css, ".green_button").click

# switch back to native view

# do more native testing if we want

// php
// assuming we have an initialized `driver` object in an AppiumTestCase

public function testThings()
        $expected_contexts = array(
                0 => 'NATIVE_APP',
                1 => 'WEBVIEW_1'

        $contexts = $this->contexts();
        $this->assertEquals($expected_contexts, $contexts);

        $context = $this->context();
        $this->assertEquals('WEBVIEW_1', $context);

        // do webby stuff


        // do mobile stuff

Automating hybrid Android apps

Appium comes with built-in hybrid support via Chromedriver. Appium also uses Selendroid under the hood for webview support on devices older than 4.4. (In that case, you’ll want to specify "automationName": "selendroid" as a desired capability).

Make sure setWebContentsDebuggingEnabled is set to true as described in the remote debugging docs.

Once you’ve set your desired capabilities and started an appium session, follow the generalized instructions above.

Automating hybrid iOS apps

To interact with a web view appium establishes a connection using a remote debugger. When executing against a simulator this connection is established directly as the simulator and the appium server are on the same machine.

Once you’ve set your desired capabilities and started an appium session, follow the generalized instructions above.

Execution against a real iOS device

When executing against a real iOS device appium is unable to access the web view directly. Therefore the connection has to be established through the USB lead. To establish this connection we use the ios-webkit-debugger-proxy.

For instruction on how to install and run ios-webkit-debugger-proxy see iOS webkit debug proxy documentation.

Now you can start an appium test session and follow the generalized instructions above.


Settings are a new concept introduced by appium. They are currently not a part of the Mobile JSON Wire Protocol, or the Webdriver spec.

Settings are a way to specify the behavior of the appium server.

Settings are: - Mutable, they can be changed during a session - Only relevant during the session they are applied. They are reset for each new session. - Control the way the appium server behaves during test automation. They do not apply to controlling the app or device under test.

An example of a setting would be ignoreUnimportantViews for Android. Android can be set to ignore elements in the View Hierarchy which it deems irrelevant. Setting this can cause tests to run faster. A user who wants to access the ignored elements however, would want to disable ignoreUnimportantViews, and reenable it afterwards.

Another example of a use-case for settings would be telling appium to ignore elements which are not visible.

Settings are implemented via the following API endpoints:

POST /session/:sessionId/appium/settings

Expects a JSON hash of settings, where keys correspond to setting names, and values to the value of the setting. { settings: { ignoreUnimportantViews : true } }

GET /session/:sessionId/appium/settings

Returns a JSON hash of all the currently specified settings. { ignoreUnimportantViews : true }

Supported Settings

“ignoreUnimportantViews” - Boolean which sets whether Android devices should use setCompressedLayoutHeirarchy() which ignores all views which are marked IMPORTANT_FOR_ACCESSIBILITY_NO or IMPORTANT_FOR_ACCESSIBILITY_AUTO (and have been deemed not important by the system), in an attempt to make things less confusing or faster.

iOS WebKit Debug Proxy

For accessing web views on real iOS device appium uses ios_webkit_debug_proxy.


Using Homebrew

To install the latest tagged version of the ios-webkit-debug-proxy using Homebrew, run the following commands in the terminal:

# The first command is only required if you don't have brew installed. > ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" > brew update > brew install ios-webkit-debug-proxy

Building ios-webkit-debug-proxy from source

Open the command terminal on your mac. You can find instructions on how to open the terminal via your favorite search engine. Once that is open, verify you have Homebew installed:

$ brew -v

When you’re certain you have Homebrew, do the following (the $ indicates the command line prompt, do not enter it):

$ cd  ~
$ sudo apt-get install autoconf automake libusb-dev libusb-1.0-0-dev libplist-dev libplist++-dev usbmuxd libtool libimobiledevice-dev
$ git clone https://github.com/google/ios-webkit-debug-proxy.git
$ cd ios-webkit-debug-proxy
$ ./autogen.sh
$ make
$ sudo make install

Running ios-webkit-debug-proxy

Once installed you can start the proxy with the following command:

# Change the udid to be the udid of the attached device and make sure to set the port to 27753 # as that is the port the remote-debugger uses. You can learn how to retrieve the UDID from # Apple's developer resources. > ios_webkit_debug_proxy -c 0e4b2f612b65e98c1d07d22ee08678130d345429:27753 -d

You may also use the ios-webkit-debug-proxy-launcher to launch the proxy. It monitors the proxy log for errors, and relaunch the proxy where needed. This is also optional and may help with recent devices:

# change the udid > ./bin/ios-webkit-debug-proxy-launcher.js -c 0e4b2f612b65e98c1d07d22ee08678130d345429:27753 -d

NOTE: the proxy requires the “web inspector” to be turned on to allow a connection to be established. Turn it on by going to settings > safari > advanced. Please be aware that the web inspector was added as part of iOS 6 and was not available previously.

Migrating your tests from Appium 0.18.x to Appium 1.x

Appium 1.0 has removed a number of deprecated features from the previous versions. This guide will help you know what needs to change in your test suite to take advantage of Appium 1.0.

New client libraries

The biggest thing you need to worry about is using the new Appium client libraries instead of the vanilla WebDriver clients you are currently using. Visit the Appium client list to find the client for your language. Downloads and instructions for integrating into your code are available on the individual client websites.

Ultimately, you’ll be doing something like (to use Python as an example):

from appium import webdriver

Instead of:

from selenium import webdriver

New desired capabilities

The following capabilities are no longer used:

Instead, use these capabilities:

The app capability remains the same, but now refers exclusively to non-browser apps. To use browsers like Safari or Chrome, use the standard browserName cap. This means that app and browserName are exclusive.

We have also standardized on camelCase for Appium server caps. That means caps like app-package or app-wait-activity are now appPackage and appWaitActivity respectively. Of course, since Android app package and activity are now auto-detected, you should be able to omit them entirely in most cases.

New locator strategies

We’ve removed the following locator strategies:

We have now added the accessibility_id strategy to do what name used to do. The specifics will be relative to your Appium client.

tag name has been replaced by class name. So to find an element by its UI type, use the class name locator strategy for your client.

Note about class name and xpath strategies: these now require the fully-qualified class name for your element. This means that if you had an xpath selector that looked like this:


It would now need to be:


(And likewise for Android: button now needs to be android.widget.Button)

We’ve also added the following locator strategies:

Refer to your client for ways to use these new locator strategies.


App source methods, which previously returned JSON, now return XML, so if you have code that relies on parsing the app source, it will need to be updated.

Hybrid support through context, not window

Hybrid apps were previously supported by switching between “windows” using

Now Appium supports the more conceptually consistent concept of “context”. To get all of the available contexts, or the particular context the application is is, you use

# python
current = driver.context
// javascript
driver.contexts().then(function (contexts) { /*...*/ })
// c#
driver.GetContexts ()
driver.GetContext ()
// java
Set<String> contextNames = driver.getContextHandles();
String context = driver.getContext();
// php
$contexts = $this->contexts();
$context = $this->context();
# ruby
contexts = available_contexts
context = current_context

And to switch between them, you use

# python
// javascript
driver.currentContext().then(function (context) { /*...*/ })
// c#
driver.SetContext ("WEBVIEW");
// php
# ruby
set_context "WEBVIEW"

No more execute_script("mobile: xxx")

All the mobile: methods have been removed, and have been replaced by native methods in the Appium client libraries. This means that a method call like driver.execute("mobile: lock", [5]) will now look something more like driver.lock(5) (where lock has been turned into a native client method). Of course, the details on calling these methods will differ by client.

Of particular note, the gesture methods have been replaced by the new TouchAction / MultiAction API which allows for a much more powerful and general way of putting gestural automation together. Refer to your Appium client for usage notes on TouchAction / MultiAction.

And that’s it! Happy migrating!

Setting up instruments without delay (iwd) for xcode 7 and iOS >= 9.0

For iOS >= 9.0 instruments without delay (iwd) does not work by passing binaries through the command line (appium does this under the hood for xcode < 7). See iwd

For enabling iwd for xcode >= 7, - Checkout appium-instruments - Run xcode-iwd.sh present in <appium-instruments>/bin/

sh <appium-instruments>/bin/xcode-iwd.sh <path to xcode> <path to appium-instruments>

eg. sh ./bin/xcode-iwd.sh /Applications/Xcode.app /Users/xyz/appium-instruments/

Note: iwd with xcode7 will only work for iOS >= 9.0, you can switch to older xcode for iOS < 9.0

Appium GUI

An OS X GUI for Appium

Build Status

If you are new to Appium then please see the Getting started guide for more information about the project.

To install:

  1. Download the latest version from Appium.io.
  2. Mount the disk image.
  3. Drag Appium.app to your Applications folder.

Build with XCode

Install CocoaPods:

  1. Open Termianl
  2. sudo gem install cocoapods
  3. pod setup
  4. cd appium-dot-app
  5. pod install

To Open in XCode:

open the appium-dot-app/Appium.xcworkspace project file

Parameter Guide

Main Window

Appium Main Window

Android Settings

iOS Settings

Preference Guide

Preferences can be accessed by clicking on the appropriate button in the main window.

Appium Preferences

General Settings

Developer Settings

Inspector / Recorder

Inspector can be accessed by clicking the magnifying glass next to the launch button once the Appium server has launched. Appium must be running with an app open for inspector to work. Otherwise, it will not work. Appium Inspector

Inspector Window

Action Palette

The action pallete contains buttons that will trigger actions on the device under test. You can try out actions here or enter them to be recorded.

Recorder Drawer

The recorder draw contains the code generated by recorded actions you’ve performed while recording is enabled.

A Windows GUI for Appium

If you are new to Appium then please see the Getting started guide for more information about the project.

Pre-req: * Need .NET Framework 4.5 redistributable libraries

To install:

  1. Download the latest version from Appium.io.
  2. Extract the ZIP file.
  3. Launch appium.exe.

To update Appium Server manually:

  1. Close appium-dot-exe
  2. Go appium-dot-exe main directory
  3. Delete node_modules folder
  4. Delete node.exe file
  5. Launch appium.exe
  6. Download should occur automatically

Parameter Guide

Main Window

Appium Main Window

Android Settings

Preference Guide

Preferences can be accessed by clicking on the appropriate button in the main window.

Appium Preferences

General Settings

Developer Settings

Inspector / Recorder

Inspector can be accessed by clicking the magnifying glass next to the launch button once the Appium server has launched. Appium must be running with an app open for inspector to work. Otherwise, it will not work.

The Inspector can be use to connect to an external Appium server. This can be specified in the General Settings.

Appium Inspector