Skip to content
Try out in chatDeveloper dashboardLogin
Environments

Computers

Cloud environments that Northstar operates in, or that you control directly.

A computer is an isolated cloud environment that Northstar operates in (via Tasks or the Responses API), or that you control directly with the Computers API. Each one runs Lightcone OS, a minimal desktop runtime built for Northstar.

When you use Tasks, the computer is created and managed for you automatically. You only need this page if you’re building your own computer-use loop or doing direct programmatic control.

DesktopBrowser
kind"desktop""browser"
EnvironmentFull Lightcone OS desktopLightcone OS with Chromium in foreground
Use casesNative apps, multi-app workflows, OS-level workWeb automation, scraping, testing
Tab managementNoYes
Proxy supportNoYes (stealth mode, residential proxies)
File systemFull Linux filesystemIsolated per session
from tzafon import Lightcone
client = Lightcone()
# High-level wrapper with automatic cleanup
with client.computer.create(kind="desktop") as computer:
result = computer.screenshot()
print(computer.get_screenshot_url(result))
# computer terminates when block exits
import Lightcone from "@tzafon/lightcone";
const client = new Lightcone();
const computer = await client.computers.create({ kind: "desktop" });
const result = await client.computers.screenshot(computer.id!);
console.log(result.result?.screenshot_url);
// Always clean up when done
await client.computers.delete(computer.id!);

Every action returns an ActionResult containing a status, optional result data, and optional page_context with viewport state.

computer.click(100, 200)
computer.type("hello world")
computer.hotkey("enter")
computer.scroll(0, 300, 640, 400) # dx, dy, x, y
result = computer.screenshot()
url = computer.get_screenshot_url(result)
html_result = computer.html()
content = computer.get_html_content(html_result)
const id = computer.id!;
await client.computers.click(id, { x: 100, y: 200 });
await client.computers.type(id, { text: "hello world" });
await client.computers.hotkey(id, { keys: ["enter"] });
await client.computers.scroll(id, { dx: 0, dy: 300, x: 640, y: 400 });
const result = await client.computers.screenshot(id);
const url = result.result?.screenshot_url as string;
const htmlResult = await client.computers.html(id);
const content = htmlResult.result?.html_content as string;
ActionResult keyValue
screenshot()screenshot_urlURL of the captured screenshot
html()html_contentThe page’s HTML as a string
debug()debug_responseShell command output
# Automatic with context manager (recommended)
with client.computer.create(kind="desktop") as computer:
pass # ... work with the computer
# Or manual cleanup
computer = client.computers.create(kind="desktop")
result = client.computers.screenshot(computer.id)
client.computers.delete(computer.id)
await client.computers.delete(computer.id!);

Both SDKs provide a ComputerSession class that binds a computer ID to convenience methods, so you don’t have to pass the ID on every call.

Python. Accessed via client.computer.create() with a context manager:

with client.computer.create(kind="desktop") as computer:
computer.click(100, 200)
computer.type("hello")
result = computer.screenshot()
url = computer.get_screenshot_url(result)

TypeScript. Imported from the package and created with ComputerSession.create():

import Lightcone, { ComputerSession } from "@tzafon/lightcone";
const client = new Lightcone();
const computer = await ComputerSession.create(client, { kind: "desktop" });
try {
await computer.click(100, 200);
await computer.type("hello");
const result = await computer.screenshot();
const url = ComputerSession.getScreenshotUrl(result);
} finally {
await computer.terminate();
}
ActionDescription
click(x, y)Left-click at pixel coordinates
double_click(x, y)Double-click
right_click(x, y)Right-click (context menu)
drag(x1, y1, x2, y2)Click-and-drag between two points
mouse_down(x, y)Press and hold the mouse button
mouse_up(x, y)Release the mouse button
ActionDescription
type(text)Type text into the focused element
hotkey(keys)Press a key combination (e.g., ["ctrl", "c"])
key_down(key)Press and hold a key
key_up(key)Release a held key
ActionDescription
navigate(url)Go to a URL (browser mode)
scroll(dx, dy, x, y)Scroll at position by delta
viewport(width, height)Resize the viewport
screenshot()Capture the current screen
html()Get the page HTML (browser mode)
ParameterDefaultDescription
max_lifetime_secondsPlan-dependentMaximum total lifetime
inactivity_timeout_secondsPlan-dependentTime with no actions before auto-termination: any executed action or keepalive call resets it
idle_timeout_enabledtrueWhether the inactivity timeout is active (max lifetime always applies)
computer.keep_alive()
await client.computers.keepalive(computer.id!);

