Pake turns any webpage into a lightweight desktop application with a single command. It wraps the site in a native window built on Rust and Tauri, so the result is roughly 20× smaller than the equivalent Electron app (typically around 5 MB) while starting faster and using less memory. Pake works on macOS, Windows, and Linux.
This guide covers everything you do as a user: installing the pake command, packaging your first app, customizing the window and behavior with options, living with the app day to day (keyboard shortcuts, system tray, menus), and fixing the problems people hit most often.
Note
Pake ships two things in one project: the Pake CLI (the
pakecommand you run to build apps) and the Pake container (the Rust/Tauri desktop shell that your packaged app runs inside). This guide is about using both — building apps with the CLI and using the apps you build.
1. Quick Start
If you already have Node.js installed, you can build a desktop app in two commands.
# 1. Install the Pake CLI globally
pnpm install -g pake-cli
# 2. Package any website into a desktop app
pake https://github.com --name "GitHub"
When the build finishes, the installer (a .dmg, .msi, .deb, or .AppImage depending on your operating system) appears in your current working directory. Open it to install your new app.
Important
The first build downloads and compiles the Rust toolchain and Tauri dependencies. Expect 5–15 minutes the first time. Every build after that is much faster because the dependencies are cached.
If you don't want to install anything locally, skip ahead to Building Online with GitHub Actions — you can build apps entirely in the cloud.
2. Installation
2.1 Requirements
| Requirement | Version | Notes |
|---|---|---|
| Node.js | ≥ 22.0.0 recommended (≥ 18.0.0 may work) | Runs the Pake CLI itself |
| Rust | ≥ 1.85.0 | Compiles the desktop app; installed automatically if missing |
| macOS / Linux tools | curl, wget, file, tar |
Used during dependency setup |
Important
Rust 1.85.0 or newer is mandatory. Pake's dependency chain requires the Rust 2024 edition, which only became stable in 1.85.0. An older toolchain fails the build with
feature 'edition2024' is required— see Troubleshooting.
2.2 Install the CLI
Pake is published to npm as pake-cli. The binary it installs is named pake.
pnpm (recommended)
pnpm install -g pake-cli
npm
npm install -g pake-cli
npx (no install)
npx pake-cli https://github.com --name GitHub
Tip
pnpmis the recommended package manager — Pake is pinned to a specific pnpm version internally. If you only havenpm, that works too; the CLI automatically falls back tonpmwhen a compatiblepnpmisn't found.
2.3 Verify the install
pake --version
3.11.7
pake --help
____ _
| _ \ __ _| | _____
| |_) / _` | |/ / _ \
| __/ (_| | < __/ https://github.com/tw93/pake
|_| \__,_|_|\_\___| can turn any webpage into a desktop app with Rust.
Usage: pake [url] [options]
...
Note
If you hit a permission error during global install, see Permission Denied When Installing Globally. The short answer is to use
npx, switch topnpm, or move npm's global prefix into your home directory.
2.4 Platform build tools
Because Pake compiles a real Rust binary, your machine needs the standard native build toolchain. These are one-time setup steps; the CLI prompts you to install Rust automatically, but the platform compilers are on you.
macOS
xcode-select --install
Windows
Install Visual Studio Build Tools 2022 with the Desktop development with C++ workload, plus the Windows 10 SDK (10.0.19041.0). For ARM64 builds, also add MSVC v143 – VS 2022 C++ ARM64 build tools.
Linux (Ubuntu/Debian)
sudo apt install libdbus-1-dev libsoup-3.0-dev \
libjavascriptcoregtk-4.1-dev libwebkit2gtk-4.1-dev \
build-essential curl wget file libxdo-dev libssl-dev \
libgtk-3-dev libayatana-appindicator3-dev librsvg2-dev \
gnome-video-effects libglib2.0-dev pkg-config
3. Packaging Your First App
The command shape is always the same:
pake [url] [options]
[url] is the website you want to wrap (or the path to a local HTML file). Everything else is optional.
pake https://github.com --name "GitHub"
✺ Using pnpm for package management.
✺ First-time setup may take 5-10 minutes (installing dependencies)...
✔ Package installed!
✸ Building app...
✔ Build success!
✔ App installer located in /Users/you/GitHub.dmg
A few things worth knowing about that first run:
- The icon is automatic. If you don't pass
--icon, Pake fetches the website's favicon and converts it to the right format for your platform. - You'll be asked for a name if you omit one. Pake prompts you interactively; the default is derived from the domain.
- The output lands in your current directory. Move to the folder where you want the installer before running
pake.
Tip
Always give your app a clear
--name. On Windows and macOS the name preserves spaces and case (--name "Google Translate"). On Linux it's automatically lowercased and hyphenated (google-translate).
3.1 A richer example
pake https://weekly.tw93.fun \
--name "Weekly" \
--icon https://cdn.tw93.fun/pake/weekly.icns \
--width 1200 \
--height 800 \
--hide-title-bar
This builds an app named Weekly with a custom icon, a 1200×800 window, and the immersive (hidden) title bar on macOS.
3.2 Ready-made popular apps
Pake's maintainers publish pre-built installers for popular sites so you don't have to build them yourself. WeChat, Twitter/X, Grok, DeepSeek, ChatGPT, Gemini, YouTube, YouTube Music, Excalidraw, XiaoHongShu, WeRead, and more are available directly from the project Releases page. Download the installer for your platform and you're done — no CLI required.
4. Everyday Packaging Options
Below are the options you'll reach for most often, grouped by what they do. For the complete alphabetical reference, see Section 11: Full Option Reference.
4.1 Naming and identity
| Option | What it does | Example |
|---|---|---|
--name <string> |
Sets the application name | --name "Weekly" |
--title <string> |
Sets the window title-bar text | --title "My App" |
--icon <path> |
Custom icon (local or remote); auto-fetched if omitted | --icon ./app.png |
--app-version <string> |
Version stamped into the app (default 1.0.0) |
--app-version 2.1.0 |
Tip
Provide the icon in the native format for the cleanest result:
.icnsfor macOS,.icofor Windows,.pngfor Linux. Pake can convert other formats, but the native one is most reliable.
4.2 Window size and appearance
| Option | What it does | Default |
|---|---|---|
--width <number> |
Window width in pixels | 1200 |
--height <number> |
Window height in pixels | 780 |
--min-width <number> |
Minimum resizable width | 0 (no limit) |
--min-height <number> |
Minimum resizable height | 0 (no limit) |
--zoom <number> |
Initial page zoom, 50–200 | 100 |
--hide-title-bar |
Immersive header (macOS only) | off |
--fullscreen |
Launch full screen | off |
--maximize |
Launch maximized | off |
--always-on-top |
Keep the window above others | off |
--dark-mode |
Force dark mode (macOS) | off |
pake https://excalidraw.com --name Excalidraw --width 1400 --height 900 --zoom 110
4.3 System tray and close behavior
| Option | What it does | Default |
|---|---|---|
--show-system-tray |
Show a tray/menu-bar icon | off on macOS, on for Windows/Linux |
--system-tray-icon <path> |
Custom tray icon (.ico/.png, 32–256 px) |
app icon |
--start-to-tray |
Start hidden in the tray (needs --show-system-tray) |
off |
--hide-on-close |
Hide instead of quit when closing | true on macOS, false elsewhere |
pake https://github.com --name GitHub --show-system-tray --start-to-tray
Note
Double-click the tray icon to show or hide the window.
--start-to-trayis ignored unless--show-system-trayis also set.
4.4 Activation shortcut
Bind a global hotkey that shows/hides the app from anywhere:
pake https://chatgpt.com --name ChatGPT --activation-shortcut "CmdOrControl+Shift+P"
Pressing the shortcut toggles the window. The accelerator syntax follows the common Electron accelerator format (e.g. CmdOrControl, Shift, Alt, letter keys).
5. Common Recipes
5.1 Package a chat app that needs sign-in
Some sites authenticate through popup windows. Allow them:
pake https://chat.example.com --name ChatApp --new-window
Warning
--new-windowand--multi-windowhelp popup-based sign-in flows, but they cannot override provider policy. Google in particular blocks sign-in inside embedded webviews. If a site relies on Google OAuth, you may still be unable to log in from a Pake app — that's the provider's restriction, not a Pake bug. Use a real browser for those sign-ins.
5.2 Package WeChat (web)
WeChat detects the webview and blocks repeat logins. Build with incognito mode:
pake https://wx.qq.com --name WeChat --incognito
The trade-off: incognito means cookies aren't stored, so you'll scan a QR code on every launch.
5.3 Strip ads or restyle a page
Inject your own CSS/JS into the wrapped page. Write the customization once and apply it at build time:
# Comma-separated
pake https://news.ycombinator.com --name HackerNews --inject ./style.css,./tweaks.js
# Or repeat the flag
pake https://news.ycombinator.com --name HackerNews --inject ./style.css --inject ./tweaks.js
A minimal ad-hiding CSS file:
.ads-banner { display: none !important; }
.header { background: #1a1a1a !important; }
5.4 Package a local web app
Point Pake at a local HTML file and copy its assets into the bundle:
pake ./my-app/index.html --name "My App" --use-local-file
--use-local-file recursively copies the folder containing the HTML file (and all sub-files) into the app so it runs offline.
5.5 Package a Flutter Web / WebAssembly app
Apps that use SharedArrayBuffer or WebAssembly (Flutter Web, sqlite3.wasm, canvaskit.wasm) need cross-origin isolation headers:
pake https://flutter.dev --name FlutterApp --wasm
5.6 Two apps for the same site
Need separate logins for the same site (e.g. work and personal Gmail)? Build with different names — Pake generates a distinct app identity per URL + name pair:
pake https://gmail.com --name "Gmail Work"
pake https://gmail.com --name "Gmail Personal"
5.7 Build for a specific architecture or format
# macOS universal binary (Intel + Apple Silicon)
pake https://github.com --name GitHub --multi-arch
pake https://github.com --name GitHub --targets universal
# Windows ARM64
pake https://github.com --name GitHub --targets arm64
# Linux RPM instead of the default deb/appimage
pake https://github.com --name GitHub --targets rpm
Note
Linux ARM64 cross-compilation needs extra setup (
gcc-aarch64-linux-gnuand cross-compile environment variables). ARM64 builds let Pake apps run on Raspberry Pi, Linux phones, and other ARM64 systems.
6. Using Your Packaged App
Once installed, a Pake app behaves like a native window around the website. It ships with a full set of keyboard shortcuts, a navigation menu, and (optionally) a tray icon.
6.1 Keyboard shortcuts
| macOS | Windows / Linux | Action |
|---|---|---|
⌘ + [ |
Ctrl + ← |
Back to previous page |
⌘ + ] |
Ctrl + → |
Forward to next page |
⌘ + ↑ |
Ctrl + ↑ |
Scroll to top of page |
⌘ + ↓ |
Ctrl + ↓ |
Scroll to bottom of page |
⌘ + R |
Ctrl + R |
Refresh the page |
⌘ + W |
Ctrl + W |
Hide window (does not quit) |
⌘ + - |
Ctrl + - |
Zoom out |
⌘ + = |
Ctrl + = |
Zoom in |
⌘ + 0 |
Ctrl + 0 |
Reset zoom to 100% |
⌘ + L |
Ctrl + L |
Copy current page URL |
⌘ + ⇧ + ⌥ + V |
Ctrl + Shift + V |
Paste and match style |
⌘ + ⇧ + H |
Ctrl + Shift + H |
Go to the app's home page |
⌘ + ⌥ + I |
Ctrl + Shift + I |
Toggle developer tools (debug builds only) |
⌘ + ⇧ + ⌫ |
Ctrl + Shift + Del |
Clear cache and restart |
Tip
Double-click the title bar to toggle full screen. On macOS you can also drag the title bar to move the window and use trackpad gestures for back/forward navigation.
6.2 In-page Find
If the app was built with --enable-find, you get an in-page search box:
| Shortcut | Action |
|---|---|
Cmd/Ctrl + F |
Open Find |
Cmd/Ctrl + G |
Jump to next match |
Cmd/Ctrl + Shift + G |
Jump to previous match |
6.3 The menu bar (macOS)
macOS builds get a full native menu: Pake (about/hide/quit), File (new window, clear cache & restart), Edit (undo/redo/cut/copy/paste, paste-and-match-style, find), View (reload, zoom, full screen, dev tools), Navigation (back/forward/home), Window, and Help (a link back to the Pake project).
6.4 Downloads
Pake captures downloads triggered inside the page — including blob, data-URI, and dynamically generated files — and saves them to your operating system's Downloads folder. You'll see a toast notification when a download starts, succeeds, or fails, in English or Chinese depending on your system language. If a file with the same name already exists, Pake appends -1, -2, and so on rather than overwriting.
6.5 System tray
If the tray is enabled, left-click the tray icon to show/hide the window. Right-click for a menu with Show, Hide, Quit, and (in multi-window apps) New Window.
7. Building Online with GitHub Actions
You can build Pake apps entirely in the cloud — no local Node, Rust, or compiler needed.
- [ ] Fork the Pake repository
- [ ] Open the Actions tab in your fork
- [ ] Select the Build App With Pake CLI workflow
- [ ] Fill in the form (the fields mirror the CLI options)
- [ ] Click Run Workflow
- [ ] When the run finishes with a green check, download your app from the Artifacts section
Build times: roughly 10–15 minutes on the first run (the cache is being built) and about 5 minutes afterward.
Tip
Pake can also be used as a reusable GitHub Action inside your own repository's workflows. See the project's
pake-action.mddocumentation for theuses:syntax.
8. Running Pake in Docker
If you'd rather not install build tools at all, run the CLI from the official container image. AppImage builds need FUSE access, so the container runs privileged:
docker run --rm --privileged \
--device /dev/fuse \
--security-opt apparmor=unconfined \
-v ./packages:/output \
ghcr.io/tw93/pake \
https://example.com --name myapp --icon ./icon.png --targets appimage
The finished installer is written to the mounted /output directory.
Note
The generated file may be owned by
root. Fix ownership afterward withsudo chown $(id -nu):$(id -ng) ./packages/*.
9. How It Works (Concepts)
You don't need this section to use Pake, but it helps explain why some options behave the way they do.
When you run pake, the CLI:
- Ensures Rust is installed (offering to install it if not) and installs the project's Node and Cargo dependencies.
- Merges your options into a Tauri configuration and writes it to a temporary build directory.
- Compiles a small Rust application — the Pake container — that opens a native window and loads your URL.
- Copies the finished installer into your current directory.
The container is what gives every Pake app its consistent behavior: the keyboard shortcuts, the menu, download handling, the tray, and the ability to inject your custom CSS/JS into the page. The website itself runs in the operating system's built-in webview (WebKit on macOS/Linux, WebView2 on Windows), which is why Pake apps are so much smaller than Electron apps — they don't bundle a whole browser engine.
Note
Because the page runs in a system webview rather than a full browser, a small number of sites behave differently than they would in Chrome or Safari. Most differences are solved with
--user-agentor--inject. See Website Features Not Working below.
10. Troubleshooting
10.1 Rust version error: "feature 'edition2024' is required"
Cause: Your Rust toolchain is older than 1.85.0. Pake's dependencies require the Rust 2024 edition.
Solution:
rustup update stable
rustc --version # must report 1.85.0 or higher
Prevention: Run rustup update stable before your first Pake build.
10.2 Linux: "Can't detect any appindicator library" on Ubuntu 24.04
Cause: Ubuntu 24.04 replaced libappindicator3-dev with the Ayatana fork.
Solution:
sudo apt-get update
sudo apt-get install -y libayatana-appindicator3-dev
10.3 Linux: AppImage build fails with "failed to run linuxdeploy"
Cause: The bundled linuxdeploy strip tool doesn't recognize the .relr.dyn section introduced in glibc 2.38+.
Solution: Pake automatically retries with NO_STRIP=1. To skip stripping from the start:
NO_STRIP=1 pake https://example.com --name MyApp --targets appimage
If that still fails, build a deb instead (--targets deb) or use the Docker image, or install the full set of Linux system dependencies listed in Section 2.4.
10.4 Linux: "cargo: command not found" after installing Rust
Solution: Reload the Rust environment in your shell, then rebuild:
source ~/.cargo/env
10.5 Windows: installation timeout during first build
Cause: First-time setup compiles native modules and downloads large dependencies; antivirus scanning slows it further.
Solutions:
-
Be patient — the first build can take 10–15 minutes on Windows.
-
If downloads are slow in China, opt in to mirrors:
$env:PAKE_USE_CN_MIRROR="1"; pake https://github.com --name GitHub -
Temporarily disable real-time antivirus scanning during the build.
10.6 Windows: missing Visual Studio Build Tools
Solution: Install Visual Studio Build Tools and select the Desktop development with C++ workload. For ARM64, add the C++ ARM64 build-tools component.
10.7 macOS: build fails with module compilation errors
Cause: macOS 26 beta SDKs can break Rust module compilation.
Solution: Pin a compatible SDK:
cat > src-tauri/.cargo/config.toml << 'EOF'
[env]
MACOSX_DEPLOYMENT_TARGET = "15.0"
SDKROOT = "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"
EOF
10.8 App window is too small or too large
Solution: Set explicit dimensions at build time:
pake https://example.com --name Example --width 1200 --height 800
10.9 App icon not showing correctly
Solution: Supply the icon in the platform-native format — .icns (macOS), .ico (Windows), .png (Linux):
pake https://example.com --name Example --icon ./icon.icns # macOS
10.9.3 Website features (login, upload) not working
Cause: Most often a webview compatibility difference, not a bug.
Solutions, in order:
-
Set a desktop browser user agent:
pake https://example.com --name Example \ --user-agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" -
Inject a fix script with
--inject ./fix.js. -
For embedded-webview sign-in limits (especially Google), use a real browser — this is provider policy.
-
For WeChat, add
--incognito.
10.4 Permission denied when installing globally
Solutions:
# Use npx (no install)
npx pake-cli https://example.com
# Or fix npm's global prefix
npm config set prefix ~/.npm-global
echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
# Or use pnpm
pnpm install -g pake-cli
11. Full Option Reference
All options are passed after the URL: pake [url] [options].
11.1 Window and appearance
| Option | Type | Default | Description |
|---|---|---|---|
--name <string> |
string | prompted | Application name |
--title <string> |
string | — | Window title-bar text |
--icon <path> |
path/URL | auto-fetched | Application icon |
--width <number> |
number | 1200 |
Window width (px) |
--height <number> |
number | 780 |
Window height (px) |
--min-width <number> |
number | 0 |
Minimum window width |
--min-height <number> |
number | 0 |
Minimum window height |
--zoom <number> |
number (50–200) | 100 |
Initial page zoom |
--hide-title-bar |
flag | off | Immersive header (macOS) |
--fullscreen |
flag | off | Launch full screen |
--maximize |
flag | off | Launch maximized |
--always-on-top |
flag | off | Keep window on top |
--dark-mode |
flag | off | Force dark mode (macOS) |
11.2 Behavior
| Option | Type | Default | Description |
|---|---|---|---|
--activation-shortcut <string> |
string | empty | Global show/hide hotkey |
--show-system-tray |
flag | platform | Show tray icon |
--system-tray-icon <path> |
path | app icon | Custom tray icon |
--start-to-tray |
flag | off | Start minimized to tray |
--hide-on-close [bool] |
bool | macOS true |
Hide instead of quit on close |
--enable-find |
flag | off | In-page Find (Cmd/Ctrl+F) |
--incognito |
flag | off | Private mode (no cookies/history) |
--enable-drag-drop |
flag | off | Native drag-and-drop in page |
--multi-instance |
flag | off | Allow multiple app processes |
--multi-window |
flag | off | Multiple windows in one process |
--new-window |
flag | off | Allow site-opened popup windows |
--force-internal-navigation |
flag | off | Keep all links inside the window |
--internal-url-regex <pattern> |
regex | empty | Treat matching URLs as internal |
--disabled-web-shortcuts |
flag | off | Disable built-in web shortcuts |
11.3 Web compatibility
| Option | Type | Default | Description |
|---|---|---|---|
--user-agent <string> |
string | empty | Custom User-Agent |
--inject <files> |
path(s) | — | Inject local CSS/JS (comma-separated or repeated) |
--wasm |
flag | off | Enable WebAssembly / cross-origin isolation |
--proxy-url <url> |
url | empty | Route requests through HTTP/HTTPS/SOCKS5 proxy |
--ignore-certificate-errors |
flag | off | Skip TLS validation (self-signed certs) |
--use-local-file |
flag | off | Copy local HTML + assets into the app |
11.4 Build and output
| Option | Type | Default | Description |
|---|---|---|---|
--targets <string> |
string | platform default | Build format/architecture (see below) |
--multi-arch |
flag | off | macOS universal (Intel + Apple Silicon) |
--app-version <string> |
string | 1.0.0 |
App version number |
--keep-binary |
flag | off | Also output a standalone executable |
--iterative-build |
flag | off | Fast app-only build (no installer) |
--install |
flag | off | Install to /Applications after build (macOS) |
--installer-language <lang> |
string | en-US |
Windows installer language |
--debug |
flag | off | Developer tools + verbose logging |
--targets values:
- Linux:
deb,appimage,rpm,deb-arm64,appimage-arm64,rpm-arm64(default:deb,appimage) - Windows:
x64,arm64(auto-detected) - macOS:
intel,apple,universal(auto-detected)
11.5 macOS media permissions (advanced)
By default Pake apps do not request camera or microphone access. Add these only for sites that need them:
pake https://meet.google.com --name GoogleMeet --camera --microphone
| Option | Grants |
|---|---|
--camera |
Camera access (com.apple.security.device.camera) |
--microphone |
Microphone access (com.apple.security.device.audio-input) |
11.6 Environment variables
| Variable | Effect |
|---|---|
PAKE_USE_CN_MIRROR=1 |
Use China mirrors (npmmirror + rsproxy.cn) for downloads |
NO_STRIP=1 |
Skip the AppImage strip step (Linux glibc 2.38+ workaround) |
PAKE_CREATE_APP=1 |
Build a macOS .app bundle instead of a .dmg |
12. FAQ
Q: How big is a Pake app? About 5 MB on average — roughly 20× smaller than the equivalent Electron app, because Pake reuses the operating system's webview instead of bundling a browser engine.
Q: Do I need to know Rust to use Pake? No. The CLI handles all compilation for you and installs Rust automatically if it's missing. Rust knowledge only matters if you want to customize the container's source code.
Q: Why does my first build take so long? The first build downloads and compiles the entire Rust/Tauri dependency tree. Subsequent builds reuse the cache and are much faster.
Q: Can I build a Windows app on macOS (or vice versa)? Pake builds for the platform you run it on. To build for all three platforms without juggling machines, use the GitHub Actions online build.
Q: Where does the installer go?
Into your current working directory. cd to the folder you want before running pake.
Q: Can I change the icon after building?
Rebuild with --icon <path>. There's no post-build icon editor.
Q: My app can't sign in with Google. Is that a bug?
No. Google blocks sign-in inside embedded webviews as a matter of policy. --new-window and --multi-window can help some flows, but Google OAuth specifically may still be blocked. Use a regular browser for those sign-ins.
Q: How do I remove ads or restyle a site?
Write a CSS or JS file and pass it with --inject ./style.css. See Recipe 5.3.
Q: Can I run two copies of the same app?
For separate identities (e.g. two accounts), build with different --name values. To allow multiple processes of the same app, use --multi-instance. To open multiple windows within one process, use --multi-window.
Q: Does Pake store my browsing data?
Each app keeps its own webview data (cookies, local storage) unless you build with --incognito, which disables persistence. Use Clear Cache & Restart (Cmd/Ctrl+Shift+Backspace) to wipe it.
Q: How do I package a site that uses WebAssembly or Flutter Web?
Add --wasm to enable the required cross-origin isolation headers.
Q: Can I build apps in the cloud without installing anything? Yes — fork the repo and use the GitHub Actions workflow, or run the official Docker image.
Q: How do I update the CLI?
Re-run your package manager's global install: pnpm install -g pake-cli (or npm). Pake also notifies you when a new version is available.
Q: Is there a configuration file, or only CLI flags? For day-to-day use, CLI flags are all you need. Deeper customization (editing the container's injected scripts and config) is covered in the Admin Guide.