Library / SDK
tauri-apps/wry avatar
tauri-apps/wry

wry: a Rust WebView library for embedding native web engines

Cross-platform WebView library in Rust for Tauri.

4,975 stars544 forksRustApache-2.0

At a glance

What is it?
wry wraps WebKitGTK, WKWebView and WebView2 behind one Rust API so a window from tao or winit can render HTML. It is the layer Tauri is built on, and it is usable on its own if you accept per-platform setup work.
Who is it for?
Adopt wry if you want a native web engine inside a Rust binary and are willing to handle per-platform setup, especially the GTK event loop on Linux. Do not adopt it if you want a batteries-included app framework with bundling and IPC, because wry gives you a webview and nothing else.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem wry solves: one WebView API across three engines

Every desktop platform ships a different web engine. macOS and iOS have WKWebView, Windows has WebView2, and Linux has WebKitGTK. Each has its own C or Objective-C API, its own lifetime rules, and its own idea of how a webview attaches to a window. Writing against all three directly means three code paths in one binary and three sets of build dependencies.

wry is the Rust crate that hides that split. The Cargo.toml describes it as a cross-platform WebView rendering library, and the platform section of the README names the engine each target uses. It is aimed at Rust developers building a desktop or mobile application whose UI is HTML, CSS and JavaScript, but who do not want to ship a bundled browser runtime. It is also the layer underneath Tauri, so anyone debugging Tauri's webview behaviour is eventually reading wry.

The design assumes you already have a window. wry does not create one. The README states the webview requires a running event loop and a window type that implements HasWindowHandle, or a gtk container widget if you need X11 and Wayland support. Windowing libraries such as tao or winit supply that window.

How a wry webview is built and attached to a window

The unit of work is WebViewBuilder. You construct it, set a URL with with_url, and then choose a build method that matches how the webview should be attached.

The default path is build, which takes a window. The README example derives Default on an App struct holding an optional window and an optional wry::WebView, then creates both inside the resumed callback of an ApplicationHandler. That callback is where the event loop has started and a window can legally be created.

A second path, build_as_child, places the webview inside another window rather than filling it. The README shows it taking a Rect built from a LogicalPosition and a LogicalSize, and notes the method is supported on macOS, Windows and Linux (X11 only). That is a real constraint, not a footnote: a child webview is the mechanism you would reach for when composing several webviews in one window, and it is unavailable on Wayland.

The Linux story is where the architecture shows through. WebKitGTK requires GTK, and if your windowing library does not use GTK, the README says you must call gtk::init before creating the webview and then call gtk::main_iteration_do alongside your windowing library's event loop. The example implements about_to_wait on ApplicationHandler and drains pending GTK events there with gtk::events_pending and gtk::main_iteration_do(false). Two event loops, one thread, driven by hand.

For Wayland plus X11, the README recommends WebViewBuilderExtUnix::build_gtk or WebViewExtUnix::new_gtk, and the example packs a gtk::Fixed into the default vbox that tao adds, then builds the webview against that fixed container. The cfg attributes in the snippet split the Linux and non-Linux paths at compile time.

Installing wry and building a first webview

wry is published on crates.io, so it is added as a normal dependency. The Cargo.toml in the repository sets rust-version to 1.85, which is the floor for the toolchain.

toml
[dependencies]
wry = "0.57.0"

On Linux you need the WebKitGTK development package before anything compiles. The README lists the package per distribution. Debian and Ubuntu use one name, Fedora another.

bash
sudo apt install libwebkit2gtk-4.1-dev
bash
sudo dnf install gtk3-devel webkit2gtk4.1-devel

Arch and Manjaro install webkit2gtk-4.1 through pacman. Nix users get a shell.nix in the README that pulls pkg-config and webkitgtk_4_1 from nixpkgs-unstable, and GUIX users get a manifest.scm listing pkg-config and webkitgtk.

With the dependency in place, the smallest useful program pairs wry with a windowing library. The README's winit example creates a window in resumed, builds a webview pointed at a URL, and stores both on the app struct so they outlive the callback.

rust
let window = event_loop.create_window(Window::default_attributes()).unwrap();
let webview = WebViewBuilder::new()
  .with_url("https://tauri.app")
  .build(&window)
  .unwrap();

On Linux with winit, that is not enough on its own. You also need the GTK drain in about_to_wait, otherwise the webview will not process its own events.

rust
#[cfg(target_os = "linux")]
while gtk::events_pending() {
  gtk::main_iteration_do(false);
}

If you would rather not manage two event loops, the alternative the README recommends is using tao with build_gtk on Linux, which hands wry a gtk container directly. The repository ships examples/simple.rs and examples/winit.rs, so you can read a working version of either path before writing your own.

Where wry stops: child webviews, Wayland and mobile

The clearest limitation is the Linux split. The default build path supports X11 only, per the README's own parenthetical. Wayland support exists, but it arrives through build_gtk and a GTK container rather than through the same call you use on macOS and Windows. That means your Linux code branches, and the branch is not a one-line difference: it changes what object owns the webview.

