> ## Documentation Index
> Fetch the complete documentation index at: https://docs.revyl.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Appium

> The Revyl driver connects a supported native Appium subset to existing device sessions.

The **Revyl Appium driver** is a thin extension loaded by your own
Appium server. It maps a limited set of native WebDriver commands to Revyl's
existing device APIs. Your test keeps using an Appium client; it does not need
to become a Revyl test or call an AI agent.

<Warning>
  This is a source-installed driver, not a hosted Appium service. The Python
  smoke sample and native-command checks have been verified against synthetic
  apps on staging Android emulators and iOS simulators. That coverage does not
  establish broader compatibility or make this a drop-in replacement for
  UiAutomator2 or XCUITest.
</Warning>

For the supported device lifecycle, use the
[device quickstart](/infrastructure/quickstart). A viewer URL is still a live
stream, not a WebDriver endpoint.

## How it connects

```text theme={null}
Your Appium test client
          |
Local Appium server + Revyl driver
          |
Authenticated Revyl device API
          |
Existing Android emulator / iOS simulator session
```

The driver uses the backend's session lookup and authenticated device proxy.
It does not expose worker addresses or require ADB, WebDriverAgent, or local
Xcode. Access is checked by the backend for the session and each proxied
operation. Only one controller should operate a session at a time.

## Install and connect

