Core Primitives

Tunnels

HTTPS tunnels for any local port: one command, stable subdomains, Basic auth, and traffic capture.

Docs for LLMs

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.

Terminal
npx otterkit tunnel <port>
Terminal
$ 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#

OptionWhat 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.
--daemonRun in the background. Manage it with status and stop.
--no-logTurn 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.
--jsonMachine-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.

Terminal
# The first run reserves the name; later runs reuse it
npx otterkit tunnel 3000 --subdomain my-api
# -> https://my-api.otterkit.app, every time

Names are 3 to 63 characters: a lowercase letter, then letters, digits, or hyphens. Manage reservations with the subdomains command:

Terminal
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 name

Auto-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.

Terminal
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 it

Background tunnels with --daemon#

Terminal
# 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-api

Captured 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.

Terminal
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 5xx

Protect 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.

Terminal
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:

Terminal
npx otterkit tunnel 5173 --ttl 4h        # Vite, auto-stops after the demo

Develop against real webhooks. Give Stripe or GitHub a stable URL that forwards straight into your local handler:

Terminal
npx otterkit tunnel 3000 --subdomain stripe-dev
# paste https://stripe-dev.otterkit.app/webhook into the Stripe dashboard

Test 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:

Terminal
npx otterkit tunnel 3000 --daemon --ttl 2h --json
# {"subdomain":"tunnel-…","publicUrl":"https://tunnel-….otterkit.app","pid":51423, ...}