Child webviews carry the same boundary. build_as_child is documented as supported on macOS, Windows and Linux (X11 only), so a layout that composes multiple webviews in one window has no Wayland path through that method.

There is also a macOS cross-compilation trap the README calls out directly. Building for macOS with osxcross can produce a runtime panic reading Class with name WKWebViewConfiguration could not be found, which the README attributes to WebKit.framework not being linked correctly. The stated fix is setting RUSTFLAGS to link the framework. This is a runtime failure, not a compile error, so it surfaces after the binary ships.

wry is also the wrong tool if what you actually want is an application framework. It gives you a webview and a builder. It does not bundle your assets, define an IPC protocol, generate installers, or manage updates. The repository does carry a MOBILE.md and the README claims support for Windows, macOS, iOS, Android and Linux (X11 Only) on the HasWindowHandle path, but that breadth is about where a webview can be attached, not about app packaging.

wry against Tauri, and against shipping a browser runtime

The obvious alternative is Tauri itself, the project wry lives under. The difference is scope, not engine. Tauri consumes wry for rendering and adds the pieces an application needs: a command and event bridge between Rust and the frontend, a configuration file, bundling, and an update mechanism. Choosing wry directly means you write the bridge yourself, typically over a custom protocol or the platform's own message passing.

The other alternative is bundling a browser engine, the Electron model. That approach gives you one engine on every platform, so rendering and JavaScript behaviour match everywhere and you do not install WebKitGTK on Linux or depend on WebView2 on Windows. The cost is a large runtime shipped with your binary and a rendering stack you update yourself. wry takes the opposite position: use the engine the operating system already has. That keeps the binary small and the engine patched by the OS vendor, but it means the engine version varies by machine, and on Linux it means a distribution package is a hard build requirement.

A third option is using the platform webview bindings directly, one crate per platform. wry's value over that is one API surface and one set of types such as Rect, LogicalPosition and LogicalSize shared across targets. If you only ever ship on macOS, that value is small and the direct binding is closer to the metal.

Licence, releases and what upgrades cost

The Cargo.toml declares license as Apache-2.0 OR MIT, and the repository carries LICENSE-APACHE, LICENSE-MIT and LICENSE.spdx alongside a .license_template. Dual licensing under those two terms is the common Rust arrangement and is permissive; it does not impose copyleft on your application. The Linux side is a different question, because WebKitGTK, GTK and soup3 are separate projects with their own licences, and your distribution's packaging of them is what governs that. That is a question for whoever reviews dependencies, not something the wry repository answers.

The release cadence is visible in the tags: wry-v0.56.0 on 2026-07-30, wry-v0.56.1 on 2026-08-13, and wry-v0.57.0 on 2026-09-08, with the last push to the dev branch on 2026-09-22. The 0.x version line means minor releases can carry breaking changes, and the repository keeps a CHANGELOG.md and a .changes directory, which is where those breaks are recorded. Upgrading is therefore a read-the-changelog operation rather than a version bump.

The dependency pins matter here. The Linux dependencies in Cargo.toml are pinned exactly, with webkit2gtk and webkit2gtk-sys at =2.0.2 and javascriptcore-rs at =1.1.2. Those exact pins reduce surprise but also mean a fix upstream does not reach you until wry publishes a release. The feature flags are the other upgrade lever: os-webview and x11 are on by default, and the docs.rs metadata builds with no-default-features plus os-webview only, so the documented API surface is the narrower one.

Editorial conclusion

Adopt wry if you want a native web engine inside a Rust binary and are willing to handle per-platform setup, especially the GTK event loop on Linux. Do not adopt it if you want a batteries-included app framework with bundling and IPC, because wry gives you a webview and nothing else. Before committing, check that your Linux targets have libwebkit2gtk-4.1-dev installed, that your Rust toolchain is at least 1.85, and that your windowing layer exposes a HasWindowHandle or a gtk container, since the README ties the build path to those two options.

Frequently asked questions

What is the Tauri app used for?

Tauri is the application framework built on top of wry, which supplies the webview rendering. The README describes wry itself as a cross-platform WebView rendering library, and the repository sits under the tauri-apps organisation.

Who is using Tauri?

No individual applications or users are named in the repository files. What those files do show is the project's structure: wry lives in the tauri-apps organisation, has a Discord chat server, an Open Collective sponsorship link and a Tauri programme within The Commons Conservancy.

What popular apps use Tauri?

No application names appear in the repository files, so there is nothing here to list. The README links to tauri.app as the project website, which is where such a list would live.

Is Tauri any good?

That is a judgement the repository files cannot settle. What they do establish is that wry, the layer Tauri builds on, uses the web engine each platform already ships rather than bundling one, and that the Linux path requires WebKitGTK plus GTK event loop handling.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. README
  4. Releases
  5. tauri-apps/wry on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tauri-apps-wry.svg)](https://hysenlabs.com/projects/tauri-apps-wry)