Quick verdict: If you want a battle-tested scraping API with deep anti-bot specialization and request-level abstractions, Scrapfly is a strong choice. If you want full browser control (Playwright sessions), plus extraction and agent tooling on top, browser.city is the broader foundation.
This is “API request” vs “browser session”
Scrapfly is built around request-level scraping. That’s great when you can express your problem as:
- make a request with the right headers, proxy, and anti-bot strategy
- return structured data
But some real workflows need a browser session:
- login and persist cookies
- multi-step navigation with state
- client-side rendering + interaction
- screenshots, PDFs, tab management
browser.city supports both:
- Request API for extraction-only jobs
- Sessions API + Playwright for full browser control
- Humanized REST tools (
/v1/do/*) for “browser actions over HTTP” - MCP server for agent clients
At a glance
| Dimension | browser.city | Scrapfly |
|---|---|---|
| Primary product | Stealth browser infrastructure | Scraping/data collection API |
| Full interaction | Yes (sessions) | Typically not (request-level) |
| Anti-bot posture | Stealth-by-default browser sessions | Anti-bot specialized scraping engine |
| Best for | Anything that needs real browser state | High-volume scraping via HTTP-style primitives |
Request API example
request.ts
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());
When to pick which
Choose Scrapfly if:
- your workload is best expressed as request-level scraping
- you want cost transparency per request and deep anti-bot specialization
Choose browser.city if:
- you need a real browser session sometimes (auth, navigation, interactive flows)
- you want to unify extraction + automation + agent tooling
- you want Playwright-native control with stealth defaults