# How to expose a port from a sandbox at an HTTPS URL Start the server with `spawn`, then call `sbx.previews.create(port)`; the address needs a token unless you pass `visibility: "public"`. **On Runtime a shared port is private by default, lives on its own domain, `runtimehost.com`, and wakes a paused sandbox when someone visits it.** So a preview can sit idle for days at paused-storage prices, $0.08 per decimal GB of saved state a month, instead of a running machine's $0.03125 an hour for 2 vCPU and 4 GiB (rates checked 25 September 2026, [pricing](/docs/pricing)). Runtime adds no badge or banner to the pages a preview serves. ## Share a port and call it ```ts check import { Sandbox } from "withruntime"; await using sbx = await Sandbox.create(); await sbx.spawn("python3 -m http.server 3000"); const preview = await sbx.previews.create(3000); const page = await fetch(preview.url, { headers: { "x-runtime-preview-token": preview.token! }, }); console.log(page.status); // 200 ``` ```python check import urllib.request from withruntime import Sandbox with Sandbox.create() as sbx: sbx.spawn("python3 -m http.server 3000") preview = sbx.previews.create(3000) request = urllib.request.Request(preview["url"], headers={"x-runtime-preview-token": preview["token"]}) print(urllib.request.urlopen(request).status) # 200 ``` ```bash no-run runtime sandbox preview "${id}" 3000 # private, with a token runtime sandbox preview "${id}" 3000 --public # anyone with the address runtime sandbox previews "${id}" runtime sandbox unshare "${id}" 3000 ``` An agent on MCP uses `runtime_sandbox_previews_create`, `_list` and `_delete`. ## Who can open it | How you share it | Who gets in | Send | | --------------------- | ------------------------------- | ---------------------------------- | | Private, from code | A client that sends the token | `x-runtime-preview-token: ` | | Private, in a browser | Whoever opens the one-time link | `preview.urlWithToken` | | Public | Anyone with the address | `preview.url` | Making a port public or private is written to the account's [audit log](/docs/teams#audit-log), with who did it and from where. ## Manage the tokens - **Revoke every token at once** with `previews.rotate(port)`. Every token issued before it is refused; use it when a link went somewhere it should not. - **Stop sharing** with `previews.delete(port)`. - **List what is shared** with `runtime sandbox previews `. A private preview's token expires, so a link sent today does not work forever ([network access](/docs/security#network-access)). ## What the server must do - **Run under `spawn`, not `exec`.** Everything an `exec` starts, `nohup … &` included, ends when its command does. `spawn` keeps the server running after your call returns. - **Listen on `0.0.0.0` or `localhost`** inside the sandbox. - **WebSockets work**, so dev servers keep their live reload. ## A paused sandbox wakes on a visit A visit to a shared port wakes a paused sandbox that has automatic wake on. An API client's request waits up to 30 seconds for it, and a browser sees a short "Waking up" page that reloads itself. The wake is an ordinary wake, billed from the moment it runs. Pair a preview with `idlePauseSeconds`, which counts preview requests as use, and the sandbox runs only while people use it ([pause and resume](/how-to/pause-and-resume-a-sandbox)). ## Preview, port-forward, SSH or a domain? | You need | Use | | ----------------------------------------------- | ----------------------------------------------------- | | A URL for a person or a webhook | A preview | | The port on your own machine, just for you | `runtime sandbox port-forward 3000` | | A shell or an editor in the sandbox | `runtime sandbox ssh ` ([editors](/docs/editors)) | | Your own hostname, paid accounts | `runtime domain add app.example.com 3000` | | A raw TCP port, such as Postgres, paid accounts | `runtime port open 5432` | Port-forward and SSH go through Runtime's API with your key, so the sandbox opens nothing to the internet ([networking](/docs/networking)). ## Mistakes to avoid - **Putting the token in a shared URL by hand.** Send it as the header from code, or give a browser `urlWithToken`, which carries it once. - **Making a preview public to skip the token.** A public address is open to anyone who finds it. Keep it private unless it is meant as a demo. - **Serving from `exec`.** The server ends when the command returns, and nothing is left listening behind the preview. - **Expecting `previews_unavailable` to clear.** That 503 means previews are switched off there on purpose; retrying will not help. - **Treating the address as your site.** Preview addresses sit under `runtimehost.com`, never under `withruntime.com`, so a sandbox's pages never share an origin with your account. For a full product built on previews, see [preview apps an AI agent builds](/use-cases/preview-agent-built-apps); for browser automation against a preview, see [Playwright](/integrations/playwright). Facts on this page were checked on 25 September 2026.