WinAppDriver to Appium Migration Guide

WinAppDriver to Appium Migration Guide

Introduction

WinAppDriver was Microsoft’s answer to UI automation for Windows desktop apps. Built on the WebDriver protocol, it allowed developers to write UI tests using familiar tools and languages. However, WinAppDriver is no longer actively maintained, and its limitations—especially around flexibility and community support—have become more apparent over time.

Appium, a widely-used open-source automation framework, now offers a powerful alternative through its Windows driver. It supports the same WebDriver protocol but with more active development, better extensibility, and cross-platform capabilities. For teams looking to future-proof their automation, migrating from WinAppDriver to Appium is a practical and strategic move.

Why Migrate to Appium

Appium is a strong alternative to WinAppDriver, primarily because it’s actively maintained, unlike WinAppDriver, which hasn’t received updates in quite some time. With Appium, you get regular updates, bug fixes, and a thriving community that’s continuously improving the tool.

While Appium’s Windows driver still relies on WinAppDriver under the hood, it provides a more unified and extensible interface. The core functionality and commands—such as locator strategies and element interactions—are very similar to WinAppDriver, so most of your test scripts won’t need to be completely rewritten. Expect some slight syntax changes, like adjustments in method names and session handling, but the transition is relatively smooth.

What Appium adds is extra flexibility. It opens the door to additional Appium-specific commands, better session management, and the ability to use plugins to extend functionality. Plus, Appium integrates more easily into modern development environments, allowing you to install it via npm, script it, and run it in CI/CD pipelines, which is a significant improvement over WinAppDriver’s more rigid setup.

Migrating to Appium is also the first step if you plan to try out our new Appium driver, NovaWindows. We designed it to provide faster and more reliable Windows desktop automation and integrate seamlessly with Appium. So by migrating to Appium first, you’re setting yourself up to easily adopt NovaWindows when you’re ready for it.

Common Prerequisites

In order to start using Appium for desktop automation, first you need to have Node.js installed on your system, as Appium is Node.js based. After you do, you can install appium by running the following command:

npm install -g appium

This will install the Appium package globally on your system. This way you can run the Appium command from anywhere. Before we run it though, we need to install the Appium Windows driver. Starting from version 2, Appium no longer bundles the drivers with itself, but they have to be installed externally, usually with a simple command. To download the Appium interface for WinAppDriver in appium, you run the following command:

appium driver install --source=npm appium-novawindows-driver

You can see the list of other available drivers here: https://appium.io/docs/en/latest/ecosystem/drivers/, including our new NovaWindows driver, that you might want to try after fully migrating to Appium.

After the install is done, simply run the command appium anywhere, and the server should be up and listening for requests.

Migration in JavaScript (WebDriverIO)

If you’re using WebDriverIO, you’re probably using winappdriver service for it. When migrating to Appium, you’ll need to swap it to an appium service. You can do it by running:

npm install @wdio/appium-service --save-dev

The next important thing in changing the capabilities. All non-standard Selenium capabilities have to have the appium: prefix. This is how they should look like inside wdio.conf.js:

...
capabilities: [{
    platformName: 'Windows',
    'appium:app': 'C:\\Path\\To\\App.exe',
    'appium:automationName': 'Windows'
}],
...

WebDriverIO’s framework provides a unified interface for all automation targets, so your locators and methods should remain unchanged.

Migrating in Python

The changes required in Python are relatively simple. Since WinAppDriver uses the outdated Selenium 3 protocol, and Appium uses Selenium 4, we need to upgrade the client libraries. You can do so by running the following command:

pip install --upgrade Appium-Python-Client selenium

This will update Appium and Selenium clients to the latest versions. You may start seeing a lot of errors in the code. Don’t worry, the changes are quite simple. First, the capabilities. In Selenium 3, the desired capabilities are deprecated in favor of Options. For desktop, you will need to import WindowsOptions, and initialize WindowsOptions object, instead of simple dictionary.

Instead of initializing capabilities like this:

desired_caps = {
    'platformName': 'Windows',
    'app': 'C:\\Path\\To\\App.exe'
}

