Preview URL
Runtime previews turn a dev server in your cloud workspace into a public URL you can open from your phone, send to a teammate, or point a webhook at. Useful when you want eyes on a feature before it goes anywhere near staging.
Your app runs on the TabTabTab VM, so localhost from your laptop or phone can't reach it the way it would for a server on your own machine. A preview URL gives that VM-local server a reachable HTTPS address.
Security
Preview URLs are password-protected by default. The CLI prints a username and password with the URL, and the Agent Browser inside the Web IDE authenticates automatically. Humans can also find the same credentials in the Environment panel. Use this default for anything that isn't meant for the open internet, including in-progress features, internal tools, and apps that read user data.
If you explicitly want a public preview that anyone with the link can open, ask the agent for a no-auth preview. Under the hood that runs tabtabtab runtime preview ... --no-auth. Use it for shareable demos and webhook receivers, not for anything sensitive.
Asking an agent for a preview
You usually don't run preview commands yourself. The intended workflow is to ask the TabTabTab IDE something like "give me a preview URL for the app." The agent figures out the right ports, verifies the app locally, runs the preview command, and hands back the public URL and credentials. The tabtabtab runtime preview CLI is built for agents to drive; everything below describes what the agent does on your behalf so you know what to expect.
How preview URLs work
When the agent creates a preview, TabTabTab registers one or more VM-local ports with the preview router. Public HTTPS traffic reaches the preview URL, passes through preview authentication by default, and is forwarded back to the selected local port inside the environment.
For a single self-contained app, the agent exposes the frontend port:
tabtabtab runtime preview 5173
The returned URL serves port 5173 from /.
Multi-port apps and CORS
Many apps are not one port. A Vite or Next.js frontend may run on 5173 or 3000, while an API, websocket server, auth service, Storybook, or docs server runs on another port.
We do not create separate preview URLs for each browser-called service. Separate preview URLs are separate origins, which can break cookies, redirects, browser auth, websockets, and CORS. We also do not leave browser code pointing at localhost or 127.0.0.1; from the public browser, those names mean the user's device, not the VM.
Instead, the agent creates one preview URL that includes every port the browser needs. It uses named routes for secondary ports so the frontend and backend share the same preview origin:
tabtabtab runtime preview 5173 --port api:3001
This serves the frontend from / and the API from /ttt-api/ on the same preview host. Browser requests should use the printed API route, for example:
VITE_API_BASE_URL=https://<preview-host>/ttt-api/ npm run dev -- --host 127.0.0.1 --port 5173
If the API has its own base path, keep it after the named route, such as https://<preview-host>/ttt-api/api.
Ports, service names, and named routes
The agent uses tabtabtab runtime ports to see the services and host ports the runtime has published:
tabtabtab runtime ports
tabtabtab runtime ports --all
The default target can be a host port or a discovered service name:
tabtabtab runtime preview web
tabtabtab runtime preview 5173
Secondary ports use repeated --port flags. We prefer named routes for anything the browser calls directly:
tabtabtab runtime preview 5173 --port api:3001 --port storybook:6006
Named routes use the format key:host-port. The key becomes a stable path prefix like /ttt-api/ or /ttt-storybook/. Route keys should be short lowercase names such as api, backend, storybook, docs, auth, or ws.
Bare secondary ports are still supported as fallback routes under /__ports/<port>, but named routes are easier to configure in frontend environment variables and easier to debug:
tabtabtab runtime preview 5173 --port 3001
Start the repo runtime:
tabtabtab runtime up
Check status and ports:
tabtabtab runtime status
tabtabtab runtime ports
tabtabtab runtime ports --all
Expose a running app through a public preview URL:
tabtabtab runtime preview 3000
Inspect logs, rebuild, or stop the runtime:
tabtabtab runtime logs
tabtabtab runtime rebuild
tabtabtab runtime down
Troubleshooting
Preview loads but API or websocket requests fail. The browser is calling the wrong origin. Check that frontend code uses the printed named route, such as https://<preview-host>/ttt-api/, not localhost, 127.0.0.1, or an internal container name. From the public browser those addresses resolve to the user's device, not the VM.
Derived URLs drop the named route. If the frontend stores an API base and then strips the path to build websocket or fetch URLs from window.location.origin, derived requests collapse back to the frontend origin and lose the /ttt-api/ prefix. Configure the app with the full absolute URL (https://<preview-host>/ttt-api/) and preserve the path when constructing websocket or sub-resource URLs (e.g. wss://<preview-host>/ttt-api/socket).
Bare relative paths don't work. Setting an API base to just /ttt-api/ works for simple fetch calls but breaks anything that needs an absolute URL, including new URL() construction, websocket clients, and OAuth redirects. Prefer the full preview URL.
Cookies, auth, or CORS break across services. That usually means the frontend and API are on different preview URLs (two separate origins). Re-create one grouped preview that includes both ports so they share the same origin.
401 prompt when opening the preview. Previews are password-protected by default. Use the username and password printed by the CLI, the Environment panel credentials, or ask the agent for a no-auth preview if the user explicitly wants a public link.
Preview URLs work from desktop or mobile. They're meant for development and team review, not production traffic.