Get the [standalone Appium driver](https://github.com/RevylAI/appium-revyl-driver)
and follow its README for setup and a runnable Python sample. Repository access
is required. Use Node 24+ and npm 10 or newer; install before loading runtime
credentials:

```bash theme={null}
git clone https://github.com/RevylAI/appium-revyl-driver.git
cd appium-revyl-driver
npm ci --ignore-scripts
npx --no-install appium driver install --source=local "$PWD"
```

There is no published `revyl` Appium driver on npm yet; use the source install
above rather than `appium driver install revyl`. Contact
[Revyl support](mailto:support@revyl.ai) if you need repository access.

Start or select a running Revyl session with your app already installed and
launched. Creating a session uses your organization's cloud resources. Keep
the session ID returned by the [quickstart](/infrastructure/quickstart).

Provide `REVYL_API_KEY` to the Appium server through your secret manager or CI
environment, then run:

```bash theme={null}
npx --no-install appium --address 127.0.0.1 --port 4723 --log-level warn
```

Keep the server on loopback: exposing it would grant callers access through
your server credential. Do not put API keys in capabilities or enable debug
logging around sensitive test inputs.

Point your existing Appium client at `http://127.0.0.1:4723` and use these
capabilities instead of its standard native-driver capabilities:

```json theme={null}
{
  "platformName": "Android",
  "appium:automationName": "Revyl",
  "appium:revylSessionId": "YOUR_RUNNING_REVYL_SESSION_UUID",
  "appium:noReset": true
}
```

Use `"iOS"` for an iOS session. A session ID is not an ADB serial or simulator
UDID. Capabilities that request installation, reset, browser automation, or
another driver's behavior are rejected.

## Which existing test commands work?

| Command                                | Supported behavior                                                                                  |
| -------------------------------------- | --------------------------------------------------------------------------------------------------- |
| Create and quit the Appium session     | Attach and detach only; never allocate or stop a Revyl device.                                      |
| Find elements by accessibility ID      | Exact Android `content-desc` or iOS `AXUniqueId`.                                                   |
| Find elements by native ID or class    | Exact full Android `resource-id`; native Android class or raw iOS type such as `TextField`.         |
| Find within an element                 | Search descendants only, excluding the parent itself.                                               |
| Read text, enabled state, or rectangle | Read from the current native hierarchy.                                                             |
| Read native attributes                 | Raw allowlisted platform attributes as strings, or `null` when an allowed attribute is absent.      |
| Click                                  | Tap the center after rechecking the hierarchy.                                                      |
| Send text                              | Tap a recognized native editable field and type without clearing; no special keys or clear command. |
| Screenshot                             | Return a PNG through WebDriver.                                                                     |
| Activate an installed app              | Native Appium activate-app endpoint with bundle/package ID, without launch options.                 |
| Read or select context                 | `NATIVE_APP` only; selecting it does not change the device.                                         |
| Native gestures                        | Explicit `revyl:tap`, `revyl:doubleTap`, `revyl:longPress`, and directional `revyl:swipe` commands. |

Screenshots must be non-interlaced PNGs of at most 16 megapixels. Backend
responses are bounded to 16 MiB.

XPath, iOS predicates/class chains, visibility assertions, page source,
browser/WebView contexts, W3C actions, `mobile:` scripts, and arbitrary execute scripts are not supported. A suite
using these needs adaptation or its existing execution environment.

<Note>
  Find an element again after every tap, text input, app launch, or hierarchy
  change. The native API does not expose stable element handles, so the driver
  deliberately raises stale-element errors instead of reusing old coordinates.
  Dynamic screens may need test changes. The hierarchy check and coordinate
  action are not atomic; avoid destructive flows and concurrent controllers.
  Handles are never re-resolved by selector. Identical-looking replacement nodes
  or changes that occur and revert between observations cannot be detected.
</Note>

The [Python smoke example](https://github.com/RevylAI/appium-revyl-driver/blob/main/examples/native_smoke.py) uses accessibility-ID
lookups, text input, a tap, an exact text assertion, and a private screenshot.
Adapt its fixture-app locators to your app. In WebdriverIO, use `addValue` to
avoid the unsupported clear command that `setValue` may invoke first. Native
input taps the field before typing without clearing it, which can move the
caret or change the selection. Appending at the end is not guaranteed; use an
initially empty field for the smoke example.

Clear, install, and reset remain unsupported. A coordinate-based clear cannot
verify that the same editable target became empty, and restarting an app is not
a data reset. The driver rejects these operations rather than approximating them.
The current text-input path may include typed text in action reports; use
non-sensitive test data, not credentials.

## Native gestures

Each execute command takes exactly one options object. These are Revyl contracts,
not UiAutomator2 or XCUITest `mobile:` commands:

```python theme={null}
driver.execute_script("revyl:tap", {"x": 100, "y": 200})
driver.execute_script("revyl:doubleTap", {"x": 100, "y": 200})
driver.execute_script("revyl:longPress", {"x": 100, "y": 200, "durationMs": 1500})
driver.execute_script("revyl:swipe", {"x": 100, "y": 200, "direction": "up", "durationMs": 500})
```

Coordinates must be integers inside the current native screen: Android pixels
and iOS points, not iOS screenshot pixels. Long press accepts 1–10000 ms and
defaults to 1500 ms. Swipe accepts the same duration range, defaults to 500 ms,
and moves one quarter of the screen dimension in the requested direction,
clamped at the edge. Explicit endpoints, custom distances, pinch, and drag are
unsupported. Double-tap uses the worker's native two-tap gesture without a
configurable interval. Unknown options are rejected.

## Evidence and cleanup

Inspect the test's actual assertions and screenshots before claiming a pass.
Native actions use the existing Revyl action-report path with `Appium` agent
attribution. A screenshot or a successful HTTP request alone does not prove
your test passed. A timed-out action may already have executed; the driver
does not retry it. Worker/device providers can still retry internally, so this
is not an end-to-end at-most-once guarantee.

Always quit the Appium session in your test's cleanup. Then the job that owns
the cloud allocation must separately release it:

```bash theme={null}
revyl device stop --session-id "$REVYL_SESSION_ID"
```

Stop only the session your job owns. Quitting the driver intentionally leaves
an externally owned Revyl session running.

## Standard drivers and broader compatibility

This subset does not provide standard UiAutomator2 connectivity over ADB or
XCUITest's WebDriverAgent and host-side operations. Those remain separate
integration requirements for broader compatibility. It also does not enable
[Maestro](/infrastructure/maestro).
