---
title: "Browser automation"
description: "Browser automation in a cloud browser: log in to portals, run multi-step lookups and download statements with your own Playwright or Puppeteer code."
canonical: https://www.zenrows.com/use-cases/browser-automation
updated: 2026-10-18
---

# Browser automation

Browser automation is software driving a real web browser through a task a person would otherwise do by hand, such as logging in, searching, clicking through steps and downloading files. Zenrows runs that browser in its cloud with Zenrows' stealth, your Playwright or Puppeteer code connects over CDP, and the task returns data or documents to your systems.

## Sample output: one portal retrieval run

```json
{
  "task": "monthly_statement_download",
  "portal": "vendor-portal.example.com",
  "account_ref": "acct_0042",
  "started_at": "2026-10-17T06:00:04Z",
  "finished_at": "2026-10-17T06:02:41Z",
  "steps": [
    { "action": "goto", "target": "/login", "ok": true },
    { "action": "fill", "target": "#username", "ok": true },
    { "action": "click", "target": "button[type=submit]", "ok": true },
    { "action": "goto", "target": "/account/statements", "ok": true },
    { "action": "fetch_file", "target": "statement-2026-09.pdf", "ok": true }
  ],
  "files": [
    { "name": "statement-2026-09.pdf", "bytes": 184320, "period": "2026-09" }
  ],
  "fields": { "amount_due": 4182.5, "currency": "USD", "due_date": "2026-11-05" },
  "status": "completed"
}
```

An illustrative run record your script writes after each task, so a missing statement or a failed step is visible the morning it happens.

## Browser automation tasks teams run

Browser automation earns its keep on work that only exists inside a website: portals with no API, dashboards with no export, and lookups that take four clicks every time. These are the tasks teams move off people's desks first.

| Task | What the browser does | Typical targets |
|---|---|---|
| Document retrieval | Logs in and downloads statements, invoices, remittance files and CSV exports | Vendor, utility, bank and payer portals with no export API |
| Status lookups | Searches a record and reads its eligibility, license, permit or case status | Insurer provider portals, state licensing boards, permit and court systems |
| Dashboard checks | Opens a logged-in dashboard and reads balances, metrics or order status | Partner portals and SaaS tools your team has accounts on |
| Multi-step searches | Runs a search, sets filters, pages through results and reads each one | Government registries, availability calendars, booking systems |
| Data entry | Types records from your database into a web form and submits them | Quote, application and registration forms, covered in automated form filling |
| Agent-driven tasks | Lets an AI agent choose the clicks at run time | Any site the agent needs to operate, through the [MCP Server](/mcp) |

## Why browser automation breaks in production

A script that works on a laptop tends to fail on the third week of a schedule. The reasons are rarely in the script.

| What breaks | What it looks like | How Zenrows handles it |
|---|---|---|
| Headless detection at login | The portal flags the session as a bot on the sign-in step | Each session runs a real Chromium with Zenrows' stealth |
| Datacenter IPs | Logins from cloud servers trigger extra checks or blocks | Zenrows' stealth sends each session through connections that look like a regular visitor's, not a cloud server's |
| Bot protection in front of the portal | A Cloudflare or Imperva challenge page loads instead of the sign-in form | Zenrows' stealth gets through Cloudflare, Imperva and similar protections before the sign-in form loads |
| Losing the session mid-task | The flow is logged out between steps and has to start again | Cookies and auth stay alive for the whole session, across pages and tabs |
| Files tied to the session | A statement link only works with the logged-in cookies, so a plain HTTP client gets the login page | Read the file inside the page with `fetch`, which sends the session cookies, and return the bytes to your script |
| Running out of machines | Each local Chromium needs memory, so 50 accounts at 6am means 50 browsers | Open one cloud session per account in parallel, with nothing to run on your own machines |

## How to automate a browser task with Zenrows

1. **Record the task by hand once.** Write down every page, field and button, and which value on the last page is the result you need.
2. **Connect your script to Zenrows.** Point Playwright's `connectOverCDP` or Puppeteer's `connect` at the Zenrows WebSocket URL. The rest of your code stays the same.
3. **Keep secrets out of the code.** Read credentials from environment variables or a secrets manager, and close the session as soon as the task ends.
4. **Log every step.** Write a run record like the sample above, and alert on runs that stop before the final step.

```python Python
# pip install playwright
import base64
import os
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp(
        "wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY"
    )
    page = browser.new_page()
    page.goto(PORTAL_LOGIN_URL)
    page.fill("#username", os.environ["PORTAL_USER"])
    page.fill("#password", os.environ["PORTAL_PASSWORD"])
    page.click("button[type=submit]")
    page.wait_for_url("**/dashboard")

    page.goto(STATEMENTS_URL)
    pdf_url = page.locator("a.statement-download").first.get_attribute("href")
    pdf_b64 = page.evaluate("""async (url) => {
        const res = await fetch(url, { credentials: "include" });
        const bytes = new Uint8Array(await res.arrayBuffer());
        let binary = "";
        for (const b of bytes) binary += String.fromCharCode(b);
        return btoa(binary);
    }""", pdf_url)
    with open("statement.pdf", "wb") as f:
        f.write(base64.b64decode(pdf_b64))
    browser.close()
```

