Device SDK Reference
Back to README | Commands | MCP SetupUse the Revyl Device SDK for programmatic device control and live test step execution.
Install
REVYL_BINARYenv var — explicit path for local dev or CI- SDK-managed binary at
~/.revyl/bin/(with valid checksum sidecar) revylonPATH- Auto-download from GitHub releases
Authenticate
RevylCLI
Low-level runner for arbitrary CLI commands.RevylCLI(binary_path=None, dev_mode=False)
| Parameter | Type | Description |
|---|---|---|
binary_path | Optional[str] | Path to the revyl binary. If None, auto-resolved via ensure_binary(). |
dev_mode | bool | When True, prepends --dev to every command for local development servers. |
cli.run(*args, json_output=False)
Run a CLI command. Returns parsed JSON when json_output=True, otherwise returns stdout as a string.
Raises RevylError on non-zero exit code.
DeviceClient
High-level helper for device interaction. Every action method returns adict with the CLI’s JSON response.
Quick Start
Context Manager
Fire-and-Forget Start
Reusing an Existing Session
Constructor
DeviceClient(cli=None, session_index=None, auto_report=True, verbose=True)
| Parameter | Type | Description |
|---|---|---|
cli | Optional[RevylCLI] | Custom CLI runner. If None, a default RevylCLI() is created. |
session_index | Optional[int] | Attach to an existing session by index. |
auto_report | bool | Auto-print the report URL when the session closes. |
verbose | bool | Print status messages during session lifecycle. |
Grounded Targets vs Coordinates
Most action methods accept either a groundedtarget (natural language element description) or raw x, y coordinates. Provide one or the other, not both.
"blue 'Sign In' button" for better accuracy.
Session Management
DeviceClient.start(platform, ..., wait_for_ready=True, ready_timeout=60, auto_report=True) -> DeviceClient
Class method. Start a device session and return a connected client.
By default, blocks until the device is API-ready. Pass wait_for_ready=False for fire-and-forget provisioning.
| Parameter | Type | Description |
|---|---|---|
platform | str | "ios" or "android" |
timeout | Optional[int] | Idle timeout in seconds |
open_viewer | bool | Open the live viewer in the browser |
app_id | Optional[str] | Revyl app ID to preinstall |
build_version_id | Optional[str] | Specific build version to install |
app_url | Optional[str] | URL to an .ipa or .apk to preinstall |
app_link | Optional[str] | Deep link to open after launch |
device_model | Optional[str] | Target device model (e.g. "iPhone 16"). Must be paired with os_version. |
os_version | Optional[str] | Target OS version (e.g. "iOS 18.5"). Must be paired with device_model. |
cli | Optional[RevylCLI] | Custom CLI instance |
wait_for_ready | bool | Block until device is API-ready (default True). Set False for fire-and-forget. |
ready_timeout | float | Max seconds to wait for readiness when wait_for_ready=True (default 60). |
auto_report | bool | Auto-print report/video URLs on close() (default True). |
verbose | bool | Show animated spinner during provisioning (default True). Set False for CI. |
start_session(platform, timeout=None, open_viewer=False, app_id=None, build_version_id=None, app_url=None, app_link=None, device_model=None, os_version=None) -> dict
Start a device session. Same parameters as start() (except cli). Returns session info including the session index.
stop_session(session_index=None) -> dict
Stop a device session. Defaults to the tracked session.
stop_all() -> dict
Stop all active sessions.
list_sessions() -> list[dict]
List all active device sessions.
use_session(index) -> str
Switch the active session. Returns confirmation text.
info(session_index=None) -> dict
Get session details including whep_url when streaming is available.
doctor(session_index=None) -> str
Run diagnostics on auth, session, device, and grounding health. Returns text output.
wait_for_device_ready(timeout=60, poll_interval=3) -> bool
Poll device doctor until the device is reported as connected. Called automatically by start(wait_for_ready=True). Returns True if the device became ready, False on timeout.
wait_for_report(timeout=30, poll_interval=2) -> dict
Poll until the session report is generated and return it. Raises RevylError if unavailable within timeout.
close() -> None
Best-effort stop for the tracked session. Called automatically when using the context manager. When auto_report=True (default), fetches and prints the report URL before stopping.
Actions
tap(target=None, x=None, y=None, session_index=None) -> dict
Tap an element by target description or coordinates.
double_tap(target=None, x=None, y=None, session_index=None) -> dict
Double-tap an element.
long_press(target=None, x=None, y=None, duration_ms=1500, session_index=None) -> dict
Long press an element. duration_ms controls hold duration.
type_text(text, target=None, x=None, y=None, clear_first=True, session_index=None) -> dict
Type text into a field. Set clear_first=False to append instead of replace.
swipe(direction, target=None, x=None, y=None, duration_ms=500, session_index=None) -> dict
Swipe in a direction ("up", "down", "left", "right") from a target or point.
drag(start_x, start_y, end_x, end_y, session_index=None) -> dict
Drag from one point to another (coordinates only).
pinch(target=None, x=None, y=None, scale=2.0, duration_ms=300, session_index=None) -> dict
Pinch/zoom gesture. scale > 1 zooms in, scale < 1 zooms out.
clear_text(target=None, x=None, y=None, session_index=None) -> dict
Clear text in a field.
Controls
back(session_index=None) -> dict
Android back button. Not supported on iOS.
key(key, session_index=None) -> dict
Press a key. Supported values: "ENTER", "BACKSPACE".
shake(session_index=None) -> dict
Trigger a shake gesture.
wait(duration_ms=1000, session_index=None) -> dict
Wait for a fixed duration.
go_home(session_index=None) -> dict
Return to the home screen.
open_app(app, session_index=None) -> dict
Open a system app by name (e.g. "settings").
navigate(url, session_index=None) -> dict
Open a URL or deep link on the device.
set_location(latitude, longitude, session_index=None) -> dict
Set the device GPS location.
download_file(url, filename=None, session_index=None) -> dict
Download a file to the device. Returns device_path in the response.
App Management
install_app(app_url=None, build_version_id=None, bundle_id=None, session_index=None) -> dict
Install an app from a URL (.ipa or .apk) or a previously uploaded build version. Provide exactly one of app_url or build_version_id.
launch_app(bundle_id, session_index=None) -> dict
Launch an installed app by bundle ID.
kill_app(session_index=None) -> dict
Kill the currently running app.
Live Steps
Execute individual test steps against an active device session without creating a full test.instruction(description, session_index=None) -> dict
Execute one instruction step. The description is a natural-language action like "Open Settings and tap Wi-Fi".
validation(description, session_index=None) -> dict
Execute one validation step. The description is an assertion like "Verify the inbox is visible".
extract(description, variable_name=None, session_index=None) -> dict
Execute one extract step. Returns extracted data from the screen. Use variable_name to tag the result for downstream use.
code_execution(script_id=None, file_path=None, code=None, runtime=None, session_index=None) -> dict
Execute a code execution step. Provide exactly one of script_id, file_path, or code. When using file_path or code, a runtime is required ("python", "javascript", "typescript", or "bash").
Capture
screenshot(out=None, session_index=None) -> dict
Take a screenshot. If out is provided, the image is saved to that file path.
Reporting & Discovery
report(session_index=None) -> dict
Fetch the session report including status, steps, video URL, and report URL.
targets(platform=None, cli=None) -> dict (static method)
List available device models and OS versions. Can be called without a session.
history(limit=20, cli=None) -> list[dict] (static method)
Show recent device session history. Can be called without a session.
wait_for_stream(timeout=30, poll_interval=2) -> str | None
Poll info() until the WebRTC WHEP URL is available and return it. Use this when you need the stream URL for building live viewers or streaming integrations. Not called automatically by start().
Note:wait_for_stream()checks for the stream URL, not device API readiness. Usewait_for_device_ready()(built intostart()by default) to ensure the device is ready for actions likescreenshot()andtap().
Live Streaming
Every active device session streams the live screen over WebRTC. The stream URL is a standard WHEP (WebRTC-HTTP Egress Protocol) endpoint — you can feed it into any WHEP-compatible player to embed the device screen in your own dashboard, CI viewer, or internal tool.Retrieving the stream URL
Usewait_for_stream() for the simplest approach:
device.info() directly — the whep_url field contains the playback URL:
device.list_sessions().
Using the stream
The WHEP URL works with any client that speaks the WHEP protocol. A few options:- Browser: Use a WHEP JavaScript client (e.g.
@AlexxIT/go2rtcor Cloudflare’s player SDK) to render a<video>element. - CLI:
revyl device info --json | jq -r '.whep_url'to pipe the URL into other tools. - Custom integration: POST to the WHEP URL with an SDP offer to negotiate a WebRTC session — the response contains the SDP answer.
ScriptClient
Manage code-execution scripts (Python, JavaScript, TypeScript, Bash) used bycode_execution blocks in tests.
list(runtime=None) -> list[dict]
List all scripts, optionally filtered by runtime ("python", "javascript", "typescript", "bash").
get(name_or_id) -> dict
Get a script by name or UUID, including its source code.
create(name, file_path, runtime, description=None) -> dict
Create a new script from a local file.
update(name_or_id, file_path=None, name=None, description=None) -> dict
Update a script’s code, name, or description.
delete(name_or_id, force=True) -> str
Delete a script. Raises RevylError if the script is in use by tests.
usage(name_or_id) -> list[dict]
List tests that reference this script.
ModuleClient
Manage reusable test modules — shared groups of test blocks that can be imported viamodule_import.
list(search=None) -> list[dict]
List all modules, optionally filtered by name or description substring.
get(name_or_id) -> dict
Get a module by name or UUID, including its blocks.
create(name, blocks_file, description=None) -> dict
Create a module from a YAML file containing a blocks: array.
update(name_or_id, name=None, blocks_file=None, description=None) -> dict
Update a module’s blocks, name, or description.
delete(name_or_id, force=True) -> str
Delete a module. Raises RevylError (HTTP 409) if still referenced by tests.
usage(name_or_id) -> list[dict]
List tests that import this module.
BuildClient
Upload and manage app builds on Revyl.upload(app_name=None, platform=None, skip_build=False, version=None, set_current=False) -> dict
Build and upload an app. Uses the project’s .revyl/config.yaml build commands by default.
list(app_name=None, platform=None) -> list[dict]
List uploaded build versions, optionally filtered by app or platform.
delete(name_or_id, version=None, force=True) -> str
Delete an app (and all versions) or a specific build version.
Types
DeviceModel
Union type of all supported device models. Auto-generated from device-targets.json.
DeviceClient.start(device_model=..., os_version=...) to target a specific device. Both parameters must be provided together. Use DeviceClient.targets() to list all available combinations.
OsVersion
Union type of all supported OS versions. Auto-generated from device-targets.json.
Other Types
| Type | Definition | Description |
|---|---|---|
Platform | Literal["ios", "android"] | Target platform |
Runtime | Literal["python", "javascript", "typescript", "bash"] | Code execution runtime |
SwipeDirection | Literal["up", "down", "left", "right"] | Swipe direction |
KeyInput | Literal["ENTER", "BACKSPACE"] | Keyboard key input |
Error Handling
All CLI failures raiseRevylError:
| Error | Cause |
|---|---|
RevylError on first command | Not authenticated. Run revyl auth login or set REVYL_API_KEY. |
ValueError: Provide target OR x/y | Passed both target and coordinates to an action method. |
ValueError: ... must not be empty | Empty string passed to a live step method. |
TypeScript Device SDK (CLI JSON Wrapper)
There is no published TypeScript Device SDK. Therevyl npm package is a binary wrapper only. For TypeScript projects, shell out to the CLI with --json and parse the response. The pattern below mirrors the Python DeviceClient: