Automate a cloud browser with Playwright
Use Steel with Playwright in TypeScript for cloud browser automation.
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-tscp .env.example .env # set STEEL_API_KEYnpm installnpm 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 PlaywrightNavigating to Hacker News...Top 5 Hacker News Stories:1. Claude 4.7 Opus released todayLink: https://news.ycombinator.com/item?id=43218921Points: 8922. Show HN: A browser extension for reading on slow connectionsLink: https://github.com/user/projectPoints: 401…Releasing session...Session releasedDone!
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.gotoURL and thepage.evaluatebody inindex.ts. Session setup, auth, and cleanup stay the same. - Turn on stealth. Uncomment
useProxy,solveCaptcha, orsessionTimeoutin thesessions.create()call for sites with anti-bot. - Persist login. Reuse cookies and local storage across runs via credentials.
Related
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-pycp .env.example .env # set STEEL_API_KEYuv 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 PlaywrightNavigating to Hacker News...Top 5 Hacker News Stories:1. Claude 4.7 Opus released todayLink: https://news.ycombinator.com/item?id=43218921Points: 8922. Show HN: A browser extension for reading on slow connectionsLink: https://github.com/user/projectPoints: 401…Releasing session...Session releasedDone!
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 inmain.py. Replacepage.gotoand thestory_rowsloop with your own selectors. Session setup, auth, and teardown stay the same. - Harden for anti-bot. Uncomment
use_proxy,solve_captcha, orsession_timeoutinsideclient.sessions.create()for sites that fingerprint or challenge headless traffic. - Go async. If you need parallel pages, switch
from playwright.sync_api import sync_playwrighttoplaywright.async_apiand rewritemain()asasync def. The Steel connection call is identical, just awaited. - Persist login. Carry cookies and local storage between runs with credentials.
Related
Related recipes
Automate browsing with natural-language instructions using Stagehand
Use Steel with Stagehand for natural-language-driven AI browser automation.
Automate a cloud browser with Puppeteer
Use Steel with Puppeteer in TypeScript for cloud browser automation.
Automate a cloud browser with Selenium
Use Steel with Selenium in Python for cloud browser automation.