AI Web Agents + Multi-Account Browser Profiles: Browser-Use CDP Guide (2026)

11 min read

You point an AI web agent at a recurring task: checking order status across several storefronts you operate, filling in a weekly report in a client's dashboard, or running a QA pass through your own checkout. The agent plans well. But every run starts in a throwaway browser with no saved login, no stored session and a default headless configuration, so each run begins by logging in again, hitting a verification step and losing the thread.

The fix is not a smarter model. It is giving the agent a browser that persists: a profile with its own cookies, storage, proxy and identity parameters, which a person can sign into once and an agent can then pick up.

This guide is for tasks you are permitted to automate, such as testing, QA, checks on public pages, and workflows inside accounts you own or manage with permission. If a site's terms forbid automated access, use its official API instead.

What We're Building With AI Web Agents

By the end of this tutorial, you'll have a working browser-use agent (or similar LLM web agent) that:

  1. Launches a JustBrowser profile via its local REST API
  2. Connects to that profile over Chrome DevTools Protocol
  3. Runs your agent tasks inside a browser whose state persists between runs
  4. Handles the profile lifecycle (start, connect, stop) so agents can work across sessions

Your agent code stays the same. You are changing which browser it talks to. The LLM keeps making decisions; the browser keeps the state.

Prerequisites

  • Python 3.10+ with browser-use installed (pip install browser-use)
  • An LLM API key (OpenAI, Anthropic, or compatible)
  • JustBrowser ($9.99/mo — one plan) — the REST API is available from day one of the 7-day trial
  • Basic familiarity with async Python and browser automation
  • At least one profile created in JustBrowser

If you're coming from Playwright or Puppeteer setups, the Playwright/Puppeteer guide covers the profile concepts. This tutorial focuses on the agent integration layer.

Step 1: Create Your Agent Profile in JustBrowser

Before any code, create a profile through the JustBrowser desktop app. Each profile stores:

  • A full identity configuration (canvas, WebGL, fonts, audio, timezone, screen, 40+ parameters)
  • Proxy settings (optional: HTTP/HTTPS/SOCKS5)
  • Cookies and localStorage from earlier sessions
  • A unique profile ID you'll reference via API

Keep the identity ordinary and internally consistent: a timezone that matches the proxy's location, a screen size that fits the operating system, a GPU string that fits the hardware you are presenting. The reason is practical. Mismatched values cause odd rendering and break sites that rely on them, which looks like an agent bug when it is a profile bug.

The WebGL fingerprinting breakdown covers what each value means.

Note your profile ID from the profile settings panel. You'll need it.

Step 2: Launch the Profile via REST API

JustBrowser's REST API runs locally when the app is open, bound to 127.0.0.1 on port 36542 by default (configurable in the app).

import httpx
import asyncio

API_BASE = "http://127.0.0.1:36542/api/v1"
API_TOKEN = "your-token-here"  # from the AI page in the app
HEADERS = {"Authorization": f"Bearer {API_TOKEN}"}  # pass headers=HEADERS on every request
PROFILE_ID = "your-profile-id-here"

async def launch_profile(profile_id: str) -> dict:
    """Launch a profile and return connection info."""
    async with httpx.AsyncClient() as client:
        response = await client.post(
            f"{API_BASE}/profiles/{profile_id}/start",
            headers=HEADERS,
            json={"headless": False}  # the API starts headless unless told otherwise
        )
        response.raise_for_status()
        return response.json()["data"]  # includes cdp_url — use profile_data["cdp_url"] as the CDP endpoint

What happens here: we POST to the start endpoint, JustBrowser starts a Chromium instance with your saved profile configuration, and we get back connection details. The cdp_url is a standard CDP WebSocket URL, so any framework that speaks Chrome DevTools Protocol can connect. Note that POST /profiles/{id}/start starts a headless browser unless the body says {"headless": false}.

If you get connection refused, JustBrowser isn't running. The API only works when the app is open.

Step 3: Connect browser-use to the Profile

browser-use typically launches its own Chromium instance. We override that:

from browser_use import Agent, Browser, BrowserConfig
from langchain_openai import ChatOpenAI

async def create_profile_agent(task: str):
    # Launch the profile
    profile_data = await launch_profile(PROFILE_ID)
    cdp_url = profile_data["cdp_url"]

    # Configure browser-use to connect to the existing browser
    browser_config = BrowserConfig(
        cdp_url=cdp_url,  # Connect to our JustBrowser profile
        headless=False
    )

    browser = Browser(config=browser_config)

    # Create the agent with your preferred LLM
    llm = ChatOpenAI(model="gpt-4o")

    agent = Agent(
        task=task,
        llm=llm,
        browser=browser
    )

    return agent, browser

