On Runtime, a shared port is private by default. It lives on its own domain,
runtimehost.com. A visit wakes a paused sandbox. So a preview can sit idle
for days at paused-storage prices: $0.08 per decimal GB of
saved state a month. Keeping a running machine instead costs $0.03125 an
hour for 2 vCPU and 4 GiB (rates checked 25 October 2026,
pricing). Runtime adds no badge or banner to the pages a
preview serves.
Share a port and call it
TypeScriptimport { 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); // 200Pythonimport urllib.requestfrom withruntime import Sandboxwith 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) # 200Terminalruntime sandboxes preview "${id}" 3000 # private, with a tokenruntime sandboxes preview "${id}" 3000 --public # anyone with the address (paid)runtime sandboxes previews "${id}"runtime sandboxes unshare "${id}" 3000An agent on MCP uses runtime_sandboxes_previews with create, list, rotate 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: <token> |
| Private, by link | Whoever holds the link | preview.urlWithToken |
| Public | Anyone with the address | preview.url |
Public addresses are for paid sandboxes in an account that has bought credit. A sandbox without credit shares a port by link, with its token. While an account is blocked, or while every purchase it made is refunded in full, a public address needs the token too. It opens to anyone again once the account pays.
To show a private preview inside your own app, set an iframe's src to
urlWithToken. The browser keeps the token for that frame on your site only. So
the page's scripts, styles and live reload load without it.
To stop other sites from framing the preview, name your site when you share the
port: previews.create(3000, { embedOrigins: ["https://app.example.com"] }). In
Python, use embed_origins. You can list up to 16, and
https://*.example.com covers subdomains. Each response then tells the browser
to draw the preview only inside those sites. The link's token works in an iframe
only there. With none named, any site may embed the preview.
Making a port public or private is written to the account's audit log. The entry records who did it and from where.
Manage the tokens
- Revoke every token at the same time with
previews.rotate(port). Every token issued before the call is refused. Use it when a link went somewhere it should not. - Stop sharing with
previews.delete(port). - List what is shared with
runtime sandboxes previews <id>.
A private preview's token expires. So a link sent today does not work forever (network access).
What the server must do
- Run under
spawn, notexec. Everything thatexecstarts ends when its command does. That includesnohup … &.spawnkeeps the server running after your call returns. - Listen on
0.0.0.0orlocalhostinside 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 turned
on. An API client's request waits up to 30 seconds for the wake. A browser shows
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. That
setting counts preview requests as use, so the sandbox runs only while people
use it (pause and resume).
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 sandboxes port-forward <id> 3000 |
| A shell or an editor in the sandbox | runtime sandboxes ssh <id> (editors) |
| Your own hostname, paid accounts | runtime domains add app.example.com <id> 3000 |
| A raw TCP port, such as Postgres, paid accounts | runtime ports open <id> 5432 |
Port forwarding and SSH go through Runtime's API with your key. So the sandbox opens nothing to the internet (networking).
Mistakes to avoid
- Putting the token in a shared URL by hand. Send it as a header from code.
Or hand out
urlWithToken, which works in a browser, withfetch,curland WebSocket clients. - 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. Then nothing listens behind the preview. - Expecting
previews_unavailableto clear. That 501 means previews are turned off there on purpose. Retrying will not help. - Treating the address as your site. Preview addresses sit under
runtimehost.com, never underwithruntime.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; for browser automation against a preview, see Playwright.
Facts on this page were checked on 26 October 2026.