Skip to main content
The CLI, TypeScript SDK, REST API, and embedded viewer use the same interaction model for iOS Simulator and Android Emulator sessions. Each request targets an active session, carries a correlation id and timeout, and returns a structured acknowledgement or error.

Authenticate and create a session

Install the CLI and sign in:
For CI, the SDK, or direct REST requests, create an API key in the run.cloud dashboard and put it in the process environment:
Create a session with an app installed. The examples below keep the session id in the shell and release it on exit:
Use a simulator-compatible iOS build or an emulator-compatible Android APK. See Run an iOS Simulator and Run an Android Emulator for artifact and lifecycle details.

Coordinate and input conventions

Points use normalized display coordinates. The top-left corner is { x: 0, y: 0 }, the center is { x: 0.5, y: 0.5 }, and the bottom-right corner is { x: 1, y: 1 }. Both endpoints are valid. Coordinates follow the current display orientation, so the same point always refers to the same visible part of the screen after rotation. swipe and gesture durations are in milliseconds. A gesture has 2 to 1,000 ordered steps, starts with begin, ends with end, and may have move steps between them. Every step has either one point or two points, and the point count cannot change during a gesture. delayMs is the wait before the next step; each delay can be 0 to 5,000 milliseconds and their sum cannot exceed the request timeout. The final end step has no next step, so omit its delay or set it to 0. Swipe duration defaults to 300 milliseconds. Key and button holds default to 50 milliseconds. Scroll deltas are normalized from -1 to 1 and at least one axis must be nonzero. Provide both x and y when anchoring a scroll. Digital Crown delta must be nonzero and between -10,000 and 10,000. typeText accepts 1 to 10,000 US ASCII characters, plus tabs and line feeds. Use pressKey when the physical key matters. Modifiers are shift, control, alt, and meta; each represents the left modifier key. A key or button hold can last 20 to 30,000 milliseconds. Swipe duration can be 50 to 30,000 milliseconds.

CLI

Replace ios with android to use the same command on an Android session. These commands return stable JSON with --json:
Pass gesture steps as JSON. Quoting the array prevents the shell from changing it:
A two-finger gesture uses two points in every step:
iOS also supports rendering controls:
Every interaction command accepts --timeout <milliseconds> from 100 to 60,000 (default 15,000), --request-id <id>, and --json. Request ids can contain letters, numbers, ., _, :, and -, up to 128 characters. Capture either platform as a PNG:
The screenshot result includes the absolute output path, byte size, and SHA-256 digest. The CLI checks the PNG signature before writing the file.

TypeScript SDK

Install the SDK on Node.js 20 or newer:
Platform clients expose a generic interact method and named methods for every action:
cloud.ios and cloud.android provide: Interaction and screenshot options accept requestId, timeoutMs, and signal. Aborting a signal stops the caller from waiting; it does not release the session and cannot undo an action that the simulator has already accepted. Use cloud.simulators when the platform is selected at runtime. Its methods take the same arguments, plus { platform: "ios" | "android" } in the options object.

REST API

Send an interaction to:
platform is ios or android. Authenticate with the same bearer API key used by the SDK:
The request is a flat object. Add requestId and timeoutMs to any action: Screenshot is a separate binary endpoint on both platforms:
It returns image/png for an active session owned by the authenticated user. Send X-Run-Cloud-Request-ID with a 1-to-128-character correlation id. If you omit it, the API generates one and returns it in the same response header. Screenshot failures use the same JSON envelope as interactions, with action: "screenshot" and a stable screenshot_* error code.

Acknowledgements and errors

