Form Automation
Fill and submit multi-step forms across legacy web apps without APIs.
Many business-critical workflows involve filling forms in web apps that don’t have APIs — HR systems, government portals, insurance platforms, procurement tools. Lightcone automates these by driving a real browser, exactly as a human would.
Fill a simple form
Section titled “Fill a simple form”from tzafon import Lightcone
client = Lightcone()
with client.computer.create(kind="browser") as computer: computer.navigate("https://httpbin.org/forms/post") computer.wait(2)
# Fill in form fields by clicking and typing computer.click(300, 180) # Customer name field computer.type("Jane Doe")
computer.click(300, 230) # Telephone field computer.type("+1-555-0123")
computer.click(300, 280) # Email field computer.type("jane@example.com")
# Take a screenshot to verify before submitting result = computer.screenshot() print(f"Preview: {computer.get_screenshot_url(result)}")
# Submit computer.click(300, 450) # Submit button computer.wait(2)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://httpbin.org/forms/post" });
await client.computers.click(id, { x: 300, y: 180 }); await client.computers.type(id, { text: "Jane Doe" });
await client.computers.click(id, { x: 300, y: 230 }); await client.computers.type(id, { text: "+1-555-0123" });
await client.computers.click(id, { x: 300, y: 280 }); await client.computers.type(id, { text: "jane@example.com" });
// Verify before submitting const screenshot = await client.computers.screenshot(id); console.log("Preview:", screenshot.result?.screenshot_url);
// Submit await client.computers.click(id, { x: 300, y: 450 });} finally { await client.computers.delete(id);}Coordinates in these examples are illustrative. Take a screenshot first with computer.screenshot() to find the actual field positions on your target form.
Multi-step form with navigation
Section titled “Multi-step form with navigation”For forms that span multiple pages (wizards):
with client.computer.create(kind="browser") as computer: # Step 1: Personal info computer.navigate("https://app.example.com/apply") computer.wait(2) computer.click(400, 200) computer.type("Jane Doe") computer.click(400, 260) computer.type("jane@example.com") computer.click(500, 400) # "Next" button computer.wait(2)
# Step 2: Address computer.click(400, 200) computer.type("123 Main St") computer.click(400, 260) computer.type("San Francisco") computer.click(400, 320) computer.type("CA") computer.click(500, 400) # "Next" button computer.wait(2)
# Step 3: Review and submit result = computer.screenshot() print(f"Review: {computer.get_screenshot_url(result)}") computer.click(500, 450) # "Submit" button computer.wait(3)
# Confirm submission result = computer.screenshot() print(f"Confirmation: {computer.get_screenshot_url(result)}")const computer = await client.computers.create({ kind: "browser" });const id = computer.id!;
try { // Step 1: Personal info await client.computers.navigate(id, { url: "https://app.example.com/apply" }); await client.computers.click(id, { x: 400, y: 200 }); await client.computers.type(id, { text: "Jane Doe" }); await client.computers.click(id, { x: 400, y: 260 }); await client.computers.type(id, { text: "jane@example.com" }); await client.computers.click(id, { x: 500, y: 400 }); // Next await new Promise((r) => setTimeout(r, 2000));
// Step 2: Address await client.computers.click(id, { x: 400, y: 200 }); await client.computers.type(id, { text: "123 Main St" }); await client.computers.click(id, { x: 500, y: 400 }); // Next await new Promise((r) => setTimeout(r, 2000));
// Step 3: Submit await client.computers.click(id, { x: 500, y: 450 });} finally { await client.computers.delete(id);}Let an AI agent fill the form
Section titled “Let an AI agent fill the form”For complex or dynamic forms, let the agent figure out the field layout:
for event in client.agent.tasks.start_stream( instruction=( "Go to https://httpbin.org/forms/post. " "Fill in the form with: " "Customer name: Jane Doe, " "Telephone: +1-555-0123, " "Email: jane@example.com, " "Size: Medium, " "Topping: Bacon. " "Submit the form." ), kind="browser",): print(event)const stream = await client.agent.tasks.startStream({ instruction: "Go to https://httpbin.org/forms/post. " + "Fill in the form with: Customer name: Jane Doe, " + "Telephone: +1-555-0123, Email: jane@example.com, " + "Size: Medium, Topping: Bacon. Submit the form.", kind: "browser",});
for await (const event of stream) { console.log(event);}- Screenshot before submitting — always verify the form is filled correctly before clicking submit
- Use
wait()between steps — multi-step forms often have animations or redirects - Use the Playwright integration for forms where CSS selectors are more reliable than coordinates
- Use persistent sessions to stay logged in across multiple form submissions
- Use batch actions to fill multiple fields in a single request for speed
See also
Section titled “See also”- Web scraping — extract data from pages after form submission
- Dashboard monitoring — monitor for form submission results
- Computers — session persistence for staying logged in
- Run an agent — let AI handle complex, dynamic forms