Save environment state and restore it later:

# Save state on termination
with client.computer.create(kind="desktop", persistent=True) as computer:
result = computer.screenshot()
# State saved automatically when terminated
# Restore later
with client.computer.create(
kind="desktop",
environment_id="previous_computer_id",
persistent=True,
) as computer:
result = computer.screenshot() # Everything is still there
const computer = await client.computers.create({
kind: "desktop",
persistent: true,
});
await client.computers.delete(computer.id!);
const restored = await client.computers.create({
kind: "desktop",
environment_id: computer.id!,
persistent: true,
});

Execute multiple actions in a single request:

results = client.computers.batch(computer.id, actions=[
{"type": "click", "x": 100, "y": 200},
{"type": "type", "text": "search query"},
{"type": "hotkey", "keys": ["enter"]},
{"type": "screenshot"},
])
const results = await client.computers.batch(computer.id!, {
actions: [
{ type: "click", x: 100, y: 200 },
{ type: "type", text: "search query" },
{ type: "hotkey", keys: ["enter"] },
{ type: "screenshot" },
],
});

Any action endpoint accepts ?screenshot_after=true to return a post-action screenshot in the same response, one round trip instead of two. Combine with settle_ms (how long to let the screen settle first) and base64=true (inline the image instead of returning a URL). See Observability.

Connect with Playwright or Puppeteer (CDP)

Section titled “Connect with Playwright or Puppeteer (CDP)”

Browser computers expose their Chrome DevTools Protocol endpoint. Point any CDP client at it and drive the same browser with selectors, while keeping the Lightcone actions API, screenshots, and live view available on the same session:

First discover the browser’s CDP websocket URL from the session’s /cdp/json/version endpoint (passing your key as ?token= embeds it in the returned URL), then connect a CDP client to it:

import httpx
from playwright.sync_api import sync_playwright
computer = client.computers.create(kind="browser")
# The returned webSocketDebuggerUrl already carries the auth token.
info = httpx.get(
f"https://api.tzafon.ai/computers/{computer.id}/cdp/json/version",
params={"token": "YOUR_API_KEY"},
).json()
with sync_playwright() as p:
browser = p.chromium.connect_over_cdp(info["webSocketDebuggerUrl"])
page = browser.contexts[0].pages[0]
page.goto("https://example.com")
print(page.title())
import { chromium } from "playwright";
const computer = await client.computers.create({ kind: "browser" });
// The returned webSocketDebuggerUrl already carries the auth token.
const info = await fetch(
`https://api.tzafon.ai/computers/${computer.id}/cdp/json/version?token=YOUR_API_KEY`,
).then((r) => r.json());
const browser = await chromium.connectOverCDP(info.webSocketDebuggerUrl);
const page = browser.contexts()[0].pages()[0];
await page.goto("https://example.com");
console.log(await page.title());

This is the recommended pattern for hybrid automation: deterministic Playwright steps for the known path, Northstar for the parts that vary. See the Playwright integration for a full guide.

with client.computer.create(kind="browser", use_advanced_proxy=True) as computer:
computer.navigate("https://protected-site.com")
const computer = await client.computers.create({
kind: "browser",
use_advanced_proxy: true,
});