That is the whole integration. browser-use connects to the already-running profile instead of launching a fresh Chromium. The LLM makes decisions, the profile executes them, and the session keeps its cookies, storage and proxy.

Step 4: Run Your Agent Task

async def run_agent_task(task: str):
    agent, browser = await create_profile_agent(task)

    try:
        result = await agent.run()
        return result
    finally:
        await browser.close()  # only disconnects; the profile keeps running
        await stop_profile(PROFILE_ID)

async def stop_profile(profile_id: str):
    """Stop the profile when done."""
    async with httpx.AsyncClient() as client:
        await client.post(f"{API_BASE}/profiles/{profile_id}/stop", headers=HEADERS)

# Example usage: a task on a page you are allowed to automate
asyncio.run(run_agent_task(
    "Open our staging storefront, search for 'mechanical keyboard', and list the top 3 results with prices"
))

The agent runs against a browser with a stable identity: the same canvas output, the same WebGL renderer and the same font set every session. Remember that browser.close() only disconnects; the profile keeps running until you call POST /profiles/{id}/stop.

Step 5: Handle Multiple Agents in Parallel

If you're running several agents at once, each needs its own profile:

class AgentProfilePool:
    def __init__(self, profile_ids: list[str]):
        self.available = list(profile_ids)
        self.active = {}

    async def acquire(self) -> tuple[str, str]:
        """Get an available profile, return (profile_id, cdp_url)."""
        if not self.available:
            raise RuntimeError("No profiles available — create more in JustBrowser")

        profile_id = self.available.pop(0)

        async with httpx.AsyncClient() as client:
            response = await client.post(
                f"{API_BASE}/profiles/{profile_id}/start",
                headers=HEADERS,
                json={"headless": False}
            )
            response.raise_for_status()
            data = response.json()["data"]

        cdp_url = data["cdp_url"]
        self.active[profile_id] = cdp_url
        return profile_id, cdp_url

    async def release(self, profile_id: str):
        """Stop profile and return it to pool."""
        if profile_id in self.active:
            async with httpx.AsyncClient() as client:
                await client.post(f"{API_BASE}/profiles/{profile_id}/stop", headers=HEADERS)
            del self.active[profile_id]
            self.available.append(profile_id)

# Usage
pool = AgentProfilePool(["profile-1", "profile-2", "profile-3"])

async def run_parallel_agents(tasks: list[str]):
    async def run_one(task):
        profile_id, cdp_url = await pool.acquire()
        try:
            browser_config = BrowserConfig(cdp_url=cdp_url, headless=False)
            browser = Browser(config=browser_config)
            agent = Agent(task=task, llm=ChatOpenAI(model="gpt-4o"), browser=browser)
            result = await agent.run()
            return result
        finally:
            await pool.release(profile_id)

    results = await asyncio.gather(*[run_one(t) for t in tasks])
    return results

Now several agents can run concurrently, each with isolated cookies, storage and browsing context. One agent's session never touches another's.

Each profile is a full browser process, and memory adds up fast. Ten parallel agents means ten browsers, and heavy single-page apps cost more than static pages. Measure RAM and CPU with two or three profiles, then scale the count to the machine you have.

Common Errors and How to Fix Them

Error: playwright._impl._errors.Error: Browser has been closed

Cause: The profile crashed or was stopped before the agent finished.

Fix: Check if JustBrowser is still running. If the app closes, all profiles stop. For long-running agents, add a keep-alive ping or wrap operations in try/except to detect and handle profile death gracefully.

Error: Agent completes but the page shows a verification step

Cause: The site is asking for a check, often because of a first login from a new location, a proxy it doesn't recognise, or automated activity it wants to confirm.

Fix: Check the proxy and its location against the profile's timezone. Complete the verification yourself in the profile, since the session persists; don't hand it to the agent. If the check keeps coming back on automated runs, take that as the site's answer: use its official API, or, on a site you run, allow your own test traffic in its settings.

For ad-related workflows where you need to verify traffic quality, ClickzProtect helps identify fraudulent click patterns, which is useful when your agents interact with paid media.

Error: httpx.ConnectError: Connection refused

Cause: JustBrowser isn't running or the API port has been changed from the default 36542 in the app's settings.

Fix: Launch JustBrowser. Open the app's API/AI tab and check the actual port and Bearer token. Also verify nothing else is bound to that port, and that the token in your code matches the one shown in the app.

Error: Profile launches but the agent sees a "fresh session"

Cause: You are launching a new profile instead of an existing one that already holds the login.

Fix: Create profiles in JustBrowser's GUI first, sign in by hand where the task needs a login, and note their IDs. The agent then inherits the saved session. The multi-account guide for affiliate teams covers working across accounts you are allowed to hold.