A successful interaction returns HTTP 200 and a typed result:
The acknowledgement confirms that the control operation was accepted and dispatched. It cannot prove that the app handled the input. Read app state or take a screenshot when the visible outcome is part of the test. Every action has the documented action-specific result object except reload, toggleSoftwareKeyboard, and simulateMemoryWarning, which omit result. Errors keep the same envelope in REST, SDK metadata, and CLI JSON:
Validation errors use invalid_interaction. A released, expired, or unknown session uses active_session_not_found. An action outside the platform matrix uses unsupported_action. Transport failures and timeouts are marked retryable when another attempt may succeed. Check the HTTP status as well as error.code; do not retry an invalid request or unsupported action. Interaction codes are invalid_interaction, active_session_not_found, simulator_capacity_unavailable, unsupported_action, duplicate_request, interaction_cancelled, interaction_timeout, interaction_transport_error, interaction_invalid_response, and interaction_failed. Screenshot codes are invalid_screenshot_request, active_session_not_found, simulator_capacity_unavailable, screenshot_cancelled, screenshot_timeout, screenshot_transport_error, screenshot_invalid_response, and screenshot_failed. The CLI reports locally invalid arguments as a non-retryable invalid_request JSON error before authenticating. The SDK rejects invalid arguments with TypeError or RangeError before making a request. The CLI writes the JSON error to stderr and exits nonzero. Pressing Ctrl-C while an interaction is pending returns status cancelled, code interaction_cancelled, and exit code 130. A CLI timeout returns status timed_out and code interaction_timeout. Screenshot capture uses screenshot_cancelled, screenshot_timeout, screenshot_transport_error, and screenshot_invalid_response. Neither cancellation nor timeout releases the session. SDK API failures throw RunCloudError. Interaction failures can populate code, retryable, details, requestId, sessionId, platform, action, interactionStatus, acceptedAt, completedAt, and durationMs. A caller AbortSignal rejects with its abort reason instead. For session creation, isSimulatorCapacityError(error) narrows the exact retry-safe capacity 503; other authentication, validation, and service errors do not match it.

Platform capabilities

Button support differs by device: On iOS, home, appSwitcher, and recents are momentary navigation actions; durationMs does not turn them into long presses. Physical buttons honor the requested hold duration on both platforms. Render options are colorBlendedLayers, colorCopiedImages, colorMisalignedImages, colorOffscreenRendered, and slowAnimations. Orientations are portrait, portrait_upside_down, landscape_left, and landscape_right. Current run.cloud iPhone Simulator sessions do not render portrait_upside_down; the API, CLI, SDK, and iframe return a non-retryable unsupported_action acknowledgement with the supported orientations. Android Emulator sessions support all four values.

Semantic keys

All key names are case-sensitive:
  • letters: a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z;
  • digits: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9;
  • editing: enter, escape, backspace, tab, space, insert, delete;
  • punctuation: minus, equal, bracketLeft, bracketRight, backslash, semicolon, quote, backquote, comma, period, slash;
  • navigation: home, end, pageUp, pageDown, arrowRight, arrowLeft, arrowDown, arrowUp;
  • system and function: capsLock, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, printScreen, scrollLock, pause, numLock;
  • number pad: numpadDivide, numpadMultiply, numpadSubtract, numpadAdd, numpadEnter, numpad0, numpad1, numpad2, numpad3, numpad4, numpad5, numpad6, numpad7, numpad8, numpad9, numpadDecimal.
Android Emulator sessions return unsupported_action for the lock-state keys capsLock, numLock, and scrollLock. Other listed semantic keys are available on both platforms.

Embedded viewer

The React RemoteControl handle exposes corresponding typed methods. The acknowledged orientation and reload helpers are named setOrientation and reloadApp to distinguish them from legacy fire-and-forget controls. It sends each action through the signed iframe and resolves only when the matching requestId result arrives:
For a raw iframe, post the flat interaction with type, requestId, and timeoutMs:
The iframe replies with type: "run-cloud:interaction-result", the matching request id, platform, action, status, timing, and typed result or error fields. Acknowledged results and failures always include valid acceptedAt, completedAt, and durationMs timing. A browser-side timeout raised before any acknowledgement cannot identify a platform. Verify both event.source and event.origin before trusting a result. See Embed a Simulator for a complete secure listener and session lifecycle example. To stop pending work, post { type: "run-cloud:interaction-cancel", requestId, action } to the same exact origin. Cancellation is best effort and cannot undo an action that completed.

Screenshot examples

The maintained examples build a small native app, create a session, install the app, capture a PNG, validate its dimensions, and release the session.
Both write screenshots/run-cloud-proof.png. Pass --open to open the signed viewer while the example runs, or --app <path> to use a prebuilt artifact. Building the iOS app requires macOS with Xcode. Building the Android app requires JDK 17 or newer and Android SDK 35 or newer. Source: iOS screenshot example and Android screenshot example.