Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Open Tauri Remote WebView
A Tauri v2 plugin that exposes your application's UI to any web browser, enabling remote interaction, frontend debugging, and E2E testing using standard web tools.
This project is based on tauri-remote-ui v0.14.0
by DraviaVemal, modified under the MIT license.
All modifications are Copyright (c) 2026 ant-cave.
Fork features: transparent @tauri-apps/api proxy over WebSocket — all
native Tauri APIs (app, window, event, core, etc.) work in the browser
without any import changes. Just add one side-effect import.
Original by DraviaVemal. Enhanced by ant-cave.
Features
| Capability | WebView (IPC) | Browser (WS) |
|---|---|---|
invoke (any command) |
✅ | ✅ |
Event listen / once |
✅ | ✅ |
@tauri-apps/api/app (getName, getVersion, …) |
✅ | ✅ via bridge |
@tauri-apps/api/window (title, size, …) |
✅ | ✅ via bridge |
@tauri-apps/api/event (listen, emit) |
✅ | ✅ via bridge |
Rust emit → browser |
✅ | ✅ via EmitterExt |
| Custom security & origin control | ✅ | ✅ |
Migration from Native Tauri
Migrating an existing Tauri app to use open-tauri-remote-webview requires only a few changes. Most of your frontend code stays exactly the same.
What changes
| Area | Before (native Tauri) | After (remote) |
|---|---|---|
| Rust plugin | — | Add open-tauri-remote-webview crate + .plugin(open_tauri_remote_webview::init()) |
Rust window.emit() |
use tauri::Emitter |
use open_tauri_remote_webview::EmitterExt (same call) |
| Rust start WS server | — | Add app.start_remote_ui(RemoteUiConfig::default()) in setup |
| Frontend install | — | npm install open-tauri-remote-webview |
| Frontend import | import "..." from "@tauri-apps/api" |
No change — add ONE line: import "open-tauri-remote-webview/bridge-init" at entry |
vite.config.ts |
— | Add /remote_ui_ws proxy to dev server |
if (isTauri()) guards |
Common pattern | Remove them — bridge makes everything work everywhere |
Step-by-step
- Rust:
cargo add open-tauri-remote-webview, then register the plugin and start the WS server insetup(see Usage > Rust side). - Frontend:
npm install open-tauri-remote-webview, then addimport "open-tauri-remote-webview/bridge-init"at the top of your entry file (before any@tauri-apps/apiimport). - Vite: Add the
/remote_ui_wsproxy if you use Vite dev server (see Usage > Vite dev proxy). - Clean up: Delete all
isTauri()/isRunningInTauri()branches — the bridge transparently proxies IPC calls to WebSocket when running in a browser, and passes through to real Tauri IPC when in WebView. - Optional: Replace
use tauri::Emitterwithuse open_tauri_remote_webview::EmitterExtin your Rust code so events emitted from the backend also reach browser clients.
What stays the same
- All
@tauri-apps/api/*imports and usage - All Tauri command definitions on the Rust side
- All frontend build tooling (Vite, Webpack, etc.)
- All event
listen/once/emitpatterns - All window and app API calls
Caveats
- Single-window mode only:
getCurrentWindow()always returns with label"main" - No asset protocol:
convertFileSrc()returns the path as-is; use raw URLs for assets - No
__TAURI__env: the bridge sets__TAURI_REMOTE_UI_SHIM__instead — check this flag if you need to detect the shim
Usage
1. Rust side
use ;
default
.plugin
.setup
.invoke_handler
.run
.expect;
If you use window.emit() in Rust, replace use tauri::Emitter with
use open_tauri_remote_webview::EmitterExt so events also get forwarded to
browser clients.
2. Frontend — zero-effort (recommended)
In your app entry point (main.ts / main.js), add one line at the top:
// Auto-inject __TAURI_INTERNALS__ WS proxy — @tauri-apps/api works everywhere
import "open-tauri-remote-webview/bridge-init";
// Keep using @tauri-apps/api as-is — no import changes needed
import { invoke } from "@tauri-apps/api/core";
import { getName } from "@tauri-apps/api/app";
import { getCurrentWindow } from "@tauri-apps/api/window";
import { listen } from "@tauri-apps/api/event";
That's it. All @tauri-apps/api calls automatically go through IPC in
WebView and WebSocket in the browser — no if (isTauri()) branches needed.
3. Frontend — explicit API (alternative)
If you prefer explicit imports from this package instead of the transparent bridge:
import { invoke, setBaseUrl } from "open-tauri-remote-webview/api/core";
import { listen, once } from "open-tauri-remote-webview/api/event";
4. Vite dev proxy
// vite.config.ts
server: {
proxy: {
"/remote_ui_ws": {
target: "ws://127.0.0.1:9090",
ws: true,
},
},
},
5. Start / Stop server manually
async
async
How the bridge works
The __TAURI_INTERNALS__ proxy shim (installTauriBridge) is injected when
your app runs in a browser. It mimics the real Tauri runtime:
Browser (@tauri-apps/api/*)
↓
window.__TAURI_INTERNALS__.invoke(cmd, args)
├── "plugin:event|listen" ──→ local WS event system (no round-trip)
├── "plugin:event|unlisten" ──→ remove local listener
└── everything else ──→ WS → Rust → WebView IPC → response
transformCallback/runCallback— managed locally inShimCallbackManagermetadata— hardcoded to{ label: "main" }(single-window mode)convertFileSrc— returns path as-is (browser has no asset protocol)plugins.path— inferred fromnavigator.platform__TAURI_REMOTE_UI_SHIM__flag — lets apps distinguish shim from real Tauri
Package exports
| Import path | What it provides |
|---|---|
open-tauri-remote-webview/bridge-init |
Side-effect — auto-install bridge (recommended) |
open-tauri-remote-webview/api/bridge |
{ installTauriBridge } — manual install |
open-tauri-remote-webview/api/core |
{ invoke, setBaseUrl } |
open-tauri-remote-webview/api/event |
{ listen, once } |
open-tauri-remote-webview |
Re-exports all of the above |
Plugin Development
# Build Rust
# Build JS
&&
# Test app
&&
License
MIT — see LICENSE for the full text.
Based on tauri-remote-ui v0.14.0
Copyright (c) 2025 DraviaVemal, used under MIT.
Modifications and additions Copyright (c) 2026 ant-cave (antmmmmm@126.com / https://github.com/ant-cave).