Skip to content
Dashboard

Migrating to Lightcone

Move from local browser automation (Selenium, Puppeteer, Playwright) to Lightcone cloud browsers.

If you’re already using Selenium, Puppeteer, or Playwright for browser automation, Lightcone replaces the browser infrastructure with managed cloud sessions. This guide maps the concepts and APIs you already know to their Lightcone equivalents.

Local automationLightcone
InfrastructureYou manage browser binaries, drivers, containersManaged cloud browsers — nothing to install or maintain
ScalingLimited by your machine’s resourcesSpin up hundreds of sessions on demand
Bot detectionYou configure fingerprinting, proxies, user agentsBuilt-in stealth with optional advanced proxy
AI agentsYou build the agent loop yourselfAgent Tasks run autonomously from a single instruction
Persistent stateYou manage cookie files or browser profilespersistent: true saves and restores automatically
CostFree (but you pay for infrastructure)Pay-per-session, no infrastructure to manage
Local conceptLightcone equivalent
Browser instance / pageComputer session (kind: "browser")
page.goto(url)computer.navigate(url)
page.click(selector)computer.click(x, y) (screenshot-based coordinates)
page.type(selector, text)computer.type(text) (types into focused element)
page.keyboard.press('Enter')computer.hotkey("Enter")
page.screenshot()computer.screenshot() → URL of the captured image
page.content()computer.html() → page HTML content
page.evaluate(js)computer.debug(command) for shell, or use Playwright CDP for JS eval
page.waitForSelector()computer.wait(seconds) + screenshot to verify
browser.close()computer.terminate() or context manager exit
Cookie files / profilesPersistent sessions (persistent: true)
Proxy configuse_advanced_proxy: true or change_proxy()

Before (Selenium):

from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://example.com")
driver.find_element(By.CSS_SELECTOR, "#search").send_keys("hello")
driver.find_element(By.CSS_SELECTOR, "#submit").click()
screenshot = driver.get_screenshot_as_png()
driver.quit()

After (Lightcone):

from tzafon import Lightcone
client = Lightcone()
with client.computer.create(kind="browser") as computer:
computer.navigate("https://example.com")
computer.wait(2)
# Instead of CSS selectors, use screenshot-based coordinates
# Take a screenshot to find field positions
result = computer.screenshot()
print(computer.get_screenshot_url(result))
# Click the search field and type
computer.click(400, 300) # Coordinates from screenshot
computer.type("hello")
# Click submit
computer.click(500, 400)
computer.wait(2)
result = computer.screenshot()
print(computer.get_screenshot_url(result))

Key differences:

  • No driver setup — no ChromeDriver, no version matching, no Docker
  • Coordinate-based interaction — take a screenshot, find the element position, click at those coordinates
  • Automatic cleanup — context manager handles session termination
  • Cloud execution — the browser runs in Lightcone’s cloud, not on your machine

Before (Puppeteer):

import puppeteer from "puppeteer";
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto("https://example.com");
await page.type("#search", "hello");
await page.click("#submit");
await page.screenshot({ path: "result.png" });
await browser.close();

After (Lightcone):

import Lightcone from "@tzafon/lightcone";
const client = new Lightcone();
const computer = await client.computers.create({ kind: "browser" });
const id = computer.id!;
try {
await client.computers.navigate(id, { url: "https://example.com" });
await new Promise((r) => setTimeout(r, 2000));
// Screenshot to find coordinates
const screenshot = await client.computers.screenshot(id);
console.log("Layout:", screenshot.result?.screenshot_url);
// Click and type using coordinates
await client.computers.click(id, { x: 400, y: 300 });
await client.computers.type(id, { text: "hello" });
await client.computers.click(id, { x: 500, y: 400 });
const result = await client.computers.screenshot(id);
console.log("Result:", result.result?.screenshot_url);
} finally {
await client.computers.delete(id);
}

Lightcone has a Playwright integration that lets you keep using Playwright’s selector-based API while running on Lightcone cloud browsers. This is the easiest migration path:

Before (Playwright local):

from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto("https://example.com")
page.fill("#search", "hello")
page.click("#submit")
page.screenshot(path="result.png")
browser.close()

After (Playwright + Lightcone):

from playwright.sync_api import sync_playwright
from tzafon import Lightcone
client = Lightcone()
session = client.computers.create(kind="browser")
with sync_playwright() as p:
# Connect to the Lightcone session via CDP
browser = p.chromium.connect_over_cdp(f"wss://api.tzafon.ai/v1/cdp/{session.id}")
page = browser.contexts[0].pages[0]
page.goto("https://example.com")
page.fill("#search", "hello")
page.click("#submit")
page.screenshot(path="result.png")
browser.close()
client.computers.delete(session.id)

This approach lets you keep your CSS selectors and Playwright test patterns while gaining cloud infrastructure, stealth, and scaling.

Lightcone’s biggest advantage over local automation is AI-powered interaction. Instead of maintaining brittle selectors, let a vision model find elements:

The old way (selector-based):

# Breaks when the site changes its HTML
page.click("#submit-btn")
page.fill("input[name='email']", "user@example.com")

The Lightcone way (AI agent):

# Works regardless of HTML structure
for event in client.agent.tasks.start_stream(
instruction=(
"Go to example.com, "
"enter user@example.com in the email field, "
"and click the submit button."
),
kind="browser",
max_steps=10,
):
print(event)

The Lightcone way (CUA loop for custom logic):

# You control each step, but AI finds the elements
response = client.responses.create(
model="tzafon.northstar-cua-fast",
input=[{
"role": "user",
"content": [
{"type": "input_text", "text": "Click the email field and type user@example.com"},
{"type": "input_image", "image_url": screenshot_url},
],
}],
tools=[{"type": "computer_use", "display_width": 1280, "display_height": 720, "environment": "browser"}],
)
# The model returns coordinates to click — execute them on the session
  • Install the SDK: pip install tzafon or npm install @tzafon/lightcone
  • Get an API key from the dashboard
  • Replace browser launch with client.computer.create(kind="browser")
  • Replace selector-based clicks with coordinate-based clicks (or use the Playwright integration)
  • Replace waitForSelector with computer.wait() + screenshot verification
  • Replace local cookie/profile management with persistent: true
  • Replace proxy configuration with use_advanced_proxy: true
  • Consider replacing coordinate-based scripts with Agent Tasks for resilience