# Difference Between Local and Remote Operators in UI-TARS Desktop: Implementation Guide

> Understand the difference between local and remote operators in UI-TARS Desktop. Learn how each manages browser instances for efficient UI testing.

- Repository: [Bytedance Inc./UI-TARS-desktop](https://github.com/bytedance/UI-TARS-desktop)
- Tags: how-to-guide
- Published: 2026-05-10

---

**UI-TARS Desktop distinguishes between local and remote operators by process ownership—LocalBrowserOperator spawns and manages new browser instances locally, while RemoteBrowserOperator attaches to existing browsers via Chrome DevTools Protocol without managing the underlying process.**

The bytedance/UI-TARS-desktop repository abstracts browser automation through the `BrowserOperator` base class, providing two concrete implementations tailored to different automation scenarios. Understanding the difference between local and remote operators in UI-TARS Desktop enables developers to choose between isolated testing environments and integration with existing browser sessions.

## Architectural Overview

Both operator types extend the abstract `BrowserOperator` class defined in [`packages/ui-tars/operators/browser-operator/src/browser-operator.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/operators/browser-operator/src/browser-operator.ts), exposing identical high-level APIs for actions like `click()`, `type()`, and `screenshot()`. The critical distinction lies in how each implementation establishes the browser connection and manages the process lifecycle.

- **LocalBrowserOperator** creates fresh browser processes using locally installed Chrome or Edge binaries discovered at runtime.
- **RemoteBrowserOperator** connects to already-running browser instances via CDP endpoints, functioning as a singleton to share connections across the application.

## LocalBrowserOperator: Launching Fresh Browser Instances

The `LocalBrowserOperator` implementation in [`multimodal/gui-agent/operator-browser/src/LocalBrowserOperator.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/multimodal/gui-agent/operator-browser/src/LocalBrowserOperator.ts) handles complete browser lifecycle management from discovery to termination.

### Browser Discovery and Launch

When initializing a local operator, the code constructs a `BrowserFinder` to locate installed browser executables, then calls `LocalBrowser.launch()` with the discovered path and browser type. According to the source at lines 29-56, this process:

1. Detects Chrome, Edge, or other supported browsers on the host machine.
2. Spawns a new process with the specified executable path.
3. Optionally opens a default search-engine page if configured in the constructor.

### Lifecycle Ownership

Local operators maintain full control over the browser process. You can close, restart, or kill the browser instance through the operator interface, making this approach ideal for automated testing scenarios requiring clean, isolated environments.

```typescript
import { LocalBrowserOperator } from '@gui-agent/operator-browser';

async function runLocalAutomation() {
  // Create operator with optional search engine startup
  const operator = new LocalBrowserOperator({
    searchEngine: 'google',
    highlightClickableElements: true,
  });

  await operator.initialize();  // Launches fresh browser process
  await operator.goto('https://example.com');
  await operator.screenshot('capture.png');
  await operator.close();       // Terminates the browser process
}

```

*Key implementation:* The constructor and initialization logic ([`LocalBrowserOperator.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/LocalBrowserOperator.ts) lines 11-68) demonstrates how the operator wraps the local browser instance and manages its execution context.

## RemoteBrowserOperator: Attaching to Existing CDP Sessions

The `RemoteBrowserOperator` class defined in [`packages/ui-tars/operators/browser-operator/src/browser-operator.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/operators/browser-operator/src/browser-operator.ts) (lines 815-843) takes a fundamentally different approach by connecting to browsers already running elsewhere.

### Singleton Connection Pattern

Unlike local operators that instantiate fresh objects, `RemoteBrowserOperator` implements a singleton pattern via `RemoteBrowserOperator.getInstance(cdpUrl)`. This ensures multiple application components share the same CDP connection without creating duplicate attachments, as seen in the desktop entry point at [`apps/ui-tars/src/main/remote/operators.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/apps/ui-tars/src/main/remote/operators.ts).

### CDP Endpoint Requirements

Remote operators require callers to supply a valid Chrome DevTools Protocol URL (e.g., `http://localhost:9222/json/version`). The operator creates a `RemoteBrowser` wrapper around this existing connection rather than spawning a new process. As implemented in the source code, this strategy:

- Does not manage the remote browser process lifecycle.
- Does not open default pages or search engines.
- Attaches to whatever pages and tabs currently exist in the target browser.

```typescript
import { RemoteBrowserOperator } from '@gui-agent/operator-browser';

async function attachToRemoteBrowser() {
  // Connect to Chrome started with --remote-debugging-port=9222
  const cdpUrl = 'http://localhost:9222/json/version';
  
  // Obtain singleton instance—no new process created
  const operator = await RemoteBrowserOperator.getInstance(cdpUrl);
  
  await operator.initialize();
  const pages = await operator.getPages();  // Access existing tabs
  await operator.click('#submit-button');
  const png = await operator.screenshot('result.png');
  // Browser process remains running after operator closes
}

```

*Key implementation:* The singleton creation and CDP attachment logic resides in [`browser-operator.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/browser-operator.ts) lines 815-843, showing how the operator wraps the remote debugging connection.

## Implementation Differences Compared

| Capability | LocalBrowserOperator | RemoteBrowserOperator |
|---|---|---|
| **Process Control** | Owns browser lifecycle—can launch and terminate | Attaches only—no process management |
| **Instantiation** | `new LocalBrowserOperator(config)` | `RemoteBrowserOperator.getInstance(cdpUrl)` |
| **Browser Discovery** | Uses `BrowserFinder` to locate local installs | Requires explicit CDP URL parameter |
| **Session State** | Fresh profile with optional search-engine page | Existing tabs and user session |
| **Architecture** | Multiple independent instances allowed | Singleton pattern ensures shared connection |
| **Typical Use** | CI/CD pipelines, headless automation, testing | Debugging existing sessions, user-driven automation |

## When to Use Each Operator

Choose **LocalBrowserOperator** when you need isolated, reproducible browser environments for automated testing or when running UI-TARS Desktop in headless server environments where browser processes must be programmatically controlled according to the specific automation schedule.

Choose **RemoteBrowserOperator** when integrating with user-driven Chrome sessions, connecting to browsers in Docker containers exposing CDP ports, or when debugging requires preserving existing browser state and cookies. The desktop application entry point in [`apps/ui-tars/src/main/remote/operators.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/apps/ui-tars/src/main/remote/operators.ts) demonstrates production usage of the remote operator for attaching to existing user sessions.

## Summary

- **Local operators** create and manage fresh browser processes using locally installed executables, offering complete lifecycle control but requiring system resources for new instances.
- **Remote operators** connect to existing browsers via CDP URLs using a singleton pattern, enabling integration with running sessions without process management responsibilities.
- Both operators share the same `BrowserOperator` base API in [`packages/ui-tars/operators/browser-operator/src/browser-operator.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/operators/browser-operator/src/browser-operator.ts), allowing seamless switching between local and remote strategies without changing automation logic.
- Local implementation resides in [`multimodal/gui-agent/operator-browser/src/LocalBrowserOperator.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/multimodal/gui-agent/operator-browser/src/LocalBrowserOperator.ts), while remote logic is defined in [`packages/ui-tars/operators/browser-operator/src/browser-operator.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/packages/ui-tars/operators/browser-operator/src/browser-operator.ts).

## Frequently Asked Questions

### Can I run multiple RemoteBrowserOperator instances simultaneously?

No. `RemoteBrowserOperator` implements a singleton pattern via `getInstance(cdpUrl)` specifically to prevent multiple connections to the same CDP endpoint. If you need to connect to different remote browsers simultaneously, you must use different CDP URLs, as each unique endpoint maintains its own singleton instance according to the implementation in [`browser-operator.ts`](https://github.com/bytedance/UI-TARS-desktop/blob/main/browser-operator.ts).

### Does LocalBrowserOperator support headless mode?

Yes. The `LocalBrowserOperator` passes configuration options through to `LocalBrowser.launch()`, which supports standard Puppeteer-compatible headless flags. You can specify headless behavior in the constructor options, allowing the operator to spawn browsers without visible UI for server-side automation tasks.

### What happens if the remote browser closes while using RemoteBrowserOperator?

Since `RemoteBrowserOperator` does not manage the browser process, it will lose connection and subsequent operations will fail with CDP connection errors. Unlike local operators that can restart their managed process, remote operators require you to manually restart the external browser and obtain a new CDP URL before reconnecting.

### Are both operators available in the same npm package?

Yes. Both `LocalBrowserOperator` and `RemoteBrowserOperator` are typically exported from `@gui-agent/operator-browser` (or the appropriate package within the monorepo), allowing you to import either implementation based on your runtime requirements while maintaining the same interface for browser automation tasks.