Public URLs
Expose any port your in-sandbox code is listening on as a public HTTPS URL. Anonymous and WebSocket-aware.
sandbox.url(port) returns a public HTTPS URL that proxies to whatever
your sandbox is listening on at that port. Start a vite dev server,
a jupyter notebook, a gradio app, or any HTTP server inside the
sandbox, and reach it from a browser anywhere on the internet.
Preview a dev server
import { Isorun } from 'isorun'
const isorun = new Isorun()
const sandbox = await isorun.create({ image: 'node:22-slim' })
await sandbox.exec('git clone https://github.com/me/my-app && cd my-app && npm install')
// Start vite in the background. nohup + setsid + redirect so the exec
// call returns immediately and the server keeps running.
await sandbox.exec('cd my-app && nohup setsid npm run dev >/dev/null 2>&1 &')
// Get a public URL anyone can open in a browser.
const url = sandbox.url(5173)
console.log(url)
// → https://5173-run<id>.isorun.app/
// Hand it to the user. Vite HMR over WebSocket works automatically.
notifyUser(url)URL format
The URL encodes the port and the sandbox ID in the host:
https://<port>-<runID>.isorun.app/<path>?<query>| Component | Meaning |
|---|---|
<port> | TCP port your in-sandbox server is listening on |
<runID> | Sandbox ID returned by sandbox.id |
<path> | Forwarded verbatim to the in-sandbox server |
<query> | Forwarded verbatim |
So https://8000-run0123456789abcdef.isorun.app/foo/bar?q=1
becomes a request to localhost:8000/foo/bar?q=1 inside the sandbox.
What passes through the proxy
- All HTTP methods. GET, POST, PUT, DELETE, PATCH, anything.
- Streaming responses. SSE, chunked encoding, etc. pass through without buffering.
- WebSocket upgrades. Vite HMR, Jupyter kernel WS, hot-reload, notebook websockets, gradio's queue WS, langchain streaming, all work end-to-end.
- Cookies. Forwarded both directions.
- Large request and response bodies. No size cap from the proxy.
Authentication model
The URL is anonymous: anyone with the URL can hit it. The sandbox ID in the host is high-entropy, so it's effectively unguessable unless you share it.
The sandbox ID is the only credential on a public URL. Treat any URL you generate as a bearer secret: sharing it grants access to that port.
If you need stronger auth in front of your in-sandbox service, run it behind a reverse proxy with auth inside the sandbox itself, or ship a per-port allowlist via your own gateway.
What gets added to the forwarded request:
X-Forwarded-HostX-Forwarded-Proto: httpsX-Real-IP: <client IP>
Performance
Most of the round-trip is network distance between the client and the runner. For traffic that needs the lowest latency, hold a persistent connection to the URL: HTTP keep-alive, WebSocket, or streaming SSE.
Limits
| Constraint | Value |
|---|---|
| Ports per sandbox | any TCP port your code listens on |
| Method support | all HTTP methods including PATCH and CUSTOM |
| WebSocket support | yes, end-to-end |
| Auth | none; the sandbox ID is the credential |
Next steps
- Computer use (CDP + VNC), expose Chrome DevTools and noVNC through the same proxy.
- TypeScript SDK, the
url(port, path?)reference.