Documentation Index Fetch the complete documentation index at: https://mintlify.com/steerlabs/opensteer/llms.txt
Use this file to discover all available pages before exploring further.
OpenSteer makes form filling simple and reliable with description-based targeting and automatic selector persistence.
Complete Example
import { Opensteer } from 'opensteer'
async function run () {
const opensteer = new Opensteer ({
name: 'contact-form' ,
model: 'gpt-5-mini' ,
})
await opensteer . launch ({ headless: false })
try {
await opensteer . goto ( 'https://www.w3schools.com/html/html_forms.asp' )
await opensteer . input ({
text: 'Ada Lovelace' ,
description: 'Fill first name' ,
})
await opensteer . input ({
text: 'Lovelace' ,
description: 'Fill in last name' ,
})
await opensteer . click ({
description: 'Submit the form' ,
})
} finally {
await opensteer . close ()
}
}
run (). catch (( err ) => {
console . error ( err )
process . exit ( 1 )
})
Text Input
await opensteer . input ({
text: 'Ada Lovelace' ,
description: 'Fill first name' ,
})
The input() method:
Fills text into input fields, textareas, and contenteditable elements
Accepts a description for natural language targeting
Persists selectors for deterministic replay
Supports optional element counter or selector for targeting
Dropdown Selection
await opensteer . select ({
value: 'california' ,
description: 'Select state dropdown' ,
})
The select() method:
Chooses options from <select> dropdowns
Can target by value, label, or index
Works with single and multi-select elements
await opensteer . click ({
description: 'Accept terms and conditions' ,
})
Use click() for checkboxes and radio buttons. OpenSteer handles the interaction intelligently.
await opensteer . click ({
description: 'Submit the form' ,
})
Click the submit button using a natural language description. OpenSteer will find and click the appropriate button.
Step-by-Step Breakdown
1. Initialize with a Namespace
const opensteer = new Opensteer ({
name: 'contact-form' ,
model: 'gpt-5-mini' ,
})
The name parameter creates a selector namespace. All selectors resolved for this instance are saved to .opensteer/selectors/contact-form/, making your script replayable.
Using gpt-5-mini is cost-effective for simple form interactions.
await opensteer . goto ( 'https://www.w3schools.com/html/html_forms.asp' )
Navigate to the page containing the form.
await opensteer . input ({
text: 'Ada Lovelace' ,
description: 'Fill first name' ,
})
await opensteer . input ({
text: 'Lovelace' ,
description: 'Fill in last name' ,
})
Fill each field with descriptive targeting. On the first run, OpenSteer:
Takes a snapshot if needed
Uses LLM to resolve the description to a selector
Saves the selector to .opensteer/selectors/contact-form/
Fills the field
On subsequent runs, OpenSteer reuses the saved selector, making the script deterministic.
await opensteer . click ({
description: 'Submit the form' ,
})
Click the submit button using a description. OpenSteer finds the button and clicks it.
File Upload
await opensteer . uploadFile ({
filePath: '/path/to/document.pdf' ,
description: 'Upload resume' ,
})
uploadFile() is only available in local mode. Cloud mode does not support file uploads.
// Page 1
await opensteer . input ({
text: 'user@example.com' ,
description: 'Email input' ,
})
await opensteer . click ({
description: 'Next button' ,
})
// Wait for navigation
await opensteer . waitForSelector ( 'form' )
// Page 2
await opensteer . input ({
text: 'SecurePassword123' ,
description: 'Password input' ,
})
await opensteer . click ({
description: 'Create account button' ,
})
Conditional Fields
// Select option that reveals additional fields
await opensteer . select ({
value: 'business' ,
description: 'Account type' ,
})
// Fill conditional field
await opensteer . input ({
text: 'Acme Corp' ,
description: 'Company name' ,
})
try {
await opensteer . click ({
description: 'Submit button' ,
})
// Check for success message
const html = await opensteer . snapshot ()
if ( html . includes ( 'Success' )) {
console . log ( 'Form submitted successfully' )
}
} catch ( error ) {
console . error ( 'Form submission failed:' , error )
}
Using Element Counters
For the first run, you can use element counters from a snapshot:
// Take a snapshot first
const html = await opensteer . snapshot ({ mode: 'action' })
console . log ( html )
// Use counter from snapshot
await opensteer . input ({
element: 12 ,
text: 'Ada Lovelace' ,
description: 'Fill first name' ,
})
The c="12" counter in the snapshot tells you which element to target. After the first run, you can omit the element parameter.
Deterministic Replay
After running your script once, selectors are persisted. You can simplify your code:
// First run (with counters or LLM resolution)
await opensteer . input ({
element: 12 ,
text: 'Ada Lovelace' ,
description: 'Fill first name' ,
})
// Subsequent runs (using persisted selector)
await opensteer . input ({
text: 'Ada Lovelace' ,
description: 'Fill first name' ,
})
This makes your automation:
Faster (no LLM calls needed)
Deterministic (same selector every time)
Cost-effective (reduced API usage)
Best Practices
Use consistent descriptions
Keep your descriptions the same across runs to benefit from selector persistence: // Good - consistent description
description : 'Fill first name'
// Bad - varying descriptions
description : 'Enter first name'
description : 'Type in first name'
Take snapshots for development
During development, take snapshots to identify element counters: const html = await opensteer . snapshot ({ mode: 'action' })
console . log ( html )
This helps you understand the page structure and find the right elements.
Handle dynamic forms gracefully
Always close OpenSteer in a finally block: try {
// Form filling logic
} finally {
await opensteer . close ()
}
Running the Example
Install OpenSteer:
Run the example:
Next Steps
AI Integration Learn how to build AI agents with OpenSteer
API Reference Explore all available methods