Quick verdict: This isn’t a pure head-to-head. Browser Use is primarily an agent framework (plus hosted execution). browser.city is browser infrastructure. Many teams use both: Browser Use for the agent loop, browser.city for the stealth browser backend.
Different layers of the stack
Think of the stack as three layers:
- Agent loop (planning, tool selection, retries, memory)
- Browser tools (navigate, click, fill, screenshot, extract)
- Browser runtime + stealth + egress (fingerprints, proxies, anti-bot)
Browser Use focuses on (1) and part of (2).
browser.city focuses on (2) and (3):
- MCP server exposes browser tools to any client
- Sessions API provides Playwright-compatible browsers
- Request API provides extraction without orchestration
At a glance
| Dimension | browser.city | Browser Use |
|---|---|---|
| Primary product | Browser infrastructure | Agent framework + hosted agent execution |
| Control style | Deterministic APIs (Playwright/REST/MCP tools) | Agentic abstraction + steps |
| Stealth | Default | Varies by tier / setup |
| Best for | Teams building agents and scrapers that need reliable infra | Teams that want agent loop primitives and an OSS ecosystem |
How to combine them (common pattern)
- Use Browser Use to decide what to do next.
- Use browser.city to provide the actual browser and extraction primitives.
If your agent framework can talk to Playwright, you can create a browser.city session and connect using the returned endpoint/token header.
import { chromium } from "playwright";const apiKey = process.env.BROWSERCITY_API_KEY!;const opts = { method: "POST", headers: { Authorization: `Bearer ${apiKey}` } };const session = await fetch("https://api.browser.city/v1/sessions", { ...opts, body: JSON.stringify({ browser: "chromium" }),}).then((r) => r.json());const browser = await chromium.connect(session.endpoint, { headers: { Authorization: `Bearer ${session.token}` },});import osimport requestsfrom playwright.sync_api import sync_playwrightapi_key = os.environ["BROWSERCITY_API_KEY"]session = requests.post( "https://api.browser.city/v1/sessions", headers={"Authorization": f"Bearer {api_key}"}, json={"browser": "chromium"},).json()with sync_playwright() as p: browser = p.chromium.connect( session["endpoint"], headers={"Authorization": f"Bearer {session['token']}"}, )using Microsoft.Playwright;using System.Net.Http.Headers;using System.Net.Http.Json;var apiKey = Environment.GetEnvironmentVariable("BROWSERCITY_API_KEY")!;var http = new HttpClient();http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);var res = await http.PostAsJsonAsync( "https://api.browser.city/v1/sessions", new { browser = "chromium" });var session = await res.Content.ReadFromJsonAsync<Session>() ?? throw new Exception("bad response");using var pw = await Playwright.CreateAsync();var browser = await pw.Chromium.ConnectAsync(session.endpoint, new() { Headers = new Dictionary<string, string> { ["Authorization"] = $"Bearer {session.token}", },});public record Session(string endpoint, string token);import com.microsoft.playwright.*;import java.net.URI;import java.net.http.*;import java.util.regex.*;var apiKey = System.getenv("BROWSERCITY_API_KEY");var http = HttpClient.newHttpClient();var res = http.send( HttpRequest.newBuilder() .uri(URI.create("https://api.browser.city/v1/sessions")) .header("Authorization", "Bearer " + apiKey) .POST(HttpRequest.BodyPublishers.ofString("{\"browser\":\"chromium\"}")) .build(), HttpResponse.BodyHandlers.ofString());var endpoint = extractJsonString(res.body(), "endpoint");var token = extractJsonString(res.body(), "token");try (var pw = Playwright.create()) { pw.chromium().connect( endpoint, new BrowserType.ConnectOptions().setHeaders( java.util.Map.of("Authorization", "Bearer " + token)));}static String extractJsonString(String json, String key) { var m = Pattern.compile("\"" + key + "\"\\s*:\\s*\"([^\"]+)\"").matcher(json); if (!m.find()) throw new RuntimeException("missing " + key); return m.group(1);}
When to pick which
Choose Browser Use if:
- you want an OSS-first agent framework and community-driven patterns
- you want higher-level agent abstractions (steps, skills, workflows)
Choose browser.city if:
- you want infrastructure primitives you can plug into any agent/tooling stack
- you need stealth-by-default and strong egress/fingerprint control
- you want Request API for cheap “URL → markdown” flows