Published

- 5 min read

Mastering Browser Sessions with browser-use for Reliable AI Automations

img of Mastering Browser Sessions with browser-use for Reliable AI Automations

Why sessions matter (especially for AI agents)

If your automation opens a browser, logs in, scrapes data, and closes — great. But real-world AI agents don’t just run one task. They follow up, revisit, continue conversations, and act on prior context. That requires sessions: preserving cookies, local storage, tabs, and even the page you left open.

browser-use has rapidly become the go-to toolkit for this kind of stateful automation, with 70k+ GitHub stars and ~8k forks as of September 2025—an impressive signal of community adoption. Even better, the project is under active development, with v0.7.9 released on Sept 19, 2025.

This guide is a hands-on walkthrough of browser sessions in browser-use: how they work, how to persist them, and how to apply them to AI automation use cases like lead generation, price monitoring, and post-login workflows. We’ll also cover security, observability, and MCP integrations for multi-session orchestration.


The mental model: Browser = a session

In today’s browser-use API, Browser is an alias for BrowserSession—use whichever name feels more natural. Think of it as the living container for your cookies, storage, tabs, and pages.

Key session-related settings live on the Browser:

  • keep_alive: keep the browser running after an agent finishes.
  • user_data_dir + profile_directory: reuse your real Chrome profile (bookmarks, extensions, and existing cookies).
  • storage_state: inject a cookies/localStorage snapshot to start authenticated.
  • allowed_domains: restrict navigation scope for safety.

Quickstart: a persistent session you can reuse

   import asyncio
from browser_use import Agent, Browser, ChatOpenAI

async def main():
    browser = Browser(keep_alive=True)  # keep session alive between tasks
    await browser.start()
    agent = Agent(
        task="Open DuckDuckGo and search for 'browser-use founders'",
        browser=browser,
        llm=ChatOpenAI(model="gpt-4.1-mini"),
    )
    await agent.run(max_steps=3)
    # Chain a second task using the *same* session + tab context
    agent.add_new_task("Return the title of the first result")
    await agent.run()
    # When you're done with the long-lived session:
    await browser.kill()

asyncio.run(main())

The official docs describe chaining tasks on the same browser session and show how keep_alive=True preserves session data across runs.


Option A: Reuse your real Chrome profile (instant auth)

If you’ve already logged into sites in your daily Chrome profile, point browser-use at that profile. This preserves your existing cookies—no need to re-authenticate.

   import asyncio
from browser_use import Agent, Browser, ChatOpenAI

async def main():
    # macOS paths shown; see docs for Windows/Linux variants
    browser = Browser(
        executable_path="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
        user_data_dir="~/Library/Application Support/Google/Chrome",
        profile_directory="Default",  # e.g., "Profile 1" for a secondary profile
        keep_alive=True
    )
    agent = Agent(
        task='Open https://duckduckgo.com and search "browser-use session persistence"',
        browser=browser,
        llm=ChatOpenAI(model="gpt-4.1-mini"),
    )
    await agent.run()

asyncio.run(main())

Option B: Bring your own storage_state (portable logins)

Prefer a clean profile but want a saved login? Pass a Playwright storage state file (cookies + localStorage) to the browser:

   import asyncio, json
from browser_use import Agent, Browser, ChatOpenAI

async def main():
    # Assume you've created ./auth.json with Playwright or a prior run
    with open("./auth.json", "r") as f:
        storage = json.load(f)

    browser = Browser(storage_state=storage, keep_alive=True)
    await browser.start()

    agent = Agent(
        task="Open https://example.com/account and report the welcome text",
        browser=browser,
        llm=ChatOpenAI(model="gpt-4.1-mini"),
    )
    await agent.run()
    await browser.kill()

asyncio.run(main())

The docs recommend storage_state for login cookies where possible—cleaner than handing real passwords to the model.


Remote & cloud sessions (scalable fleets)

You can provision a cloud browser or connect to an existing CDP endpoint. This is powerful for running many long-lived sessions in parallel.

   import asyncio
from browser_use import Agent, Browser, ChatOpenAI
from browser_use.browser import ProxySettings

async def main():
    # EITHER: built-in cloud browser
    browser = Browser(use_cloud=True, keep_alive=True)

    # OR: third-party CDP (uncomment and configure)
    # browser = Browser(
    #     cdp_url="http://remote-server:9222",
    #     proxy=ProxySettings(server="http://proxy:8080",
    #                         username="user", password="pass"),
    #     keep_alive=True
    # )

    agent = Agent(task="Open example.com and extract the H1 text",
                  llm=ChatOpenAI(model="gpt-4.1-mini"),
                  browser=browser)
    await agent.run()

asyncio.run(main())

Security essentials for long-lived sessions

  • Constrain navigation with allowed_domains=[...].
  • Prefer storage_state over raw credentials.
  • Beware of disable_security=True — not recommended.

Designing a Session Pool (multi-tenant or multi-workflow)

For AI automation backends, treat sessions as first-class resources. A simple in-memory pool looks like this:

   import asyncio
from browser_use import Browser

class SessionPool:
    def __init__(self):
        self._by_tenant: dict[str, Browser] = {}

    async def get_or_create(self, tenant_id: str) -> Browser:
        if tenant_id not in self._by_tenant:
            b = Browser(keep_alive=True)
            await b.start()
            self._by_tenant[tenant_id] = b
        return self._by_tenant[tenant_id]

    async def close(self, tenant_id: str):
        b = self._by_tenant.pop(tenant_id, None)
        if b:
            await b.kill()

    async def close_all(self):
        for b in list(self._by_tenant.values()):
            await b.kill()
        self._by_tenant.clear()

This pattern lets you route tasks to the right long-lived session: perfect for CRM workflows, per-client scrapers, or customer-specific dashboards.


Chaining tasks conversationally

Agent.add_new_task() lets you append follow-ups without tearing down the browser. It’s ideal for assistants that iterate step by step.

  • Cookies persist
  • LocalStorage persists
  • Tabs persist

Observability: trace session timelines

For production systems, trace both agent reasoning and the browser session timeline. browser-use integrates with Laminar, aligning each agent step with the session recording—crucial when debugging why a session lost auth or a selector failed.


MCP: Manage sessions from AI assistants

Running browser-use as an MCP server exposes tools your AI assistant can call—including session management:

  • browser_list_sessions
  • browser_close_session
  • browser_close_all

Once you start uvx browser-use --mcp, assistants like Claude Desktop can reuse or terminate sessions on demand.


Conclusion ✅

Browser sessions are the backbone of reliable AI automations. With browser-use, you can:

  • Persist context across multiple tasks
  • Reuse Chrome profiles or portable states
  • Securely scale with cloud sessions
  • Trace and debug with observability tools
  • Orchestrate workflows with session pools

If you’re building agents that need to remember and continue, sessions are not optional — they’re essential. 🚀