Browser preview
Open any HTTP server running on your host in the in-app browser, forwarded over SSH. No public tunnel, no port-juggling.
When an agent spins up a dev server — next dev, vite, a Python runserver, a Storybook — you usually want to look at it. Browser preview turns any HTTP server moshi-hook can see on the host into a single tap from the terminal, without exposing the port to the internet.
What it is
moshi-hook watches local TCP listeners on the host and asks each one whether it speaks HTTP. The Moshi app reaches them through a per-session SSH local-forward, so the in-app browser loads the server over an authenticated, host-bound tunnel. Nothing leaves the host except encrypted SSH traffic on the same connection you're already using for the terminal.
This avoids the usual workarounds: no ngrok, no cloudflared, no public ingress, no manual -L flags.
The iOS Simulators and Android emulators on a Mac, streamed by the Mata that comes with moshi-hook, show up next to your web servers and open with live touch control. See Simulator preview.
Requirements
moshi-hookinstalled and running on the host. See Hooks.- An SSH-capable session to the host. Mosh sessions are fine — they bootstrap over SSH and the same channel is reused for the forward.
- A Pro subscription — browser preview and the diff viewer together form the host gateway, which is gated on Pro.
Auto-detection
moshi-hook periodically probes local listeners and remembers which ones respond with an HTTP header. Each detected server carries:
- A name (process command, e.g.
node,python,vite). - The PID and port.
- The bind address (so a server on
127.0.0.1is distinguished from one on0.0.0.0).
When at least one server is detected, the terminal title shows a button in the theme's blue on the right. Tap it to open the picker.
If the button is missing entirely, browser preview is turned off in Settings → Hooks. Turn "Use preview" back on to bring it back.
Choose which ports to scan
By default, moshi-hook probes every eligible loopback listener. If broad discovery touches an unrelated local service, or a dev server on a high port is skipped, configure an explicit allowlist:
moshi-hook set scan-ports 3000,5173,8000
Inclusive ranges work too (moshi-hook set scan-ports 3000,8000-8010), so listing the range you work in is also how you keep an unrelated local service from being probed. Use scan-ports all to restore automatic discovery or scan-ports none to disable HTTP probing. The change applies on the next discovery refresh without restarting the daemon. See Hook settings for the exact behavior and config-file form.
Open a server
Tap the blue button. If a single server is running, the picker still opens so you can confirm it before forwarding. Each row shows:
- The server name and the PID.
- The host:port the server is listening on.
- A short label when moshi-hook recognizes the framework (e.g. "vite", "next", "storybook").
Pick one and Moshi opens it in the in-app browser. The page is a regular browser view — links, refresh, devtools-style scroll all work as you'd expect.
Same-port vs random local port
When you open a server, Moshi tries to bind the matching port locally first (e.g. host :5173 → local :5173), so the URL in the address bar mirrors what you would type on a desktop. If that port is already in use on the device, it falls back to a random free local port and the URL shifts to that one. Either way, only 127.0.0.1 on the device is involved — nothing is reachable from your LAN.
Privacy
- The forward exists only for the active terminal session. Closing the session tears the tunnel down.
- The forward binds locally on the device, not on the host's public interfaces. Other machines on your network or the internet cannot reach the server through Moshi.
- moshi-hook discovery never publishes the server list to Moshi's backend. The picker reads it through the same authenticated host gateway used by the diff viewer.
Troubleshooting
- Button is hidden. Turn on Settings → Hooks → Use preview, then return to the terminal.
- Button is muted with "no servers detected". moshi-hook has not yet found an HTTP listener. Start your dev server (
bun dev,vite, etc.) and retry — the next discovery sweep picks it up within a few seconds. - A specific port never appears. Add it explicitly with
moshi-hook set scan-ports <port>, then wait for the next discovery refresh. - "Preview unavailable" with "no session". The SSH bootstrap for the current session has not finished. Wait a moment or reconnect.
- Wrong server opens. If two processes share a port across interfaces (e.g. one on
127.0.0.1and another on0.0.0.0), pick the one with the bind address you want from the sheet. - Forward fails on the matching local port. Another app on your device is using that port. Moshi falls back to a random port and reports the new URL — there is nothing to do besides note the address.