DLogin
For AI agents

Browser profiles for AI agents

Give your agent a browser that stays signed in. Each XDLogin profile is a real Chrome on your machine with its own fingerprint, proxy, timezone and cookies. Agents reach it over MCP or the Chrome DevTools Protocol, and the local API and MCP server are on every plan, the free one included.

Why profiles

What an agent gets from a real profile

A browser started fresh for every run forgets every login, and each site sees a new visitor each time. A profile is the opposite: a browser that keeps its session, its history and an identity of its own between runs.

Sessions that persist

Log in once, by hand or from a script. Cookies, local storage and cache stay in the profile’s folder on your disk, so the next run starts signed in. Nothing is uploaded unless you turn on encrypted sync (Pro and above).

One identity per profile

A profile takes its user agent, client hints, screen, GPU string, CPU and memory from one real device model, and sends its traffic through the proxy you give it. Its timezone and language are the ones you set. Two agents in two profiles share no cookies and no canvas hash.

On your machine

Every profile is a Chrome process on your computer. The REST API, the MCP server and each profile’s DevTools endpoint listen on 127.0.0.1 only, and the browsing data stays on your disk.

No per-hour bill

XDLogin charges per plan, not per browser-hour, per session or per gigabyte of proxy traffic. The free plan has 10 profiles and the same API and MCP server as the paid plans.

Two ways in

MCP: the agent manages profiles

Your agent lists, creates, launches, navigates and stops profiles through tools, from Claude Code, Cursor, Claude Desktop, VS Code, Codex CLI or another MCP client. From desktop 3.5.8 they can also read a page and click, type and scroll in it; earlier versions can’t.

CDP: the agent works inside one

Launch a profile through the REST API, read its DevTools endpoint, and hand it to browser-use, Playwright or Puppeteer. The framework reads and clicks; the profile supplies the identity and the logins.

MCP setup

Connect your MCP client

  1. Start the server

    In XDLogin, open Settings → API & Auto and press Start MCP under MCP Server (AI Agents). It listens on http://127.0.0.1:8931 and speaks Streamable HTTP; a client set to the older SSE transport gets a 405. From then on the server starts with XDLogin, until you press Stop MCP.

  2. Set a key

    Under Authentication, press Generate, then stop and start the server so the key applies. Clients send it as Authorization: Bearer <key>, and the same key protects the REST API. Without a key, any program on your computer can drive your profiles. From 3.5.8, web pages can’t, key or not: both servers answer 403 to a request whose Origin or Host names anything but 127.0.0.1, localhost or [::1], as a website’s requests do. Scripts and MCP clients send no Origin, so they’re unaffected. The Linux build (3.5.6) and the macOS beta (3.5.5) don’t check: with no key set, a page open in your browser could send them commands.

  3. Add it to your client

    Pick your client below. Without a key, leave out the header lines.

# With an API key (Settings > API & Auto > Authentication)
claude mcp add --transport http xdlogin http://127.0.0.1:8931 --header "Authorization: Bearer YOUR-API-KEY"

# Without a key
claude mcp add --transport http xdlogin http://127.0.0.1:8931

# For every project, not just this one: --scope user before the name
claude mcp add --transport http --scope user xdlogin http://127.0.0.1:8931 --header "Authorization: Bearer YOUR-API-KEY"

# Check the connection
claude mcp list
{
  "mcpServers": {
    "xdlogin": {
      "url": "http://127.0.0.1:8931",
      "headers": {
        "Authorization": "Bearer ${env:XDLOGIN_API_KEY}"
      }
    }
  }
}
{
  "mcpServers": {
    "xdlogin": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "http://127.0.0.1:8931",
        "--header",
        "Authorization:${AUTH_HEADER}"
      ],
      "env": {
        "AUTH_HEADER": "Bearer YOUR-API-KEY"
      }
    }
  }
}
{
  "inputs": [
    {
      "type": "promptString",
      "id": "xdlogin-key",
      "description": "XDLogin API key",
      "password": true
    }
  ],
  "servers": {
    "xdlogin": {
      "type": "http",
      "url": "http://127.0.0.1:8931",
      "headers": {
        "Authorization": "Bearer ${input:xdlogin-key}"
      }
    }
  }
}
# ~/.codex/config.toml
[mcp_servers.xdlogin]
url = "http://127.0.0.1:8931"
bearer_token_env_var = "XDLOGIN_API_KEY"
  • Claude Code. Options such as --scope go before the server name. To share the setup through a project’s .mcp.json without committing the key, write the header as "Authorization": "Bearer ${XDLOGIN_API_KEY}"; Claude Code fills it in from the environment.
  • Cursor. Save as .cursor/mcp.json in a project, or ~/.cursor/mcp.json for every project. ${env:XDLOGIN_API_KEY} reads the key from your environment.
  • Claude Desktop. Its config file only starts local commands, so the mcp-remote npm package (Node.js 18 or later) bridges to XDLogin. Open Settings → Developer → Edit Config, merge this in, replace YOUR-API-KEY, then quit and reopen Claude Desktop. The key sits in env because some clients, Claude Desktop on Windows among them, split arguments at spaces. mcp-remote accepts plain http:// for 127.0.0.1 without extra flags.
  • VS Code. Save as .vscode/mcp.json. VS Code prompts for the key, so the file holds no secret.
  • Codex CLI. Add to ~/.codex/config.toml. Codex sends the value of XDLOGIN_API_KEY as the bearer token.
