Automate a cloud browser with Playwright

Use Steel with Playwright in TypeScript for cloud browser automation.

examples/playwright-ts
Contributors: , Updated
Terminal

Scaffolds a starter project locally. Requires the Steel CLI.

Playwright exposes chromium.connectOverCDP(), which attaches to any Chrome speaking the Chrome DevTools Protocol. Steel sessions expose one over a websocket. Connect them and your local code drives a remote browser with stealth, proxies, and a live viewer. No Chrome on your machine required.

session = await client.sessions.create();
const browser = await chromium.connectOverCDP(
`${session.websocketUrl}&apiKey=${STEEL_API_KEY}`,
);
const page = browser.contexts()[0].pages()[0];

A few lines. Steel returns a context with a page already open, so skip newContext() / newPage(). Everything after is plain Playwright: selectors, page.evaluate, waitForSelector, tracing.

Run it

cd examples/playwright-ts
cp .env.example .env # set STEEL_API_KEY
npm install
npm start

Get a key at app.steel.dev/settings/api-keys. The script prints a session viewer URL as it starts. Open it in another tab to watch the browser run live.

Your output varies. Structure looks like this:

Creating Steel session...
Steel Session created!
View session at https://app.steel.dev/sessions/ab12cd34…
Connected to browser via Playwright
Navigating to Hacker News...
Top 5 Hacker News Stories:
1. Claude 4.7 Opus released today
Link: https://news.ycombinator.com/item?id=43218921
Points: 892
2. Show HN: A browser extension for reading on slow connections
Link: https://github.com/user/project
Points: 401
Releasing session...
Session released
Done!

A run costs a few cents of browser time. Steel bills per session-minute, so the finally block that calls client.sessions.release() isn't optional. Forgetting it keeps the browser running until the default 5-minute timeout.

Make it yours

  • Swap the target. Replace the page.goto URL and the page.evaluate body in index.ts. Session setup, auth, and cleanup stay the same.
  • Turn on stealth. Uncomment useProxy, solveCaptcha, or sessionTimeout in the sessions.create() call for sites with anti-bot.
  • Persist login. Reuse cookies and local storage across runs via credentials.

Python version · Playwright docs

examples/playwright-py
Contributors: , Updated
Terminal

Scaffolds a starter project locally. Requires the Steel CLI.

Playwright's Python API ships a CDP attach point, chromium.connect_over_cdp(). Point it at the websocket URL a Steel session hands back and your Page, Locator, and expect calls drive a remote browser instead of a local one. No playwright install, no headful display, no Chrome on your machine.

The whole connection is three lines inside a with sync_playwright() block:

session = client.sessions.create()
playwright = sync_playwright().start()
browser = playwright.chromium.connect_over_cdp(
f"{session.websocket_url}&apiKey={STEEL_API_KEY}"
)
page = browser.contexts[0].new_page()

Two Python-specific details worth calling out. First, this starter uses the sync API. Easier to read top-to-bottom and fine for one script at a time; swap in async_playwright if you need to fan out concurrent pages. Second, Steel returns a session with a context already attached, so you reuse browser.contexts[0] rather than calling new_context(). Everything downstream is plain Playwright: page.locator, page.goto(url, wait_until="networkidle"), XPath selectors.

Run it

cd examples/playwright-py
cp .env.example .env # set STEEL_API_KEY
uv run main.py

Grab a key at app.steel.dev/settings/api-keys. As the script boots it prints a session viewer URL. Open it in a second tab to watch the browser click through Hacker News in real time.

Your output varies. Structure looks like this:

Creating Steel session...
Steel Session created successfully!
You can view the session live at https://app.steel.dev/sessions/ab12cd34…
Connected to browser via Playwright
Navigating to Hacker News...
Top 5 Hacker News Stories:
1. Claude 4.7 Opus released today
Link: https://news.ycombinator.com/item?id=43218921
Points: 892
2. Show HN: A browser extension for reading on slow connections
Link: https://github.com/user/project
Points: 401
Releasing session...
Session released
Done!

One run costs a few cents of session time. Steel bills per session-minute, which is why main() wraps the script in try / finally and calls client.sessions.release(session.id) on exit. If you skip that, the session sits idle until the default 5-minute timeout burns through.

Make it yours

  • Swap the target. The scraping logic lives between the Your Automations Go Here! banner comments in main.py. Replace page.goto and the story_rows loop with your own selectors. Session setup, auth, and teardown stay the same.
  • Harden for anti-bot. Uncomment use_proxy, solve_captcha, or session_timeout inside client.sessions.create() for sites that fingerprint or challenge headless traffic.
  • Go async. If you need parallel pages, switch from playwright.sync_api import sync_playwright to playwright.async_api and rewrite main() as async def. The Steel connection call is identical, just awaited.
  • Persist login. Carry cookies and local storage between runs with credentials.

TypeScript version · Playwright docs