A tunnel exposes a local port on a public HTTPS URL. The CLI creates it, charges your credits, and connects over a WebSocket. Run otterkit login once first. A tunnel costs 1 credit ($0.01) per connected hour, with the first hour charged up front. Billing pauses while the tunnel is disconnected, and no tunnel bills more than $3 per rolling 30 days.
npx otterkit tunnel <port>$ npx otterkit tunnel 3000
✓ Tunnel provisioned · tunnel-a1b2c3d4
✓ Tunnel ready
URL https://tunnel-a1b2c3d4.otterkit.app
Target 127.0.0.1:3000
Rate 1 credit/hr · never more than 300/month
Press Ctrl+C to disconnect
200 GET / (12ms)
200 GET /api/users (8ms)Options#
| Option | What it does |
|---|---|
<port> | The local port to forward to (1-65535). |
--host <host> | The local host to forward to. Default 127.0.0.1. |
--subdomain <name> | Use a stable name. It is reserved to your account on first use (up to 10 per account), and the URL survives restarts. |
--ttl <duration> | Auto-stop on the server, e.g. 45m, 4h, 3d. Default 24h. Use never to run until stopped. |
--daemon | Run in the background. Manage it with status and stop. |
--no-log | Turn off traffic capture. Capture to a local JSONL log is on by default. |
--auth <user:pass> | Require HTTP Basic auth, checked on your machine before forwarding. |
--json | Machine-readable output. Requires --daemon. |
Stable URLs with --subdomain#
By default every tunnel gets a random tunnel-… name. Pass --subdomain to reserve a name to your account. Restart the tunnel any time and the URL stays the same, so webhooks, OAuth redirect URIs, and bookmarks keep working.
# The first run reserves the name; later runs reuse it
npx otterkit tunnel 3000 --subdomain my-api
# -> https://my-api.otterkit.app, every timeNames are 3 to 63 characters: a lowercase letter, then letters, digits, or hyphens. Manage reservations with the subdomains command:
npx otterkit subdomains # list your reserved names
npx otterkit subdomains reserve my-api # reserve without starting a tunnel
npx otterkit subdomains release my-api # free the nameAuto-stop with --ttl#
A TTL is a safety net for forgotten tunnels. When the timer runs out, the server stops the tunnel, even if the process is still running. The TTL limits how long the tunnel runs, not what it costs per hour.
npx otterkit tunnel 3000 --ttl 45m # quick review call
npx otterkit tunnel 3000 --ttl 4h # an afternoon demo
npx otterkit tunnel 3000 --ttl 7d # a week
npx otterkit tunnel 3000 --ttl never # until you stop itBackground tunnels with --daemon#
# Stable background tunnel for the workday
npx otterkit tunnel 3000 --subdomain my-api --ttl 8h --daemon
# See what's running, then stop it by name
npx otterkit status
npx otterkit stop my-apiCaptured traffic#
Tunnels capture every request (headers, body, status, and duration) to a local JSONL file at ~/.otterkit/requests/<subdomain>.jsonl. Bodies over 64 KB and asset responses are stored as metadata only, and the log rotates at about 50 MB. Pass --no-log to turn capture off.
npx otterkit tunnel 3000
# Later: browse, follow, filter, or export what came in
npx otterkit inspect tunnel-a1b2c3d4
npx otterkit inspect tunnel-a1b2c3d4 --follow --status 5xxProtect the URL with --auth#
The CLI checks credentials on your machine before anything reaches your local server. Requests without valid credentials get a 401 and are never forwarded. The credentials are not sent to or stored by OtterKit's servers.
npx otterkit tunnel 3000 --auth admin:s3cret
curl -u admin:s3cret https://tunnel-a1b2c3d4.otterkit.app/Use cases#
Demo work in progress. Share the dev server you already have running. A client sees your machine over HTTPS with no deploy:
npx otterkit tunnel 5173 --ttl 4h # Vite, auto-stops after the demoDevelop against real webhooks. Give Stripe or GitHub a stable URL that forwards straight into your local handler:
npx otterkit tunnel 3000 --subdomain stripe-dev
# paste https://stripe-dev.otterkit.app/webhook into the Stripe dashboardTest from a phone or another machine. Point any device at the public URL to reach your local build.
Agents exposing their own work. An agent that just built a web app can create its own preview URL and hand it back, with no human in the loop:
npx otterkit tunnel 3000 --daemon --ttl 2h --json
# {"subdomain":"tunnel-…","publicUrl":"https://tunnel-….otterkit.app","pid":51423, ...}