Skip to content

Stoffbergie/tailview

Tailview

Private screen sharing for a Mac over a Tailscale tailnet.

CI License: MIT

Tailview runs a tiny Mac host that captures the screen, streams it to a browser with WebRTC, and forwards touch, click, keyboard, scroll, pan, and zoom input back to macOS. The default flow is meant for an iPhone on the same private tailnet: open the Tailview URL, see the Mac screen, control it.

Features

  • Streams the Mac screen to the web viewer over WebRTC.
  • Uses Tailscale for private access instead of exposing the session publicly.
  • Supports remote pointer, keyboard, scroll, pinch zoom, and two-finger pan.
  • Auto-opens the mobile keyboard when the remote click focuses a Mac text input.
  • Adapts bitrate dynamically while keeping full resolution and 60 FPS targets.

Fresh Clone

Requirements:

  • macOS
  • Node.js 24 or newer
  • pnpm 11.5.2 via Corepack
  • Tailscale on the Mac and viewer device
  • macOS Screen Recording and Accessibility permissions for the desktop host

Setup:

corepack enable
pnpm install --frozen-lockfile
pnpm run validate

pnpm run validate runs Biome, TypeScript, Vitest, the production builds, and the repository audit.

Local Development

TAILVIEW_PORT=4177 TAILVIEW_VIEWER_URL=https://main.tail0f70a4.ts.net/ pnpm --filter @tailview/desktop start
pnpm --filter @tailview/web dev

Then open the Tailscale HTTPS URL on the phone.

Useful checks:

pnpm run validate
pnpm run web:smoke

Architecture

sequenceDiagram
    participant Mac as "Mac host"
    participant Viewer as "Phone browser"
    participant Tailscale as "Tailnet"

    Mac->>Mac: "Capture screen"
    Viewer->>Mac: "Open private HTTPS URL"
    Mac-->>Viewer: "WebRTC video stream"
    Viewer-->>Mac: "Pointer, keyboard, scroll, zoom"
    Mac->>Mac: "Inject native macOS input"
Loading

The web viewer is intentionally static and small. The Mac host owns capture, WebRTC signaling, metrics, and native input injection.

Scripts

  • pnpm run dev starts workspace dev tasks.
  • pnpm run build builds all packages and apps.
  • pnpm run test runs Vitest.
  • pnpm run typecheck runs TypeScript checks.
  • pnpm run check runs Biome.
  • pnpm run validate runs the full local validation path.
  • pnpm run web:smoke runs the browser touch smoke test.

Tech Decisions

  • Tailscale is the privacy boundary; the app does not need a public relay for the direct personal-use path.
  • WebRTC carries live video because browsers and macOS already have the right low-latency media stack.
  • Control messages stay separate from video so input latency can be tuned independently.
  • The viewer stays dependency-light because mobile browser behavior is the product surface.
  • macOS native input is compiled from Swift so the host can avoid a large automation dependency.

Limits

Item Limit
Host platform macOS
Viewer platform Modern browser
Network model Same Tailscale tailnet
Input permissions macOS Accessibility
Screen permissions macOS Screen Recording

License

MIT

About

Private tailnet screen sharing for Mac, web, and iPhone.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors