Start Tiny (Hobbyists)
One request to extract markdown. Great for price alerts, personal research, and weekend projects.
From weekend scripts to enterprise pipelines: browser.city is a stealth-first browser backend with multiple integration styles.
One request to extract markdown. Great for price alerts, personal research, and weekend projects.
Humanized REST tools let you open, navigate, click, type, and screenshot over HTTP. No Playwright infra needed.
If you already run Playwright, connect to remote sessions for deterministic workflows and deep debugging.
Zero-logs posture, BYOP, labels, and sane defaults for running stealth browser workloads inside real orgs.
Fingerprints, proxies, and anti-bot defenses are handled for you. You ship outcomes, not browser plumbing.
Expose the same primitives as discoverable tools for Codex, Claude Code, Cursor, and other MCP clients.
If you want interactive steps but don’t want to run Playwright, Humanized REST tools give you a clean HTTP surface over remote sessions.
const apiKey = process.env.BROWSERCITY_API_KEY!;const opts = { method: "POST", headers: { Authorization: `Bearer ${apiKey}` } };const post = (path: string, body: unknown) => fetch("https://api.browser.city" + path, { ...opts, body: JSON.stringify(body) }).then((r) => r.json());const open = await post("/v1/do/open", { browser: "chromium", egress: { mode: "managed", proxyType: "residential", country: "US" },});const sessionId = open.result;await post("/v1/do/navigate", { sessionId, url: "https://example.com" });const md = await post("/v1/do/markdown", { sessionId });console.log(md.result);import osimport requestsapi_key = os.environ["BROWSERCITY_API_KEY"]headers = {"Authorization": f"Bearer {api_key}"}base = "https://api.browser.city"post = lambda path, payload: requests.post(base + path, headers=headers, json=payload).json()open_res = post( "/v1/do/open", { "browser": "chromium", "egress": {"mode": "managed", "proxyType": "residential", "country": "US"}, },)session_id = open_res["result"]post("/v1/do/navigate", {"sessionId": session_id, "url": "https://example.com"})md = post("/v1/do/markdown", {"sessionId": session_id})print(md["result"])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 open = await http.PostAsJsonAsync( "https://api.browser.city/v1/do/open", new { browser = "chromium", egress = new { mode = "managed", proxyType = "residential", country = "US" }, });var openJson = await open.Content.ReadFromJsonAsync<DoResponse>() ?? throw new Exception("bad response");var sessionId = openJson.result;await http.PostAsJsonAsync( "https://api.browser.city/v1/do/navigate", new { sessionId, url = "https://example.com" });var md = await http.PostAsJsonAsync( "https://api.browser.city/v1/do/markdown", new { sessionId });var mdJson = await md.Content.ReadFromJsonAsync<DoResponse>() ?? throw new Exception("bad response");Console.WriteLine(mdJson.result);public record DoResponse(string result);import java.net.URI;import java.net.http.*;var apiKey = System.getenv("BROWSERCITY_API_KEY");var auth = "Bearer " + apiKey;var http = HttpClient.newHttpClient();var openRes = http.send( HttpRequest.newBuilder() .uri(URI.create("https://api.browser.city/v1/do/open")) .header("Authorization", auth) .POST(HttpRequest.BodyPublishers.ofString( "{\"browser\":\"chromium\",\"egress\":{\"mode\":\"managed\",\"proxyType\":\"residential\",\"country\":\"US\"}}")) .build(), HttpResponse.BodyHandlers.ofString());var sessionId = extractField(openRes.body(), "result");http.send( HttpRequest.newBuilder() .uri(URI.create("https://api.browser.city/v1/do/navigate")) .header("Authorization", auth) .POST(HttpRequest.BodyPublishers.ofString( "{\"sessionId\":\"" + sessionId + "\",\"url\":\"https://example.com\"}")) .build(), HttpResponse.BodyHandlers.discarding());var mdRes = http.send( HttpRequest.newBuilder() .uri(URI.create("https://api.browser.city/v1/do/markdown")) .header("Authorization", auth) .POST(HttpRequest.BodyPublishers.ofString( "{\"sessionId\":\"" + sessionId + "\"}")) .build(), HttpResponse.BodyHandlers.ofString());System.out.println(mdRes.body());static String extractField(String json, String key) { // Use a proper JSON parser in production. This is intentionally minimal. var i = json.indexOf("\"" + key + "\""); if (i < 0) return ""; var start = json.indexOf('"', i + key.length() + 2); var end = json.indexOf('"', start + 1); return (start >= 0 && end > start) ? json.substring(start + 1, end) : "";} Free tier. No credit card. Full stealth from day one.