Prompt
How do I set up a browser automation platform for an agent that reads pages, clicks through workflows, and handles logins?
Latest observation
A solid browser-automation setup for an agent usually has 5 parts:
- A browser runtime
- An automation library
- A page-interpretation layer
- A login/session strategy
- A safety/observability layer
Here’s a practical way to build it.
1) Pick the automation stack
Common choices
- Playwright: best default for modern web apps, reliable, supports Chromium/Firefox/WebKit
- Puppeteer: good if you only need Chromium
- Selenium: widest ecosystem, but usually less ergonomic for agents
Recommended default
Use Playwright unless you have a specific reason not to. It handles:
- navigation
- selectors
- downloads/uploads
- frames
- multiple tabs
- cookies/storage state
- headless or headed runs
2) Decide how the agent “sees” pages
Your agent needs a representation of the page. Usually you combine:
A. DOM extraction
Pull:
- visible text
- headings
- buttons/links/forms
- input values
- ARIA labels
- metadata like URL, title
This is usually the most useful signal for an LLM agent.
B. Screenshot / visual input
Useful for:
- CAPTCHA-like visual issues
- layout-dependent flows
- confirming what the user would see
C. Structured element map
Build a list of interactable elements:
- tag
- text
- role
- aria-label
- selector
- bounding box
- enabled/disabled
- visible/hidden
This lets the agent choose actions more reliably than relying on raw HTML.
3) Build the browser control loop
A standard agent loop looks like:
- Open page
- Extract page state
- Ask the agent for the next action
- Execute the action
- Observe result
- Repeat until task complete or fails
Actions you should support
goto(url)click(selector or element_id)type(selector, text)press(key)select(option)wait_for(selector/network/navigation)extract_text()scroll()back()open_tab()close_tab()
Important
Keep execution deterministic:
- agent proposes action
- your controller validates it
- browser executes it
- you capture outcome/errors
Don’t let the model directly manipulate the browser without guardrails.
4) Handle logins properly
Login is usually the hardest part. Best practice is to separate interactive login setup from normal agent runs.
Recommended pattern: persistent authenticated profile
- Run a real browser once
- Log in manually
- Save session state:
- cookies
- localStorage
- sessionStorage if needed
- Reuse that state in future runs
In Playwright this is commonly done with storage state.
Why this is better
- avoids re-authenticating every run
- reduces MFA friction
- makes workflows more stable
Handling MFA
If MFA is required:
- support a human-in-the-loop step
- pause the agent
- let a human complete login
- resume and persist state afterward
Avoid
- storing passwords in prompts
- asking the model to type secrets if you can avoid it
- trying to bypass authentication challenges
5) Use a browser session manager
If you expect multiple tasks/users, add a session layer that manages:
- browser instances
- contexts/profiles
- per-user cookies and storage
- timeout/restart logic
- tab lifecycle
Good structure
- BrowserManager: launches browser
- ContextManager: creates isolated user sessions
- PageAdapter: wraps page actions and observations
- TaskRunner: executes agent plans
- SecretManager: retrieves credentials securely
- AuditLogger: records actions and failures
6) Create a page adapter for the agent
A useful adapter provides a compact, structured snapshot like:
{
"url": "https://example.com/dashboard",
"title": "Dashboard",
"text": ["Welcome back", "Invoices", "Settings"],
"elements": [
{"id": 1, "role": "button", "text": "New Invoice", "selector": "button:has-text('New Invoice')"},
{"id": 2, "role": "link", "text": "Settings", "selector": "a:has-text('Settings')"},
{"id": 3, "role": "textbox", "label": "Search", "selector": "input[aria-label='Search']"}
]
}
This is much easier for an agent to reason about than raw HTML.
7) Add reliability features
You’ll want:
- retries for transient failures
- explicit waits for navigation / element visibility
- page reload recovery
- timeouts
- screenshot on error
- console/network logging
- detection of redirects and expired sessions
Especially useful
- auto-retry once after a stale element / detached node error
- if session expired, pause and re-login instead of failing immediately
8) Security and compliance
If the agent handles logins:
- store credentials in a secret manager
- never put passwords in logs
- limit which sites/actions the agent can access
- use allowlists for domains
- isolate sessions per user
- redact sensitive page content before sending it to an LLM when possible
If this is for a production system, also consider:
- audit trails
- consent
- rate limits
- anti-abuse protections
9) A practical architecture
Simple version
- Node.js or Python
- Playwright
- LLM agent
- Persistent storage state files
- Structured page extractor
- Action executor
Example flow
- Start Playwright browser context
- Load saved auth state
- Navigate to target page
- Extract page snapshot
- Send snapshot to agent
- Agent returns next action
- Controller validates and executes action
- Repeat
- Save updated state if needed
10) Minimal Playwright approach
What to implement first
open_browser()load_auth_state()extract_page_snapshot()execute_action()save_auth_state()
If you want, I can give you:
- a Python Playwright starter template
- a Node.js starter template
- a recommended agent loop architecture
- or a login/session management example
Observation history
Unlock observation history
Create a free Obsurfable account to unlock historical responses, model comparisons, and deeper brand intelligence.
How did Obsurfable measure this prompt?
Obsurfable records AI answers to buyer-style prompts in its research corpus (1 observation for this page). Metrics are distributions over observations, not a single static ranking.
Which AI systems does Obsurfable collect answers from?
OpenAI, ChatGPT, Google, Gemini, Google AI Mode, Anthropic, Claude, Perplexity, Grok, DeepSeek, Mistral, Copilot, and Meta AI.