You initialize options like this:

from appium.options.windows import WindowsOptions

opts = WindowsOptions()
opts.app = 'C:\\Path\\To\\App.exe'

# for additional capabilities
opts.set_capability('namespace:key', 'value')

Before:

driver.find_element_by_accessibility_id('AppNameTitle')
driver.find_element_by_class_name('TextBlock')
driver.find_element_by_id('42.333896.3.1')
driver.find_element_by_name('Calculator')
driver.find_element_by_tag_name('Text')
driver.find_element_by_xpath('(//Button)[2]')

After:

from appium.webdriver.common.appiumby import AppiumBy

driver.find_element(by=AppiumBy.ACCESSIBILITY_ID, value='AppNameTitle')
driver.find_element(by=AppiumBy.CLASS_NAME, value='TextBlock')
driver.find_element(by=AppiumBy.ID, value='42.333896.3.1')
driver.find_element(by=AppiumBy.NAME, value='Calculator')
driver.find_element(by=AppiumBy.TAG_NAME, value='Text')
driver.find_element(by=AppiumBy.XPATH, value='(//Button)[2]')

That’s it, you should be good to go, as everything else should be the same!

Migrating in Java

If you’re using WinAppDriver with Java, you’re probably using io.appium.java_client version 7.6.0, since the newer versions are using the updated Selenium 4 protocol, which is incompatible with WinAppDriver. That’s the first thing we have to upgrade when migrating to Appium.

After the changes, there will be some changes in the code that we have to do, starting with initializing the driver and capabilities. Currently, the capabilities probably look something like this:

DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("platformName", "Windows");
capabilities.setCapability("app", "C:\\Path\\To\\App.exe");

This won’t work anymore in the new Appium, since it requires “app” and other appium-specific capabilities to be prefixed with namespace “appium:”. You don’t have to do it manually though, there’s a better way to initialize capabilities, as WindowsOptions:

WindowsOptions options = new WindowsOptions();
options.setApp("C:\\Path\\To\\App.exe");

// for additional capabilities
options.setCapability("namespace:key", "value")

As for the driver, it no longer requires generic parameter, as WindowsElement no longer exists in the new version of the client. Next thing is the element locators. You may have a lot of maps, but you should be able to fix everything with a mass replace. Everything that has been WindowsElement will now be of class WebElement. Here are the rest of the changes:

Before:

driver.findElementByAccessibilityId("AppNameTitle");
driver.findElementByClassName("TextBlock");
driver.findElementById("42.333896.3.1");
driver.findElementByName("Calculator");
driver.findElementByTagName("Text");
driver.findElementByXPath("(//Button)[2]");

After:

import io.appium.java_client.AppiumBy;

driver.findElement(AppiumBy.accessibilityId("AppNameTitle"));
driver.findElement(AppiumBy.className("TextBlock"));
driver.findElement(AppiumBy.id("42.333896.3.1"));
driver.findElement(AppiumBy.name("Calculator"));
driver.findElement(AppiumBy.tagName("Text"));
driver.findElement(AppiumBy.xpath("(//Button)[2]"));

If there any other errors regarding some windows-specific methods that no longer exists, you may have to use the executeScript method, consult the appium-windows-driver repo’s readme for documentation of the platform-specific commands.

Migrating in Ruby

If you’re running WinAppDriver in Ruby, you’re in luck! You probably have to make the least changes to your code, especially if you’re on the latest appium_lib version! Just add the automationName property to your capabilities and you should be good to go!

...
automationName: 'Windows',
...

Migrating in .NET

If you’re using WinAppDriver with C#, you’re using one of the two packages—either Microsoft.WinAppDriver.Appium.WebDriver or Appium.WebDriver with version up to 4.4.5.

// Microsoft.WinAppDriver.Appium.WebDriver
var caps = new DesiredCapabilities();
caps.SetCapability("app", "C:\\Path\\To\\App.exe");

var driver = new WindowsDriver<WindowsElement>(new Uri("http://127.0.0.1:4723"), caps);
// Appium.WebDriver up to version 4
var opts = new AppiumOptions();
opts.AddAdditionalCapability("app", "C:\\Path\\To\\App.exe");