```javascript Node.js
// A status lookup that takes a search, a filter and a results page
import puppeteer from "puppeteer";

const browser = await puppeteer.connect({
  browserWSEndpoint: "wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY",
});
const page = await browser.newPage();
await page.goto(LOOKUP_URL);
await page.select("#license-type", "contractor");
await page.type("#license-number", "LIC-004417");
await page.click("#search");
await page.waitForSelector(".result-status");
const status = await page.$eval(".result-status", (el) => el.textContent.trim());
console.log({ license: "LIC-004417", status });
await browser.close();
```

```bash CLI
npx -y @zenrows/cli init
# Check what the public status page returns before you script the clicks
zenrows fetch STATUS_PAGE_URL --wait-for ".history-table" --output markdown
zenrows fetch STATUS_PAGE_URL --screenshot --out status.png
# Give your coding agent the browser tools for the interactive steps
zenrows mcp config --client claude-code
```

```text Claude Code (MCP)
# Connect once
claude mcp add zenrows -e ZENROWS_API_KEY=YOUR_ZENROWS_API_KEY -- npx -y @zenrows/mcp

# Then ask:
Use the Zenrows browser to open LOOKUP_URL, choose "contractor" as the license type, search for license number LIC-004417, and tell me the status and expiry date shown in the result. Close the session when done.
```

## Which Zenrows product fits

| If you need to | Use | Why |
|---|---|---|
| Log in, click through steps and download files | [Browser](/products/browser) | A cloud Chromium that Playwright, Puppeteer or any CDP client drives |
| Check pages and set up an agent from a terminal | [CLI](/cli) | `zenrows fetch` shows what a page returns, and `zenrows mcp config` gives your agent the browser tools |
| Let an AI agent decide the clicks | [MCP Server](/mcp) | Claude, Cursor and other MCP clients get browser tools that run on Zenrows |
| Read public pages that need no clicks | [Fetch](/products/fetch) | One request per page, with no session to open or close |

## What success looks like

| Measure | What good looks like | How to check it |
|---|---|---|
| Run completion | Scheduled runs reach the final step and produce their result | Share of runs whose record ends with `completed` |
| Minutes per task | Each task takes the same few minutes every run | Session duration per task, from your run records or the Zenrows dashboard |
| Re-login rate | One sign-in per session, with no forced re-authentication mid-flow | Count runs that hit the login page more than once |
| Document completeness | Every expected statement or report arrives for every account and period | Compare files retrieved with the account and period list |
| Manual hours replaced | Tasks that used to need a person run on a schedule | Hours per week your team spent on these portals before and after |
| Failed step rate | Failures cluster on known steps and fall after each fix | Group failed runs by the last step recorded before the failure |

## Browser automation FAQ

### What is browser automation?

Browser automation is a program controlling a web browser the way a person would: opening pages, typing into fields, clicking, waiting for results and reading or downloading what appears. Teams use it for portals and web apps that have no API. Playwright and Puppeteer are the most common libraries for writing these scripts.

### When should I use a cloud browser instead of a scraping API?

Use a scraping API such as Fetch when the data is on a public page you can reach with one URL. Use a browser when the task needs a sign-in, a sequence of clicks, a file download, or state that carries from one page to the next. A common setup uses both: Browser for the login and the lookup, Fetch for public pages around it.

### Can I run my existing Playwright or Puppeteer scripts on Zenrows?

Yes. Replace the line that launches a local browser with a connection to wss://browser.zenrows.com?apikey=YOUR_ZENROWS_API_KEY , using connectOverCDP in Playwright or connect in Puppeteer. Selectors, waits and page logic stay as they are.

### Does browser automation work with logins and MFA?

Logins work as they do in a local browser, and the session keeps its cookies for every step of the task. For one-time codes, your script reads the code from the inbox or authenticator your team controls and types it into the field like any other value.

### Can AI agents use Zenrows for browser automation?

Yes. The Zenrows MCP Server gives Claude, Cursor, Codex and other MCP clients browser tools to navigate, click, fill and read pages. The agent decides each step at run time, which suits tasks that vary too much for a fixed script. See AI agent browser for that pattern.

### How do I schedule browser automation tasks?

Run the script from the scheduler you already use, such as cron, a CI pipeline, Airflow or a serverless function. Because the browser runs in the Zenrows cloud, the machine that triggers the job only needs your script and network access, not Chromium. Open one session per account, write a run record per task, and alert on any run that stops before its final step so a missing statement is noticed the same day.

### Is it allowed to automate a portal I have an account on?

Automating your own accounts is common, but each portal's terms decide what is permitted, and some restrict automated access. Use credentials your organization is authorized to use, keep personal and health data within your compliance rules, and ask your legal team when a portal's terms are unclear.

## Related use cases

- [AI agent browser](https://www.zenrows.com/use-cases/ai-agent-browser.md): A cloud browser your agent drives over MCP or CDP to log in, click and fill forms.
- [Public records API](https://www.zenrows.com/use-cases/public-records-api.md): Permits, violations, licenses and registry filings from city, county and state portals, returned as JSON on demand.
- [Healthcare provider data](https://www.zenrows.com/use-cases/healthcare-provider-data.md): Clinician and facility records from payer directories and hospital sites, matched on NPI and re-verified on schedule.

Start free: https://app.zenrows.com/register. Docs: https://docs.zenrows.com
