Skip to main content
On this page

iOS UI Automation on Windows with WebDriverAgent on iPhone

Sign, install and start WebDriverAgent on your iPhone with one command, then tap, swipe, type, find elements by text and take screenshots from scripts, test frameworks or AI agents.

Last updated

For iOS UI automation on Windows, one command, kxdevice test runwda, signs WebDriverAgent (WDA, the UI automation server Appium uses on iPhone), installs it on your phone and starts it. Your scripts, test frameworks and AI agents then use local port 8100 to tap, swipe, type, find elements by their text, read the view hierarchy and take screenshots. It works the same on Linux and macOS, and the iPhone needs iOS 17 or later.

What do I need for iOS UI automation on Windows?

1

Connect your iPhone

The iPhone must trust this computer and have Developer Mode turned on. See Device setup. With several iPhones connected, add --udid to choose one.

2

Put a development certificate in the shared certificate folder

WDA is signed with the certificates in KXBUILD_HOME/keychain/. A project's own keychain folder isn't used. Add an Apple Development certificate and a development profile that includes this iPhone.

A wildcard profile with App ID * is easiest. A wildcard profile like com.yourcompany.* also works, and WDA then uses the bundle ID com.yourcompany.WebDriverAgentRunner.xctrunner automatically. If you only have a profile for one app, see below. See how to sign iOS apps on Windows.


How do I start WebDriverAgent on my iPhone?

The first run signs, installs and then starts WDA. Later runs just start it. When WDA is ready, the command prints WebDriverAgent is ready at http://127.0.0.1:8100, and your scripts can use that address. The command keeps running. Press Ctrl-C when you're done.

> kxdevice test runwda

You can also open http://127.0.0.1:8100/status in a browser. If the response contains "ready" : true, WDA is ready.

No wildcard profile? How do I change WDA's bundle ID?

If you don't have a wildcard profile but do have a development profile for another bundle ID that can sign WDA, use --bundle-id to change WDA's bundle ID to that profile's bundle ID.

> kxdevice test runwda --bundle-id com.example.myapp

What options does runwda take?

OptionWhen to use it
--reinstallSign and install again after updating KXBuild, or after changing your certificate or profile
--no-installWDA is already on the iPhone. Start it without checking
--ipa <file>Use a WDA runner you built yourself instead of the bundled one
--bundle-id <ID>Change WDA's bundle ID to this value, then sign and install it. See above
--port <port>Port 8100 on your computer is taken. Pick another, for example --port 8101, and point your scripts at 8101
--no-forwardDon't use a local port. Forward it yourself with kxdevice forward
--udid <UDID>Pick one of several connected iPhones. To drive several at once, give each its own --port
-vShow WDA's own output, for troubleshooting startup

How do I drive WDA from a Python script?

WDA speaks the WebDriver protocol, so any language that can send HTTP requests can drive it. The Python example below opens Settings, finds General by its text, taps it and takes a screenshot. Elements are found by their visible text or accessibility label, so use the text in the language the app is showing.

> pip install requests
import base64, requests WDA = "http://127.0.0.1:8100" # Open the app and get a session r = requests.post(f"{WDA}/session", json={ "capabilities": {"alwaysMatch": {"bundleId": "com.apple.Preferences"}}}) sid = r.json()["sessionId"] # Find an element by its text and tap it r = requests.post(f"{WDA}/session/{sid}/element", json={"using": "accessibility id", "value": "General"}) el = r.json()["value"]["ELEMENT"] requests.post(f"{WDA}/session/{sid}/element/{el}/click") # Take a screenshot png = requests.get(f"{WDA}/screenshot").json()["value"] open("screen.png", "wb").write(base64.b64decode(png)) requests.delete(f"{WDA}/session/{sid}")

Replace the bundleId with your own app's. Common requests are below. Prefix each path with http://127.0.0.1:8100.

To do thisRequest
Check that WDA is readyGET /status
Open an app and create a sessionPOST /session with bundleId in capabilities
Find an element by text or labelPOST /session/<session>/element with using set to accessibility id
Tap an elementPOST /session/<session>/element/<element>/click
Screen size in pointsGET /session/<session>/window/size
View hierarchy, to look up element names and positionsGET /source
Screenshot as a base64-encoded PNGGET /screenshot
Go to the Home ScreenPOST /wda/homescreen
End the sessionDELETE /session/<session>

If you don't know what an element is called, request /source and look for its name or label attribute in the XML. Swiping, long presses, typing and the other requests are the same as in Appium's WebDriverAgent. See the WebDriverAgent project's documentation.

How do I let an AI agent use the iPhone?

Add kxdevice as an MCP server, and AI agents such as Claude Code and Cursor can tap, swipe, type, find elements by text and read the view hierarchy to check their own UI changes. The first time an agent calls one of these tools, kxdevice starts WDA for it, so you don't run runwda yourself. For example, in Claude Code:

> claude mcp add kxdevice -- kxdevice mcp

How do I fix common WDA errors?

ProblemFix
Signing or installing failsCheck that KXBUILD_HOME/keychain/ has a development certificate and a development profile that includes this iPhone. Then run again with --reinstall
The WebDriverAgent component is missingRun kxbuild doctor to install the missing component
It says iOS 17 is requiredWDA only works on iOS 17 or later. Update the iPhone first
Port 8100 is in useStop the earlier runwda or kxdevice forward that is still running, or pick another port with --port 8101 and use 8101 in your scripts
"ready" never appearsUnlock the iPhone first. If that doesn't help, press Ctrl-C and run again with -v to see WDA's output
An element can't be found by its textThe text must match what's on screen exactly, including the language. Request /source to see the element's actual name and label. In your own app, set an accessibilityIdentifier on the element

For startup problems not in the table, rerun runwda with -v to see WDA's own output. Once everything works, the daily loop for iOS UI automation on Windows is simple: run runwda, run your scripts, press Ctrl-C. To debug the app on the device at the same time, see debug iOS apps on iPhone in VS Code.

Frequently asked questions

Which iOS versions does UI automation support?

iPhones on iOS 17 or later. Update older phones first. The iPhone also needs to trust this computer and have Developer Mode turned on.

Do I have to write scripts in Python?

No. WDA speaks the WebDriver protocol, so any language or test framework that can send HTTP requests can drive it. Python is just the example here.

Can I control several iPhones at once?

Yes. Run one runwda per phone, pick each phone with --udid and give each a different --port, such as 8100 and 8101. Each script then talks to its own port.

Does an AI agent need me to run runwda first?

No. Once kxdevice is added as an MCP server, kxdevice starts WDA automatically the first time the agent calls a tool like tap or swipe.

Next steps