var driver = new WindowsDriver<WindowsElement>(new Uri("http://127.0.0.1:4723"), opts);

Either way, you will need to install the latest version of Appium.WebDriver and remove Microsoft.WinAppDriver.Appium.WebDriver if used. Just like in Java, the generic type is not needed anymore in WindowsDriver as WindowsElement no longer exists, it uses the AppiumElement. This is how you define the new AppiumOptions and WindowsDriver:

var opts = new AppiumOptions
{
    PlatformName = "Windows",
    AutomationName = "Windows",
    App = "C:\\Path\\To\\App.exe",
};

var driver = new WindowsDriver(new Uri("http://127.0.0.1:4723"), caps);

Next thing is the element locators. You may have a lot of maps, but you should be able to fix everything with a mass replace. Everything that has been WindowsElement will now be of type AppiumElement. Here are the rest of the changes:

Before:

driver.FindElementByAccessibilityId("AppNameTitle");
driver.FindElementByClassName("TextBlock");
driver.FindElementById("42.333896.3.1");
driver.FindElementByName("Calculator");
driver.FindElementByTagName("Text");
driver.FindElementByXPath("(//Button)[2]");

After:

driver.FindElement(MobileBy.AccessibilityId("AppNameTitle"));
driver.FindElement(MobileBy.ClassName("TextBlock"));
driver.FindElement(MobileBy.Id("42.333896.3.1"));
driver.FindElement(MobileBy.Name("Calculator"));
driver.FindElement(MobileBy.TagName("Text"));
driver.FindElement(MobileBy.XPath("(//Button)[2]"));

If there any other errors regarding some windows-specific methods that no longer exists, you may have to use the executeScript method, consult the appium-windows-driver repo’s readme for documentation of the platform-specific commands.

Related Articles

AutomationTools, Free Tools

Test Automation Reporting with ReportPortal in .NET Projects

In the next few articles from the Automation Tools Series, I will show you different test automation reporting solutions. Finally, there will be an article comp

Test Automation Reporting with ReportPortal in .NET Projects

AutomationTools, Free Tools

Quick Guide Bitbucket Pipelines on Running Selenium C# Tests

In this article from the series Automation Tools, I am going to guide you on how you can set up a Bitbucket Pipelines job for a Selenium C# project, run your Se

Quick Guide Bitbucket Pipelines on Running Selenium C# Tests

Desktop Automation, Web Automation

Automate Windows Desktop Apps with WebDriver- WinAppDriver C#

In the Desktop Automation Series, you can find invaluable tips and tricks about desktop automation. I will dedicate the next couple of articles on the automatio

Automate Windows Desktop Apps with WebDriver- WinAppDriver C#

AutomationTools, Free Tools

Test Automation Reporting with Allure in .NET Projects

In the next few articles from the Automation Tools Series, I will show you different test automation reporting solutions. Finally, there will be an article comp

Test Automation Reporting with Allure in .NET Projects

AutomationTools, Free Tools, Web Automation

UI Performance Analysis via Selenium WebDriver

The article from the series Automation Tools reviews different approaches to check the UI performance of web apps reusing your existing functional Selenium WebD

UI Performance Analysis via Selenium WebDriver

AutomationTools, Free Tools, Java

Healenium: Self-Healing Library for Selenium-based Automated Tests

In this article, we're going to review a library called Healenium. It is an AI-powered open-source library for improving the stability of Selenium-based tests,

Healenium: Self-Healing Library for Selenium-based Automated Tests
Anton Angelov

About the author

Anton Angelov is Managing Director, Co-Founder, and Chief Test Automation Architect at Automate The Planet — a boutique consulting firm specializing in AI-augmented test automation strategy, implementation, and enablement. He is the creator of BELLATRIX, a cross-platform framework for web, mobile, desktop, and API testing, and the author of 8 bestselling books on test automation. A speaker at 60+ international conferences and researcher in AI-driven testing and LLM-based automation, he has been recognized as QA of the Decade and Webit Changemaker 2025.