This page compares InitialForce's snoopwpf fork (the one publishing InitialForce.SnoopAgent)
against seven other tools that inspect or automate WPF applications. The goal is an honest
picture: every alternative does something well; the right tool depends on the job.
When a WPF application behaves unexpectedly, there are two distinct problems an engineer might be trying to solve. The first is inspection: understanding why the UI looks or behaves the way it does — which property value is driving a layout, what the binding chain resolves to, what resource dictionary entry wins a key lookup, which trigger just fired. The second is automation: driving the application programmatically to test workflows or verify state changes across a sequence of interactions.
Most tools in this space address automation, not inspection. They sit on top of the Windows UI Automation (UIA) API, which exposes a subset of control state — the names, types, bounding rectangles, and a fixed set of control patterns that Windows standardizes across all UI frameworks. UIA is sufficient for driving an application. It is not sufficient for answering questions like "why is this TextBox blank?" or "which resource dictionary is supplying this brush and is it being shadowed by a closer entry?"
SnoopWPF.Agent (this fork) adds an MCP-native surface to the Snoop inspection engine, making inspection-level answers accessible to AI agents without requiring human interaction with the Snoop GUI. This comparison page exists to help you decide when that capability matters and when a simpler tool serves better.
- The TL;DR table gives a four-dimension summary per alternative.
- What each alternative does well describes each tool fairly, with links.
- The full capability matrix covers ~20 features with footnoted qualifications.
- Honest weaknesses lists five areas where a different tool wins.
- Picking the right tool maps common scenarios to recommendations.
- Citations records the source and verification date for each maintenance status claim.
| Alternative | Introspection depth | Attach friction | Mutability | MCP native | Verdict |
|---|---|---|---|---|---|
| Upstream Snoop WPF | ✅ Full WPF tree | ❌ | Best human-facing inspector; no agent API | ||
| FlaUI | ✅ Zero injection | ❌ | Solid cross-framework automation; no binding-level insight | ||
| Raw UIA3 (COM) | ✅ Zero injection | ❌ | Maximum OS compatibility; verbose COM surface | ||
| WinAppDriver | ❌ | Archived; do not start new projects on it | |||
| Appium Windows Driver | ❌ | Active successor to WinAppDriver; mobile-centric workflow | |||
| Playwright | ❌ No native WPF | ✅ Zero injection (web/Electron only) | ✅ Full browser | ❌ | Wrong layer for pure WPF apps |
| TestStack/White | ✅ Zero injection | ❌ | Archived; use FlaUI instead | ||
| snoopwpf (this fork) | ✅ Visual + logical + UIA tree; binding chains; DataContext; triggers | ✅ DP mutation via SetCurrentValue | ✅ | Only tool with native MCP surface and binding-chain resolution |
snoopwpf/snoopwpf — Latest release: v6.0.0, May 2025
The canonical WPF inspector. Upstream Snoop provides the most complete human-operated GUI for examining the visual tree, live property values, and binding errors — with a polished interface that lets developers navigate large trees interactively. Trigger enumeration, resource inspection, and binding-error highlighting are all well-integrated into the GUI, and the project is actively maintained by a community of WPF practitioners. Version 6.0 added a revamped diagnostics panel and improved DataTemplate support. It is the right choice when a human developer needs to debug a live app manually without writing any code. The InitialForce fork derives from this codebase and adds an MCP-over-stdio transport layer on top of the same inspection engine — so the two are broadly equivalent in inspection depth, but only the fork exposes that depth programmatically.
FlaUIInc/FlaUI — Latest release: v4.0.0, June 2025
FlaUI is the most actively maintained UIA wrapper for .NET. It covers WPF, WinForms, WinUI 3,
and Win32 dialogs through a single consistent API, making it the practical choice whenever a
test suite needs to cross UI-framework boundaries. Its event model (AddAutomationEventHandler)
delivers real push notifications from the OS automation framework, so a test harness can react
to structural changes — element added, element removed, property changed — without any polling
loop. This push model is genuinely superior to polling for event-driven architectures. The
experimental FlaUI.WebDriver
shim (February 2026) extends FlaUI with a W3C WebDriver endpoint, making it compatible with any
Selenium-speaking test runner. FlaUI requires zero injection and attaches to any running process
through the public UIA COM interfaces, which means it works in environments where DLL injection
is prohibited by policy. Its key limitation for WPF-specific work is that it sees only the UIA
automation tree, not the WPF visual or logical tree — so DP properties, binding expressions,
DataContext objects, and resource dictionaries are all opaque to it.
UI Automation — Microsoft Learn
The OS-level API that FlaUI, WinAppDriver, and Appium all sit on top of. Using it directly gives
maximum control over automation event subscriptions, property filtering, and custom control
patterns — with no additional dependencies beyond the Windows SDK. It is always current because
it is an OS API, not a versioned package: any process that implements IUIAutomationProvider is
automatically visible. This makes it the correct foundation for long-lived system tooling where
a third-party dependency chain is a liability. It is also the only way to register custom
control patterns or extend the automation property set beyond what a wrapper library exposes.
The cost is verbosity: identifying an element requires navigating a tree of IUIAutomationElement
COM objects, and every waiter or retry must be implemented by the caller. There is no built-in
concept of a locator strategy with fallbacks, a polling waiter with a timeout, or a screenshot
crop by element bounds.
microsoft/WinAppDriver — Latest release: v1.2.1, 2020
Microsoft's Selenium-over-UIA bridge. WinAppDriver exposed WPF, WinForms, and UWP apps through the W3C WebDriver protocol, letting teams reuse Selenium tooling for desktop automation. Its chief strength was broad ecosystem compatibility: any language with a Selenium client library could drive Windows apps, and the wire protocol was already well-understood by test infrastructure teams that had invested in Selenium. It also enabled parallel test execution via the standard WebDriver grid mechanism. However, the project has had no new commits since 2020 and is effectively unmaintained — open issues related to Windows 11 compatibility and modern .NET targets remain unresolved. Do not start new projects on WinAppDriver. Existing suites should plan migration to Appium Windows Driver, which is a largely compatible drop-in for the WebDriver surface while adding ongoing maintenance.
appium/appium-windows-driver — Latest release: v3.x, 2025
The active, community-maintained successor to WinAppDriver under the Appium 3 umbrella. It tunnels through WinAppDriver under the hood but receives ongoing maintenance, Appium 3 compatibility, and cross-platform client support. Teams that already invest in Appium for mobile testing (iOS, Android) can extend that infrastructure to Windows desktop with minimal additional tooling — the same Appium server, the same client libraries, the same CI configuration patterns. This platform convergence is a genuine operational advantage for organizations running large heterogeneous test fleets. The WebDriver wire protocol is the same as WinAppDriver's, so the UIA-level capability ceiling is unchanged: inspection is limited to what UIA exposes, and property mutation goes through UIA patterns rather than the WPF DP system. Setup requires running both the Appium server and the Windows Driver, adding more moving parts than a pure .NET solution like FlaUI.
microsoft/playwright — Latest release: current, ongoing
Playwright is the gold standard for browser and Electron automation. It offers reliable cross-browser coverage (Chromium, Firefox, WebKit), rich locator strategies backed by the Accessibility tree and CSS/text selectors, built-in network mocking and request interception, and first-class tracing and video capture. For Electron-based desktop applications, Playwright is the correct tool — the same APIs that automate a Chrome tab also work against an Electron window with full DevTools protocol access. For hybrid teams building web plus Electron plus a WPF admin tool, Playwright handles the web and Electron portions better than any alternative in this list, while a tool like FlaUI or snoopwpf covers the WPF portion. For pure WPF apps, Playwright has no applicable code path: WPF windows are not rendered in a browser engine and Playwright's CDP (Chrome DevTools Protocol) client cannot attach to them. Including Playwright in this comparison is intentional — it is often the answer to the question "can Playwright handle this?" and the correct answer for WPF is no, redirect to FlaUI or this fork.
TestStack/White — archived ~2016
White was the dominant .NET UIA wrapper before FlaUI emerged. It covered WPF, WinForms, and
Win32 through a fluent API that was ahead of its time in 2008: element finders with retry logic,
a typed control hierarchy (Button, TextBox, ListBox) that shielded tests from raw
IUIAutomationElement COM, and an Application abstraction that managed process lifecycle.
Those patterns are directly reflected in FlaUI's design, which can be thought of as White rebuilt
on a modern .NET foundation with active maintenance. Although White is archived, a large number
of legacy test suites still run on it because the API surface is stable and the .NET Framework
target is compatible. For any new project or major investment in expanding an existing suite,
FlaUI is the direct functional successor and the correct choice. White is included in this
comparison because engineers working on applications that already have White-based tests will
encounter it, and the migration path to FlaUI is well-understood.
Symbols: ✅ full support /
| Feature | snoopwpf (this fork) | Upstream Snoop | FlaUI | Raw UIA3 | WinAppDriver | Appium Win | Playwright | White |
|---|---|---|---|---|---|---|---|---|
| Visual tree | ✅ | ✅ | ❌ | |||||
| Logical tree | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Automation tree (UIA) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ |
| Property read | ✅ | ✅ | ❌ | |||||
| Property MUTATE | ✅ [3] | ❌ | ||||||
| Binding path resolve | ✅ | ✅ [4] | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| DataContext inspect | ✅ | ✅ [4] | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Style/trigger enum | ✅ | ✅ [4] | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Resource lookup (with shadow) | ✅ | ✅ [4] | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Behavior enum (Blend) | ✅ | ✅ [4] | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Screenshot (element) | ✅ | ❌ | ❌ | ✅ | ❌ | |||
| Screenshot (window) | ✅ | ✅ | ❌ | ✅ | ❌ | |||
| Screenshot as blob ref (no context bloat) | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Keyboard input | ✅ [7] | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Click / invoke | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| List virtualization handling | ✅ [8] | ❌ | ❌ | |||||
| Hot-reload friendly | ✅ [11] | ✅ | ✅ | ✅ | ✅ | ❌ | ||
| MCP native | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Protocol type | MCP stdio/pipe | None (GUI) | .NET API | COM API | WebDriver | WebDriver | WebDriver | .NET API |
| In-proc vs out-of-proc | Both [10] | Out (GUI) | Out | Out | Out | Out | Out | Out |
| Last release year | 2026 | 2025 | 2025 | N/A | 2020 | 2025 | 2026 | 2016 |
| Status | Active | Active | Active | OS built-in | Archived | Active | Active | Archived |
Footnotes
- UIA tree only — does not distinguish WPF visual tree from logical tree. WPF-internal
elements that do not override
UIElement.CreateAutomationPeer()are invisible to UIA-based tools, including all elements whose AutomationPeer returnsnull. This typically includes decorators, adorners, and non-interactive panels that WPF renders visually but does not expose for accessibility purposes. - Only exposes UIA AutomationElement properties (Name, ControlType, BoundingRectangle,
IsEnabled, etc.) plus the values exposed through specific control patterns (Value via
ValuePattern, selection state viaSelectionPattern, etc.). Arbitrary DependencyProperty values — background brushes, font sizes, margin/padding, binding expressions, DataContext types — are not accessible. - DP mutation via
DependencyObject.SetCurrentValue— preserves existing TwoWay binding expressions on the target property. RequiresEnableMutation = trueinSnoopAgentOptions. A subset of property types is in the safe-settable list; see the security model for details. See also honest weaknesses for the limitations of DP-layer mutation vs. UIA-pattern mutation. - Available in the Snoop GUI only; not accessible programmatically or via any API. The GUI does expose these features in a polished, interactive form — this is Snoop's primary use case and it excels at it. The limitation is that an AI agent or automated test harness cannot call into the Snoop GUI to retrieve these values programmatically.
- Via UIA patterns only —
ValuePattern.SetValuefor text controls,TogglePattern.Togglefor checkboxes,SelectionItemPattern.Selectfor list items. These patterns go through the control's own UIA provider implementation and do NOT callSetCurrentValue. On most WPF controls,ValuePattern.SetValuewill clear an active TwoWay binding on the target DependencyProperty because it sets the value at a layer below the WPF binding system. - Via OS-level
BitBlt/Graphics.CopyFromScreenclipped to the element's bounding rectangle. Requires the element to be on-screen and unobscured. Does not handle DPI scaling on non-primary monitors without additional code. May capture overlapping windows if the element is partially covered. - Via
wpf_set_text_value(TextBox/PasswordBox/RichTextBox),wpf_set_check_state(CheckBox/RadioButton), andwpf_set_slider_value(Slider/RangeBase) — all implemented withSetCurrentValueat the DP layer. Raw Win32 keystroke simulation (SendInput,PostMessage WM_KEYDOWN) is not provided; use FlaUI'sKeyboardclass for that need. - snoopwpf handles virtualization via dedicated tools:
wpf_select_itemaccepts a zero-based integeridentifier(e.g."500") and callsItemContainerGenerator.ContainerFromIndexfollowed byBringIntoViewto materialize the virtualized container, then sets selection viaSetCurrentValueonSelector.SelectedItemProperty;wpf_select_item_by_scrollforces realization by scrolling to the target index before selecting (preferred when the caller has only an index and needs explicit scroll control);wpf_select_item_by_indexis the explicit integer-index alias when you want to avoid the string-identifier form. Inspection-without- selection of virtualized items (reading properties from an off-screen item without changing selection) is not yet supported — see honest weaknesses. - UIA cannot enumerate items that have not been realized by the
VirtualizingStackPanel(or other virtualizing panel). The automation tree for a 10,000-itemListBoxreports only the currently visible item containers. Workarounds involve programmatic scrolling to force realization, but these are fragile under re-virtualization. - NuGet co-located mode is in-proc (agent runs in the same process as the app, shares the
WPF Dispatcher). Injection mode and brokered mode are out-of-proc (the
snoop-mcp.exeinjector loads into the target process address space, but the MCP server transport boundary is a named pipe to the external host). snoopwpf supports three brokered sub-modes:StartBrokered(target=client, broker=server, stdin token),StartBrokeredClient(legacy alias), andStartBrokeredServerAsync(target=server, broker=client, manifest-based). Mode-dependent features — hot-reload friendliness, source-code requirement, third-party-app support — vary by sub-mode; see footnote [11] and the architecture docs for details. - Hot-reload behavior is mode-dependent. In NuGet co-located mode, a
dotnet watchrebuild terminates and restarts the host process, requiring agent reconnection. In brokered mode (StartBrokeredServerAsync), the broker process is separate from the target; the broker session survives target restarts and can reattach automatically, giving a warm-attach advantage over co-located mode. This makes brokered mode the preferred attach strategy for development workflows where the app is rebuilt frequently.
Five places where a competing tool wins or partially wins over snoopwpf.
FlaUI and raw UIA3 attach to any running Windows process through the published OS automation
APIs — no DLL injection, no process modification. Snoopwpf's external (injection) mode requires
injecting snoop-mcp.exe into the target process, which demands that the process be owned by
the current user and that certain anti-tamper mechanisms are absent. In high-security or
sandboxed environments, injection may be blocked outright. The NuGet co-located mode avoids
injection entirely but requires a recompile.
Snoopwpf's inspection engine is built on WPF internals: DependencyObject, FrameworkElement,
VisualTreeHelper, and the WPF resource system. None of these APIs exist in WinForms or WinUI 3.
An application with mixed UI technology — for example a WPF shell hosting legacy WinForms
panels via WindowsFormsHost, or a WinUI 3 migration in progress — cannot have the non-WPF
portions inspected by snoopwpf. FlaUI and raw UIA3 operate at the OS abstraction layer and
see all frameworks uniformly.
The brokered mode, which allows a separate broker process to inject into an already-running app
and expose it over MCP, has some lifecycle tooling gaps. Certain broker-specific commands
(for example mc_wait_for_recording and the full encoding-pipeline polling path required for
multi-step async state machines) are deferred to a future milestone. As documented in
shim-retained-flaui.md, two scenario families in the MotionCatalyst
integration continue to use FlaUI fallbacks because the shim cannot yet cover their specific
polling patterns. Applications that rely heavily on broker lifecycle coordination — particularly
those with multi-step async recording or encoding pipelines — should review that document before
committing to the brokered path. The active FlaUI fallback count is tracked against the M2 gate
(threshold: 5 active families) and is currently at 2, indicating the gap is bounded and
narrowing.
wpf_poll_changes returns structural deltas by comparing tree snapshots — the agent must call
it repeatedly to detect changes, and the minimum observable latency is one poll interval
(approximately 80–100 ms in practice). FlaUI's AddAutomationEventHandler registers an
OS-level callback that fires synchronously when an element is added, removed, or has a property
change event raised by the WPF automation peer. The difference matters for test architectures
where the harness must react immediately to UI changes — for example, a test that asserts a
spinner disappears within 200 ms of an operation completing, or a monitor that must log every
structural change in the tree in real time. FlaUI's push model has lower latency and does not
consume CPU cycles between events. Snoopwpf's wpf_wait_for_property tool is a convenience
wrapper that polls internally, which reduces the polling burden on the caller but does not
eliminate it.
wpf_set_property and the L0 mutation tools (wpf_set_text_value, wpf_set_check_state,
etc.) use DependencyObject.SetCurrentValue, which preserves active TwoWay bindings and
triggers DP change notifications — but it does not simulate physical user input. Some
applications validate or transform input only in response to TextBox.PreviewTextInput,
KeyDown, or focus-change events, which are not fired by SetCurrentValue. UIA-based tools
(ValuePattern.SetValue in FlaUI and WinAppDriver) go through the control's own input
processing and raise these events, more closely reproducing what a real user does. If your
test coverage depends on event-driven validation that runs only on physical-input events,
prefer UIA-pattern–based mutation over DP-layer mutation.
The table below maps five common scenarios to a tool recommendation with a brief rationale. "Pick" is a primary recommendation; in mixed scenarios, combining two tools is sometimes the right answer.
| Scenario | Pick | Rationale |
|---|---|---|
| I own the source; CI test harness | snoopwpf NuGet mode | Zero injection, in-process MCP server, full binding-chain diagnostics, CI-friendly stdio transport. Add SnoopAgent.StartCoLocated() behind an env-var flag so it only runs in CI and dev builds. |
| Third-party legacy WPF app; debug once | snoopwpf injection OR FlaUI | Injection gives deeper insight (binding chains, DataContext, triggers); FlaUI is the safer choice if the process is owned by a different user account, runs elevated, or has anti-tamper tooling active. |
| Cross-framework automation (WPF + WinForms + Electron) | FlaUI + Playwright | FlaUI covers WPF/WinForms/WinUI3 through a single .NET API; Playwright covers Electron and browser targets. Neither covers the other's domain; use both in the same test suite if the application spans frameworks. |
| Push-event–driven watcher | FlaUI (AddAutomationEventHandler) |
OS-level push events fire synchronously without polling overhead. Suitable for harnesses that react to UI state changes at sub-100 ms latency. |
| Runtime binding-chain debugging | snoopwpf | The only tool that walks multi-step binding paths with per-segment live values, surfaces DataContext runtime types, identifies shadowed resource entries, and enumerates style and ControlTemplate triggers — all over a structured MCP API. |
Several real applications require a pragmatic combination. A WPF host with embedded WinForms
panels (via WindowsFormsHost) can use snoopwpf for the WPF portions and FlaUI for the WinForms
panels — both attach to the same process simultaneously without conflict. An application under
active development that uses both dotnet watch hot reload and an AI coding agent can run in
NuGet mode during development (where the agent drives binding diagnostics) and FlaUI-based
SpecFlow scenarios in CI (where the test suite verifies end-to-end workflows). These modes are
complementary, not exclusive.
SnoopWPF.Agent is an inspection and light-mutation tool, not a general-purpose UI test runner.
It deliberately omits raw input simulation (mouse movement, physical keystrokes via SendInput),
cross-process coordination primitives (grid execution, parallel test sessions), and built-in
assertion libraries. For production test suite infrastructure — test discovery, parallel
execution, reporting, CI integration — use a testing framework (xUnit, NUnit, SpecFlow) with
FlaUI or Appium as the driver, optionally adding snoopwpf NuGet mode for binding-level
assertions where they add value over UIA-based checks.
The recommended pattern for teams building out a WPF test suite from scratch is:
- FlaUI (or Appium) as the primary driver for workflow-level tests.
- snoopwpf NuGet mode (conditional on
#if DEBUGor an env var) for diagnostic sessions and binding-chain assertions during development. - Upstream Snoop GUI for ad-hoc interactive debugging by developers.
This layering gives each tool the scope it is optimized for.
The claims in this document were verified against the tool repositories and documentation in April 2026. Strong claims — particularly "only tool that" — are backed by a corresponding row in the capability matrix. Where a claim involves a nuance or a partial capability, a footnote explains the scope.
Maintenance status is determined by the most recent tagged release on the respective GitHub repository, not by commit frequency alone, since some mature libraries release infrequently but remain correct and well-maintained. The WinAppDriver "archived" classification reflects the combination of no tagged release since 2020, open GitHub issues marked "no activity", and Microsoft's own guidance directing users to Appium Windows Driver.
If you find a factual error — for example if a tool you use has added a capability listed as ❌ — please open an issue against InitialForce/snoopwpf with a link to the relevant documentation or release notes.
Versioning note: Alternative version numbers (FlaUI 4.x June 2025, upstream Snoop 6.0.0 May 2025, WinAppDriver 1.2.1 2020, Appium Windows Driver v3.x 2025) reflect the package metadata at docs-write time. Check the linked GitHub release pages for current versions. WinAppDriver has had no commits since 2020 as of this writing; that characterization is time-stable, but other projects may have released newer versions.
Maintenance status and release dates used in the matrix above are sourced from the GitHub releases pages listed here. All dates were verified in April 2026.
| Tool | Repository | Releases page | Last release |
|---|---|---|---|
| Upstream Snoop WPF | snoopwpf/snoopwpf | Releases | v6.0.0 — May 2025 |
| FlaUI | FlaUIInc/FlaUI | Releases | v4.0.0 — June 2025 |
| FlaUI.WebDriver | FlaUIInc/FlaUI | Same repo | Experimental — February 2026 |
| Raw UIA3 | Windows Automation | OS built-in | N/A — always current |
| WinAppDriver | microsoft/WinAppDriver | Releases | v1.2.1 — 2020 (no further commits) |
| Appium Windows Driver | appium/appium-windows-driver | Releases | v3.x — 2025 |
| Playwright | microsoft/playwright | Releases | Current — ongoing 2026 |
| TestStack/White | TestStack/White | Releases | Archived ~2016 |
| snoopwpf (InitialForce) | InitialForce/snoopwpf | Releases | 2026 (active) |