MCP tools

What the agent can call

Twenty-one tools on Windows (3.5.8), the same on every plan; six of them are new in 3.5.8. The MCP tools reference says what each one does, and how the Linux build (3.5.6) and the macOS beta (3.5.5) differ. Profiles are also exposed as resources (xdlogin://profiles, xdlogin://profile/{id} and xdlogin://sessions/active), so an agent can read a profile before acting on it.

  • profile_list
  • profile_get
  • profile_create
  • profile_clone
  • profile_launch
  • profile_stop
  • profile_delete
  • browser_navigate
  • browser_screenshot
  • browser_snapshot
  • browser_click
  • browser_type
  • browser_press_key
  • browser_scroll
  • browser_get_text
  • fingerprint_get
  • proxy_test
  • cookies_export
  • cookies_import
  • health
  • stats
Inside the page

browser-use and Playwright

For an agent that reads and clicks, launch the profile through the REST API (Start API in the same settings tab), wait for GET /api/profiles/{id}/connect to stop answering 409, and pass the endpoint it returns to your framework. The endpoint’s port can change with every launch, so read it each time.

browser-use

browser-use 0.13 attaches to a running Chrome with cdp_url. It needs Python 3.11 or later and an API key for the model you pick.

# pip install browser-use requests   (browser-use 0.13; set ANTHROPIC_API_KEY for the model)
import asyncio
import os
import time

import requests
from browser_use import Agent, Browser, ChatAnthropic

BASE = os.environ.get("XDLOGIN_BASE_URL", "http://127.0.0.1:31337")
KEY = os.environ.get("XDLOGIN_API_KEY")
HEADERS = {"Authorization": f"Bearer {KEY}"} if KEY else {}


def cdp_url(profile_id):
    r = requests.post(f"{BASE}/api/profiles/{profile_id}/launch", headers=HEADERS, timeout=90)
    if r.status_code != 200:
        raise RuntimeError(f"launch failed: {r.json().get('error')}")
    for _ in range(60):  # /connect answers 409 until Chrome is ready
        r = requests.get(f"{BASE}/api/profiles/{profile_id}/connect", headers=HEADERS, timeout=10)
        if r.status_code == 200:
            return r.json()["data"]["httpEndpoint"]
        time.sleep(0.5)
    raise RuntimeError(r.json().get("error"))


async def main():
    browser = Browser(
        cdp_url=cdp_url(os.environ["XDLOGIN_PROFILE_ID"]),
        headless=False,
        no_viewport=True,          # keep the profile's own window and screen size
        highlight_elements=False,  # don't draw highlight boxes into the page
        keep_alive=True,           # leave the profile running when the agent is done
    )
    agent = Agent(
        task="Open my account's order history and list the three most recent orders",
        llm=ChatAnthropic(model="claude-sonnet-4-6"),
        browser=browser,
    )
    await agent.run()


asyncio.run(main())

no_viewport stops browser-use from resizing the page to its own viewport, which would contradict the screen the profile reports. keep_alive leaves the profile open for the next run.

Playwright

Attach with connectOverCDP and work in browser.contexts()[0]: that context is the profile, with its cookies. The Playwright guide has the full script, parallel runs and the pitfalls; there are guides for Puppeteer and Selenium too.

import { chromium } from 'playwright';

const BASE = 'http://127.0.0.1:31337';
const id = process.env.XDLOGIN_PROFILE_ID;
const key = process.env.XDLOGIN_API_KEY;
const headers = key ? { Authorization: `Bearer ${key}` } : {};

await fetch(`${BASE}/api/profiles/${id}/launch`, { method: 'POST', headers });
let info;
for (let i = 0; i < 60 && !info; i++) {   // 409 until Chrome is ready
  const r = await fetch(`${BASE}/api/profiles/${id}/connect`, { headers });
  if (r.ok) info = (await r.json()).data;
  else await new Promise((res) => setTimeout(res, 500));
}
if (!info) throw new Error('No DevTools endpoint: is the profile running in Chrome?');

const browser = await chromium.connectOverCDP(info.wsEndpoint, { noDefaults: true });
const page = await browser.contexts()[0].newPage();   // signed in, with the profile's cookies
// ...hand `page` to your agent's tools...
await page.goto('https://example.com');
await browser.close();   // disconnects; the profile keeps running
Limits

What to know before you rely on it

  • The page tools are new in 3.5.8, and narrow. On Linux (3.5.6) and the macOS beta (3.5.5) no MCP tool reads a page’s text, clicks or types, and browser_screenshot returns a text description, not an image. From 3.5.8 the six page tools work on the first tab only, see nothing inside iframes, and don’t pick from select menus, upload files, hover or drag. No tool returns the DevTools endpoint. For more than that, use CDP as above.
  • Your agent needs your computer. The API and the MCP server run inside the XDLogin app, so an agent reaches profiles only while XDLogin is open and the machine is awake. Each running profile is a full Chrome process, so memory decides how many run at once.
  • A profile doesn’t change how the agent behaves. XDLogin sets what a site can read about the device. How fast the agent clicks, what it requests and how often is up to the agent. Frameworks can also add their own marks to a page, such as browser-use’s highlight boxes, which is why the example turns those off.
  • The usual fingerprint limits apply. The TLS handshake is your Chrome’s, WebGL limits and font measurements come from your hardware, and some Web Workers report this computer’s values. The test results page lists every known gap.