Steel
Run web tests in Steel cloud browser sessions, or in a steel-browser you host yourself.
The Steel plugin, @vostride/agent-qa-plugin-steel, gives each web test a Steel browser session. Before the test connects, it creates the session through Steel's API and hands agent-qa its CDP address. After the test it releases the session. It also drives a steel-browser you host yourself.
Steel runs Chromium only, so tests on a Steel remote use use.browser.name: chromium. CAPTCHA solving, ad blocking, Steel's proxies and Steel's fingerprint injection are off unless a setting turns them on, so a test sees your app the way your users do.
Install
Install the plugin at exactly the version of agent-qa your project runs:
npm install --save-dev --save-exact @vostride/agent-qa-plugin-steel@$(npx agent-qa --version)Configure
plugins:
- name: steel
package: "@vostride/agent-qa-plugin-steel"
options:
apiKey: "{{secret:STEEL_API_KEY}}"
registry:
remotes:
- name: steel
plugin: steel
settings:
idleMinutes: 5
use:
browser:
name: chromium
headless: true
remote: steelPut the key in your secrets file, .env.secrets.local by default, as STEEL_API_KEY=....
Options
Options belong to the plugins entry and describe the account.
| Option | Default | Meaning |
|---|---|---|
apiKey | The Steel API key, a credential. Write it as a {{secret:NAME}} reference. Leave it out for a self-hosted steel-browser. | |
apiUrl | https://api.steel.dev | Steel's API. It must use https:// with no user or password, unless it points at this machine. |
The key is sent as the steel-api-key header and in the connect URL, which agent-qa masks. It never appears in logs, run records or doctor output.
Settings
Settings belong to each remote and describe one place.
| Setting | Default | Meaning |
|---|---|---|
timeoutMinutes | 1440 | Minutes before Steel ends the session, from 1 to 1440. Your Steel plan may cap it lower. |
idleMinutes | 5 | Minutes with no browser command before Steel ends the session, from 1 to 60. |
solveCaptcha | false | Steel's CAPTCHA solving. |
blockAds | false | Steel's ad blocking. |
fingerprint | false | Steel's browser fingerprint injection, which changes what pages see. |
proxy | false | Steel's proxy: true, or Steel's proxy object. |
proxyUrl | Your own proxy, http(s)://user:password@host:port, a credential. Sent instead of Steel's proxy. | |
dimensions | The browser window, { width, height } in pixels. | |
region | The Steel region, such as us-east. | |
profile | A Steel profile ID, loaded read-only. Needs context: reuse. | |
extensions | Steel extension IDs to load into the browser. | |
extra | Any other field of Steel's create request, merged last. |
How the request is built
The plugin builds Steel's create request in this order, each part overriding the one before:
- a session ID the plugin chooses, so it can release the session even if Steel's response never arrives;
- the lifetimes, from
timeoutMinutesandidleMinutes; - the features that change the page: CAPTCHA solving, ad blocking, fingerprint injection and Steel's proxies, each sent off unless a setting turns it on. Steel injects fingerprints unless told not to, so the plugin always says so explicitly;
- the other settings, in Steel's field names. With
proxyUrl, the plugin sends your proxy and not Steel's, so a remote that sets bothproxyUrlandproxyis refused; extra, last, so a field there overrides both a default and a setting. It cannot setsessionId.
For example, settings: { extra: { solveCaptcha: true, headless: true } } turns CAPTCHA solving on and asks for a headless browser.
Session lifetime
By default the plugin asks for a session of up to 1440 minutes that ends after 5 idle minutes. agent-qa releases every session itself after its test; the lifetimes only bound a session agent-qa could not release.
- Plans cap the lifetime. Steel's Launch plan allows 15 minutes, Scale 60 and Enterprise up to 1440. When Steel refuses to create a session with a 400 or 422 that may be about the lifetime, the line ends
if your Steel plan caps sessions below <n> minutes, set settings.timeoutMinutes to the cap. SettimeoutMinutesto your plan's cap, such as15on Launch. - Idle time. Any browser command resets it, and agent-qa sends a heartbeat every 30 seconds while a test holds the session, so a running test never goes idle.
- Killed jobs. A session left behind by a killed CI job, where agent-qa and the plugin die together, ends within the idle time, so it stops billing within minutes.
Recording
Steel records every session and keeps the replay on its dashboard, behind its login. agent-qa's masking does not reach that replay, so a secret a test types may show in it. Steel has no switch to turn recording off, so the plugin has no recording setting. Use test credentials.
The session link is the session's page in Steel's dashboard. Steel's debug URL lets anyone who has it watch and drive the session, so agent-qa masks it and never shows it.
Signed-in profiles
profile loads a Steel profile by ID. The plugin never asks Steel to save it, so nothing a test does is kept. A profile lives in the browser's first context, so the remote needs context: reuse:
registry:
remotes:
- name: steel-signed-in
plugin: steel
context: reuse
settings:
profile: <Steel profile ID>Self-hosted steel-browser
The plugin drives a steel-browser you run yourself:
plugins:
- name: steel-local
package: "@vostride/agent-qa-plugin-steel"
options:
apiUrl: "http://localhost:3000"
registry:
remotes:
- name: steel-local
plugin: steel-local
use:
workers: 1- Point
apiUrlat it. Plainhttp://is allowed only for this machine. - Leave out
apiKey, and the plugin sends no key. - Set
use.workers: 1. A steel-browser serves one session at a time, and releasing a session ends whatever session is active, so two tests at once would end each other's browser. - Its session page is plain
http://, so tests on it show no link.
Account check
agent-qa doctor runs the plugin's account check, which lists sessions and opens none:
- an accepted key reads
the API key was accepted; - without
apiKey, a self-hosted steel-browser that responds readsSteel answered without an API key, and a Steel that wants a key warnsSteel asked for an API key; set options.apiKey; - a refused key warns
the API key was refused.
When a remote is refused
| Kind | Cause | Fix |
|---|---|---|
auth | Steel responded with 401. | Check the key in your secrets file. |
capacity | Steel responded with 429: no free sessions, or a rate limit. | Wait, or lower use.workers. |
refused, ending set settings.timeoutMinutes to the cap | Your plan may cap sessions below the lifetime asked for. | Set timeoutMinutes to the plan's cap. |
refused at settings.profile | The remote sets profile without context: reuse. | Add context: reuse to the remote. |
refused at settings.proxyUrl | The remote sets both proxy and proxyUrl. | Keep one. |
refused at settings.extra.sessionId | extra sets sessionId. | Remove it. |
refused with Unrecognized key: "recording" | Steel cannot turn recording off. | Remove recording. |
refused naming a browser | Steel runs Chromium only. | Use use.browser.name: chromium, or another remote. |
refused at options.apiUrl | The endpoint is not https:// and not this machine. | Use https://, or a loopback address. |
unreachable | Steel did not respond. | Check the network, or that your steel-browser is running. |
Each refusal is one line with Steel's status, the request and Steel's message, and the wait Steel asked for on a 429. If Steel refuses the create request with a 4xx, no session exists and nothing needs releasing. After any other failure, agent-qa still releases whatever Steel may have created.
npx agent-qa plugins describe steel --json lists every option and setting with its type, default and description.