Error: Agent works locally but fails on a server

Cause: The server is probably running headless, and a headless session has no real window, so its screen and viewport follow headless defaults. If the "server" is a Linux VM, there is a bigger problem: JustBrowser ships for Windows x64 and macOS (Apple Silicon) only. There's no Linux build to run.

Fix: Keep the browser on a machine that has a real desktop session, a Windows x64 box or an Apple Silicon Mac, and run it headed, with your agent code on that same host talking to the local API. A dedicated always-on Windows machine is the boring answer.

# headed mode, on a host with a real display session
await client.post(
    f"{API_BASE}/profiles/{profile_id}/start",
    headers=HEADERS,
    json={"headless": False}
)

You lose the tidiness of a headless Linux container, and gain a browser with a normal window and screen.

Next Steps

You've got AI agents running inside persistent profiles. Where to go from here:

Test before production. Point your agent at a page you control first, and check the profile's values with the JustBrowser fingerprint checker or BrowserLeaks. If the values are consistent and ordinary, you're ready. If they show a software renderer or mismatched timezone, something is misconfigured. For the network-layer side, the TLS fingerprinting explainer has the details.

Log in once, run many times. Sign in to the accounts the task needs by hand, inside the profile, then let the agent continue from the saved session. That is simpler and more reliable than scripting logins.

Proxy matching. A profile set to Seattle's timezone shouldn't route through a Frankfurt IP; the mismatch causes confusing behaviour on sites that localise. Match your proxies to the profile. The ISP proxy setup guide covers configuration.

Multi-agent orchestration. For production agent systems, you'll want proper profile pool management, health checks, and failure handling. Consider JustAnalytics to track agent success rates and see which tasks hit verification pages. For email-based agent workflows (notification handling), JustEmails provides inboxes your agent can read over IMAP.

The 7-day trial is how you validate the integration: full access, REST API included, nothing held back for a higher tier. After that it's $9.99/month, or $99.99/year, for unlimited profiles. A card is required up front, but cancel inside the seven days and you're not charged. One flat price either way.

FAQ

Why use a persistent browser profile for an AI web agent?

Frameworks like browser-use usually launch a fresh, throwaway Chromium for every run. That means no saved logins, no cookies, no stored state and a default headless configuration. A persistent profile keeps cookies, localStorage and logged-in sessions between runs, has its own proxy and identity parameters, and can be shared with teammates, so the agent picks up where the last run stopped.

Can I connect browser-use to a JustBrowser profile instead of stock Chromium?

Yes. browser-use and similar agent frameworks connect via Chrome DevTools Protocol. JustBrowser exposes a CDP endpoint for each launched profile through its local REST API. You launch a profile, grab the WebSocket URL, and pass it to browser-use as the connection target instead of letting the framework launch its own browser.

Does this work with other LLM agent frameworks?

Any agent that controls a browser through Playwright, Puppeteer or CDP can connect to a profile, including LangChain browser tools and function-calling agents you write yourself. The browser profile handles state and identity; the LLM handles the decision layer. They are separate concerns that compose cleanly.

What happens to agent sessions when profiles have existing cookies and history?

The agent inherits whatever state exists in the profile: cookies, localStorage, browsing history and logged-in sessions. That is useful for workflows on accounts you own, because you can log in once by hand and let the agent continue from the signed-in state.


Try JustBrowser

A multi-account browser for teams, built on a custom Chromium engine with native C++ integration, not an extension. Real C++ engine patches at the canvas / WebGL / audio / font / screen layer, across 40+ identity parameters. Each profile keeps its own cookies, storage and proxy, and teammates can share profiles. REST API for Playwright, Puppeteer, Selenium. $9.99/month or $99.99/year. 7-day free trial, card required — cancel any time in the seven days and you are not charged. Unlimited profiles.

Get started → · How it differs from Multilogin / GoLogin / AdsPower

Tags
  • ai-web-agents
  • browser-use
  • cdp-integration
  • multi-account-browser
  • llm-automation
  • buildinpublic
  • saasstudio
  • aiworkforce
  • buildwithclaude

Ready to manage multiple accounts?

Seven days free, then $9.99/month — one plan, everything included.

We'd like to use Google Analytics, a Google service, to understand how our website is used. It sets two cookies in your browser and runs only if you click Accept. You can change your choice at any time with Cookie settings. Cookie Policy

Sign-in cookies and the cookie that remembers this choice are always on; the website needs them to work.

Google Analytics, a Google service, helps us understand how our website is used. It sets two cookies, _ga and _ga_TVZHQ99TZW. It is now onoff in this browser. If your browser sends a Global Privacy Control or Do Not Track signal, it stays off. Cookie Policy