Quick verdict: If all you need is “turn URLs into LLM-ready markdown/JSON,” Firecrawl is purpose-built for that. If you need interactive workflows (logins, multi-step navigation, screenshots, stable sessions) while still having a fast extraction path, browser.city covers both layers.
Same output goal, different underlying product
Firecrawl is an extraction API. It’s optimized for:
- speed to “markdown output”
- RAG ingestion pipelines
- programmatic crawling at scale
browser.city is browser infrastructure, but it includes a Request API that covers a large slice of extraction workloads.
At a glance
| Dimension | browser.city | Firecrawl |
|---|---|---|
| Primary product | Remote stealth browsers | Extraction API (LLM-ready output) |
| Interaction | Yes (Playwright sessions, Humanized REST, MCP tools) | Limited (depends on product features) |
| Extraction | Request API → markdown | Core focus |
| Best for | Mixed workloads: scrape + automate + agent control | High-throughput extraction pipelines |
If you only need extraction, start with the Request API
browser.city “URL → markdown” in one call:
const apiKey = process.env.BROWSERCITY_API_KEY!;const opts = { method: "POST", headers: { Authorization: `Bearer ${apiKey}` } };const res = await fetch("https://api.browser.city/v1/requests", { ...opts, body: JSON.stringify({ url: "https://example.com", markdown: true }),}).then((r) => r.json());console.log(res.content);import osimport requestsapi_key = os.environ["BROWSERCITY_API_KEY"]res = requests.post( "https://api.browser.city/v1/requests", headers={"Authorization": f"Bearer {api_key}"}, json={"url": "https://example.com", "markdown": True},).json()print(res["content"])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/requests", new { url = "https://example.com", markdown = true });Console.WriteLine(await res.Content.ReadAsStringAsync());import java.net.URI;import java.net.http.*;var apiKey = System.getenv("BROWSERCITY_API_KEY");var http = HttpClient.newHttpClient();var body = "{\"url\":\"https://example.com\",\"markdown\":true}";var req = HttpRequest.newBuilder() .uri(URI.create("https://api.browser.city/v1/requests")) .header("Authorization", "Bearer " + apiKey) .POST(HttpRequest.BodyPublishers.ofString(body)) .build();var res = http.send(req, HttpResponse.BodyHandlers.ofString());System.out.println(res.body());
If you hit targets that require real interaction (cookie banners, dynamic content, multi-step flows), use sessions and connect with Playwright.
When to pick which
Choose Firecrawl if:
- extraction is the whole product requirement
- you don’t need long-running interactive sessions
- you want an “LLM-ready by default” pipeline with minimal orchestration code
Choose browser.city if:
- you need a real browser session sometimes (auth, navigation, screenshots)
- you want one vendor for both extraction and automation
- you want agent tooling via MCP (Codex/Claude Code/etc.)