Agent Runtime
Status: Connected
Parsing documentation...
Extracted api references
Generating type definitions...
opensteeropensteer
Y Combinator logoBacked by Y Combinator.

The most comprehensive browser automation framework for AI

Enterprise-grade automation at scale.

Custom plans, unlimited concurrent sessions, dedicated proxies, and advanced support for teams that need more.

+ self-service sso
+ unlimited concurrent sessions
+ custom audit logs
+ advanced captcha bypass
+ dedicated support
view pricing

Simple, transparent pricing.

Start for free, upgrade when you need to scale. Everything you need to build robust AI agents.

Skills & Integrations

Workflows

CLI exploration to SDK replay workflow and integration patterns.

Always Use OpenSteer Methods

Wrong (Playwright)Right (OpenSteer)
page.goto(url)opensteer.goto(url)
page.click(selector)opensteer.click({ description })
page.fill(selector, text)opensteer.input({ description, text })
page.locator(sel).textContent()opensteer.getElementText({ element })
page.content()opensteer.snapshot()
page.evaluate(...)opensteer.extract({ ... })

Only exception: page.evaluate(fetch(...)) for REST/GraphQL API calls after navigating for cookies.

Default Workflow

  1. Explore with CLI — open a session, navigate, snapshot, interact
  2. Cache selectors — descriptions persist automatically in .opensteer/selectors/<namespace>
  3. Cache extractions — extract schemas persist for replay
  4. Generate script — SDK reads from the same namespace

CLI Exploration

# Open session with namespace
opensteer open --name eures-scraper --url https://eures.europa.eu

# Snapshot for actions
opensteer snapshot action

# Interact with elements
opensteer click --description "search-button"
opensteer input --description "keyword-input" --text "software engineer"
opensteer click --description "search-submit"

# Wait for results
opensteer wait-for "results"

# Snapshot for extraction
opensteer snapshot extraction

# Extract data
opensteer extract --description "job-listings" --schema '{"items": [{"title": "string", "company": "string", "location": "string"}]}'

# Close
opensteer close

Key Rules

  • Always use --name to set namespace (links CLI cache to SDK)
  • Use snapshot action before clicks/inputs, snapshot extraction before extracts
  • Always use --description for replayable selectors
  • Use array schemas ([{...}]) for lists
  • open = raw goto (no stability wait), navigate = goto + stability wait
  • Re-snapshot after navigation or significant DOM changes
  • Prefer counter-based element targeting (--element N) when descriptions are ambiguous

Script Template

import { Opensteer } from 'opensteer'

async function main() {
  const opensteer = new Opensteer({
    name: 'eures-scraper',
    headless: false,
  })

  try {
    await opensteer.launch()
    await opensteer.goto('https://eures.europa.eu')

    // Action phase
    await opensteer.snapshot({ mode: 'action' })
    await opensteer.click({ description: 'search-button' })
    await opensteer.input({ description: 'keyword-input', text: 'software engineer' })
    await opensteer.click({ description: 'search-submit' })

    await opensteer.waitForText('results')

    // Extraction phase
    await opensteer.snapshot({ mode: 'extraction' })
    const result = await opensteer.extract({
      description: 'job-listings',
      schema: {
        items: [{
          title: { type: 'string' },
          company: { type: 'string' },
          location: { type: 'string' },
        }],
      },
    })

    console.log(JSON.stringify(result.data, null, 2))
  } finally {
    await opensteer.close()
  }
}

main()

Script Rules

  • No top-level await — wrap in async function main()
  • Default to headless: false for development
  • Always use try/finally with close()
  • Use the same name as CLI exploration

Element Targeting Priority

  1. description — persisted, replayable across sessions
  2. element — counter from current snapshot, volatile
  3. selector — CSS selector, fragile on dynamic pages

Debugging

  1. Run opensteer status to verify session health
  2. Re-snapshot before counter-based actions
  3. Enable OPENSTEER_DEBUG=true for verbose logging
  4. Check namespace: CLI --name must match SDK name