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
- Explore with CLI — open a session, navigate, snapshot, interact
- Cache selectors — descriptions persist automatically in
.opensteer/selectors/<namespace> - Cache extractions — extract schemas persist for replay
- 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
--nameto set namespace (links CLI cache to SDK) - Use
snapshot actionbefore clicks/inputs,snapshot extractionbefore extracts - Always use
--descriptionfor 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 inasync function main() - Default to
headless: falsefor development - Always use
try/finallywithclose() - Use the same
nameas CLI exploration
Element Targeting Priority
description— persisted, replayable across sessionselement— counter from current snapshot, volatileselector— CSS selector, fragile on dynamic pages
Debugging
- Run
opensteer statusto verify session health - Re-snapshot before counter-based actions
- Enable
OPENSTEER_DEBUG=truefor verbose logging - Check namespace: CLI
--namemust match SDKname
