Skip to main content
A preview URL is a public HTTPS endpoint that routes traffic to a port inside your sandbox. Start a web server and access it immediately via the sandbox’s domain.

Quick Access

Every sandbox has a built-in domain property that gives you instant access to port 80 without creating a preview URL explicitly:
const sandbox = await Sandbox.create();
await sandbox.exec.run("python3 -m http.server 80 &");

console.log(sandbox.domain);
// → sb-abc123-p80.workers.opencomputer.dev

// For other ports:
console.log(sandbox.getPreviewDomain(3000));
// → sb-abc123-p3000.workers.opencomputer.dev
The domain and getPreviewDomain(port) properties construct the preview hostname directly — no API call needed. Traffic is routed through the control plane proxy to the correct sandbox.

Authentication

Preview URLs are public by default — anyone who can guess or learn the hostname can hit your sandbox’s port. To require a bearer token in front of every request, opt in at create time with previewAuth. When enabled, the control plane validates an Authorization: Bearer <token> (or X-OC-Preview-Token: <token>) header on every preview-URL request. Missing or wrong → 401. The check happens before traffic ever reaches your sandbox, so a brute-force run also can’t wake a hibernated sandbox.

Enable at create time

const sandbox = await Sandbox.create({
  previewAuth: { scheme: "bearer", token: "auto" },
});

// previewAuthToken is returned exactly once — store it somewhere durable.
console.log(sandbox.previewAuthToken);
// → "qx2sSi5IYXWBvnnRqwK9Ky_cIAI-x0Vx1bPCt0XMxsI"
token: "auto" (or omitting the field) tells the server to generate a 256-bit random token. To bring your own — useful when your gateway already has a secret it can share with both ends — pass an explicit string of at least 16 characters:
await Sandbox.create({
  previewAuth: { scheme: "bearer", token: process.env.GATEWAY_TOKEN! },
});

Making authenticated requests

Send the token on every request to the preview URL. Two header forms are accepted; pick whichever fits your client:
curl -H "Authorization: Bearer $TOKEN" https://sb-abc123-p3000.workers.opencomputer.dev/
curl -H "X-OC-Preview-Token: $TOKEN"   https://sb-abc123-p3000.workers.opencomputer.dev/
The token gates every port on the sandbox — there’s one token per sandbox, shared across all preview URLs you create on it.

Rotation

When you need to roll the token — exposure, scheduled rotation, employee offboarding — call rotate. The old token stops working immediately and the new plaintext is returned exactly once:
const newToken = await sandbox.rotatePreviewAuthToken();
// sandbox.previewAuthToken is also updated in place.
There is no zero-downtime dual-token mode in v1 — roll out the new token to your caller before discarding the old one, or expect a brief window of 401s during the swap.

What’s stored and what’s not

  • Only the SHA-256 hash of the token is persisted. The server never sees the plaintext after the create or rotate response returns.
  • There is no GET endpoint that returns the token. If you lose it, your only options are to rotate (mint a new one) or recreate the sandbox.
  • A sandbox created without previewAuth has open preview URLs — exactly the same as before this feature existed. The feature is fully opt-in and backwards compatible.

Where the check happens

Authentication is enforced by the cell’s control plane immediately before the request is proxied to the worker. That means:
  • Hibernated sandboxes stay hibernated on missing/wrong tokens — bad tokens can’t burn wake capacity.
  • Self-hosted deployments without the Cloudflare edge get the same gate for free — the check follows the sandbox, not the front door.

Explicit Preview URLs

For tracking, custom domains, or auth configuration, use the preview URL API:
import { Sandbox } from "@opencomputer/sdk";

const sandbox = await Sandbox.create();
await sandbox.exec.run("npx create-next-app@latest /app --yes", { timeout: 120 });
sandbox.exec.start("npm run dev -- --port 3000", { cwd: "/app" });

const preview = await sandbox.createPreviewURL({ port: 3000 });
console.log(preview.hostname); // sb-abc123-p3000.workers.opencomputer.dev

API Reference

Create Preview URL

const preview = await sandbox.createPreviewURL({
  port: 3000,
  domain: "preview.myapp.com", // optional custom domain
});
ParameterTypeRequiredDescription
portnumberYesContainer port to expose (1–65535)
domainstringNoCustom domain
authConfigobjectNoAuthentication configuration

List Preview URLs

const previews = await sandbox.listPreviewURLs();
for (const p of previews) {
  console.log(`Port ${p.port}: https://${p.hostname}`);
}

Delete Preview URL

await sandbox.deletePreviewURL(3000);

Custom Domains

Pass a domain when creating a preview URL. SSL is provisioned automatically via Cloudflare. Custom domain verification is configured at the organization level through the dashboard — not through the SDK.

Persistence

Preview URLs persist across hibernation and wake cycles. If you hibernate a sandbox and wake it later, the preview URLs are still active.

Multiple Ports

Expose multiple services from the same sandbox:
// Frontend
await sandbox.createPreviewURL({ port: 3000 });
// API server
await sandbox.createPreviewURL({ port: 8080 });
// Database admin
await sandbox.createPreviewURL({ port: 5432 });
CLI equivalent: oc preview. Full reference: TypeScript SDK · Python SDK · HTTP API.