iOS JavaScript SDK
@midscene/ios controls iOS devices through WebDriverAgent (WDA). IOSAgent inherits all AI methods from the base Agent.
Imports and API overview
In most cases, use the agentFromWebDriverAgent() factory to create and connect a Device in one step. If you need to configure and manage the IOSDevice and IOSAgent instances separately, construct them explicitly.
agentFromWebDriverAgent()
Connects to WebDriverAgent and returns an IOSAgent bound to the connected Device. options accepts both Agent and Device settings. Note that wdaBaseUrl cannot be combined with wdaHost or wdaPort.
Set MIDSCENE_IOS_DEVICE_CLASS_OVERRIDE to configure a device class override module. An explicit iOSDeviceClassOverride passed to the factory takes precedence over the environment variable.
IOSDevice / IOSAgent
When constructing IOSDevice explicitly, call await device.connect() before passing the Device to IOSAgent. Each Device instance belongs to a single Agent.
Configuration options
Agent options
Accepts all shared Agent options, plus the following platform option:
appNameMapping?: Record<string, string>— Maps friendly app names to iOS bundle IDs so you can reference apps by name inlaunch(),terminate(), or natural-language prompts. User-provided mappings take precedence over built-in defaults.
Device options
wdaPort?: number— WebDriverAgent server port. Default:8100.wdaHost?: string— WebDriverAgent server host. Default:'localhost'.wdaBaseUrl?: string— Full HTTP(S) base URL for the WDA API (including any gateway path prefix). Cannot be combined withwdaHostorwdaPort.iOSDeviceClassOverride?: string— Custom npm module path used to replace the defaultIOSDeviceimplementation when callingagentFromWebDriverAgent()or running the iOS Playground. The module must export anIOSDeviceclass or a default class.sessionId?: string— Existing WebDriverAgent session ID to reuse. When provided, Midscene skips creating a new WDA session, and detaches from the external session during cleanup instead of deleting it.wdaMjpegPort?: number— WDA MJPEG server port for real-time screen streaming. Default:9100.wdaMjpegUrl?: string— Full HTTP(S) MJPEG stream URL (including any gateway path or query string). Cannot be combined withwdaMjpegPort.wdaMjpegFrameSource?: { enabled?: boolean }— Whether to use WDA's MJPEG stream as the continuous frame source foragent.startObserving(). Disabled by default; when disabled, observers fall back to sequentialscreenshotBase64()calls.autoDismissKeyboard?: boolean— Whether to automatically dismiss the on-screen keyboard after text input. Default:true.keyboardTypeDelay?: number— Delay in milliseconds between keystrokes (must be a finite non-negative number). When set to a positive value,'legacy'input sends characters one Unicode code point at a time through WDA's/wda/keysendpoint. Useful when an input field drops characters during fast typing.inputStrategy?: 'legacy' | 'sequential' | 'bulk'— Default text input strategy forInputactions. Default:'legacy':'sequential': Makes one WDA call per Unicode code point. Use this strategy when setting a positivekeyboardTypeDelay.'bulk': Sends the entire string in a single WDA text call. RequireskeyboardTypeDelayto be omitted or set to0.
customActions?: DeviceAction<any>[]— Custom actions registered for the Agent planner to invoke. Pass this option tonew IOSDevice()oragentFromWebDriverAgent(); see Integrate with any interface for details.
Platform methods
launch()
Open a web URL, launch a native app, or trigger a custom URL scheme.
target: string— Web URL, app bundle ID, custom URL scheme (such astel:ormailto:), or app name. Iftargetmatches a key inappNameMapping, Midscene resolves it to the mapped bundle ID; otherwise, it launchestargetas provided.
terminate()
Terminate (close) a running iOS app by its bundle ID.
bundleId: string— Bundle ID of the app to terminate (such ascom.apple.Preferences) or an app name registered inappNameMapping.
runWdaRequest()
Send raw requests to WebDriverAgent REST endpoints when you need low-level control.
params.method— HTTP method:'GET','POST','DELETE', or'PUT'.params.endpoint— WebDriverAgent endpoint path.params.data— Optional JSON request body.
When calling device.runWdaRequest() directly on an IOSDevice instance, use the positional signature: runWdaRequest(method, endpoint, data?).
System navigation
agent.home(): Promise<void>— Return to the Home screen.agent.appSwitcher(): Promise<void>— Open the app switcher.
device.hideKeyboard()
Dismisses the on-screen keyboard and returns whether it was hidden. When called explicitly, a failed WDA request throws an error.
By default (autoDismissKeyboard: true), after entering text, Midscene attempts to locate the standard iOS keyboard accessory toolbar, tap its dismiss button, and wait until WebDriverAgent confirms that the keyboard is hidden. Some keyboards (such as the iPhone number pad) do not include a dismiss button. If the toolbar cannot be safely identified, the keyboard remains visible, or the dismissal request fails, Midscene logs a warning instead of failing the text input step.
When an Enter, Return, or Tab key action immediately follows an auto-dismissed input, Midscene restores focus to that input field once before sending the key. Any intervening pointer, touch, system, custom, or text-input action clears the pending focus target.
Custom input accessory toolbars defined by an app may contain business buttons such as Save or Submit. To avoid accidental taps, Midscene skips toolbars that do not match the standard iOS layout (navigation controls on the left, dismiss button on the right). If your app uses a custom toolbar, set autoDismissKeyboard: false and call hideKeyboard() explicitly with the dismiss control's accessibility name.
Lifecycle
Calling agent.destroy() waits for pending operations to complete, calls the underlying Device's destroy(), and finalizes the execution report. Do not share a single Device instance across multiple Agents or reuse a Device after cleanup.
On iOS, device.destroy() stops the MJPEG frame source, deletes the WDA session created by Midscene, and stops the WDA manager (an external session passed via sessionId is detached rather than deleted). Any Device cleanup errors are logged.
Troubleshooting
How do I customize the WebDriverAgent port and host?
Pass wdaPort and wdaHost to agentFromWebDriverAgent() or the IOSDevice constructor:
For physical or remote devices, make sure port forwarding is set up accordingly:
If WebDriverAgent is exposed behind a gateway with a path prefix, specify the full API base URL using wdaBaseUrl instead:
Midscene appends /status, /session, and session command paths to this base URL. Use either wdaBaseUrl or wdaHost / wdaPort—combining them throws an error.
Note that wdaBaseUrl only configures WDA API requests; by default, the MJPEG screen stream still connects to http://localhost:9100. If your gateway also proxies the MJPEG stream, configure wdaMjpegUrl separately:
wdaMjpegUrl must be a full HTTP(S) URL (with its own host, port, path, and query string; embedded credentials and URL fragments are rejected) and cannot be combined with wdaMjpegPort. For local port forwarding, leave wdaMjpegUrl unset and configure wdaMjpegPort (default 9100). If the MJPEG stream is unavailable, Playground automatically falls back to screenshot polling.

