Getting started

Create an account, get a project ID, install the SDK, and run your first browser Node or Python process.

Create an account

Verklet requires a project ID before Runtime.boot() can load runtime assets or registry configuration. Sign up at /account, then select or create an organization. Verklet provisions a default project for that organization and shows a public ID that starts with prj_.

Copy that ID into your SDK boot options. It is safe to ship in browser code, but it must come from your Verklet account; demo IDs such as prj_demo are placeholders.

Install

npm install @verklet/sdk
# or
pnpm add @verklet/sdk
# or
yarn add @verklet/sdk

The SDK is published as ESM-only. It expects a browser environment with SharedArrayBuffer available — see browser support for the cross-origin isolation headers your page needs to serve.

Boot a runtime

import { Runtime } from '@verklet/sdk';

const runtime = await Runtime.boot({
  projectId: 'prj_your_project_id',
  backend: 'auto',
  persistenceKey: 'my-first-runtime',
});

Runtime.boot() spins up the coordinator worker, sets up the virtual filesystem, and resolves once everything is ready. projectId is a public identifier from your Verklet account. The boot service uses it to load compatible hosted runtime assets, choose the package registry, enable server-runtime access when available, and report usage. Unknown project IDs are rejected. With a persistenceKey, browser filesystem state is hydrated from OPFS if the visitor has been here before.

backend: 'auto' starts in the browser, runs supported Python through Pyodide, and promotes to the server only for commands that need it, such as uv, unsupported pip packages, or native tools. Use backend: 'browser' for browser-only sessions or backend: 'server' for server-first sessions.

Preview domain allowlist

Hosted Verklet previews load from https://<session>.preview.verklet.com/preview/<port>/. The hosted boot endpoint returns that preview origin template automatically, so SDK users normally do not need to configure a preview domain.

If your app sets a Content Security Policy, allow Verklet previews in the places you render or call them:

frame-src https://*.preview.verklet.com;
child-src https://*.preview.verklet.com;
connect-src https://verklet.com https://registry.verklet.com https://broker.verklet.com wss://broker.verklet.com;

Use the frame-src directive for preview iframes. Keep child-src if you support older CSP implementations. Use runtime.fetchPreview() when your host page needs to inspect preview responses directly. Corporate firewall and egress allowlists should also allow *.preview.verklet.com.

Server promotion needs a short-lived broker grant from your backend. The SDK asks for it through server.grant instead of calling a grant endpoint for you, so your application can attach its own auth headers and policy checks. The grant callback receives the project ID, runtime ID, workspace key, browser installation ID, and requested action:

const runtime = await Runtime.boot({
  projectId: 'prj_your_project_id',
  backend: 'auto',
  server: {
    grant: async (request) => {
      const response = await fetch('/api/verklet/server-grant', {
        method: 'POST',
        headers: {
          authorization: `Bearer ${await getYourAppSessionToken()}`,
          'content-type': 'application/json',
        },
        body: JSON.stringify(request),
      });
      if (!response.ok) {
        throw new Error(`Server grant denied: ${response.status}`);
      }
      return response.json();
    },
  },
});

Keep vks_... private grant secrets on your backend. The browser should only receive short-lived grants scoped to the project, runtime, workspace, and action it is about to perform. In your backend endpoint, verify the current user can use the requested projectId and workspaceKey, then forward the request to Verklet's hosted grant endpoint with your private secret:

await fetch(
  `https://verklet.com/api/runtime/server/grants?projectId=${encodeURIComponent(body.projectId)}`,
  {
    method: 'POST',
    headers: {
      authorization: `Bearer ${process.env.VERKLET_PRIVATE_GRANT_SECRET}`,
      'content-type': 'application/json',
    },
    body: JSON.stringify(body),
  },
);

See server runtime for a complete endpoint example, public minting caveats, and server persistence deletion.

Mount some files

await runtime.mount({
  '/workdir': {
    'package.json': { contents: '{"type":"module"}' },
    'index.mjs': { contents: 'console.log("hello from a tab")' },
    'hello.py': { contents: 'print("hello from Pyodide")' },
  },
});

The mount API takes a tree object. Files contain contents; directories contain nested entries. You can mount as many trees as you like; later mounts overlay earlier ones.

Spawn a process

const proc = await runtime.spawn('node', ['index.mjs'], {
  cwd: '/workdir',
});

for await (const chunk of proc.output) {
  console.log(chunk);
}

await proc.exit;

spawn returns a process handle with an async-iterable output stream, an exit promise that resolves with the exit code, and stdin/kill methods for interactive control.

Supported Python uses the same API and runs in Pyodide in the browser:

const py = await runtime.spawn('python', ['hello.py'], {
  cwd: '/workdir',
});

for await (const chunk of py.output) {
  console.log(chunk);
}

await py.exit;

For packages that Pyodide ships, configure browser preloading at boot:

const runtime = await Runtime.boot({
  projectId: 'prj_your_project_id',
  backend: 'auto',
  python: { preloadPackages: ['matplotlib'] },
});

Listen for server-ready events

If your spawned process opens a port, Verklet emits a server-ready event you can use to fetch from it or open it in an iframe:

runtime.on('server-ready', async ({ port, url }) => {
  console.log(`server is up on :${port}`);
  // `url` is a service-worker-routed URL on this origin.
  iframeRef.current.src = url;
});

Tear down

await runtime.teardown();

Call this on unmount to release worker handles and free resources. If persistOnTeardown was set, the filesystem is flushed through the active backend first: OPFS for browser sessions, server persistence for server sessions.