Full Identity Control
Control the entire browser identity, or let us handle it: fingerprint, viewport, locale, timezone, and proxy stay in sync, so every session looks like a real, legitimate user.

The stealth browser API for AI agents, scraping, and automation.
import { chromium } from 'playwright';
const { endpoint, token, id } = await fetch('https://api.browser.city/v1/sessions', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.BROWSERCITY_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ browser: 'chromium' }),
}).then((r) => r.json());
try {
const browser = await chromium.connect(endpoint, {
headers: { Authorization: `Bearer ${token}` },
});
const page = browser.contexts().at(0)!.pages().at(0)!;
await page.goto('https://google.com');
} finally {
const { summary } = await fetch(`https://api.browser.city/v1/sessions/${id}`, {
method: 'DELETE',
headers: { Authorization: `Bearer ${process.env.BROWSERCITY_API_KEY}` },
}).then((r) => r.json());
console.log('Runtime seconds:', summary?.stats?.runtimeSeconds ?? 0);
console.log('Cookies stored:', summary?.storage?.cookies?.length ?? 0);
}import os, requests
from playwright.sync_api import sync_playwright
auth = {'Authorization': f"Bearer {os.environ['BROWSERCITY_API_KEY']}"}
session = requests.post(
'https://api.browser.city/v1/sessions', headers=auth, json={'browser': 'chromium'}
).json()
endpoint = session['endpoint']
token = session['token']
session_id = session['id']
playwright = None
try:
playwright = sync_playwright().start()
browser = playwright.chromium.connect(
endpoint,
headers={'Authorization': f'Bearer {token}'},
)
page = browser.contexts[0].pages[0]
page.goto('https://google.com')
finally:
try:
deleted = requests.delete(f'https://api.browser.city/v1/sessions/{session_id}', headers=auth).json()
summary = deleted.get('summary') or {}
print('Runtime seconds:', (summary.get('stats') or {}).get('runtimeSeconds', 0))
cookies = (summary.get('storage') or {}).get('cookies') or []
print('Cookies stored:', len(cookies))
finally:
if playwright:
playwright.stop()using Microsoft.Playwright;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Collections.Generic;
var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new(
"Bearer", Environment.GetEnvironmentVariable("BROWSERCITY_API_KEY"));
var session = await (await http.PostAsJsonAsync(
"https://api.browser.city/v1/sessions", new { browser = "chromium" }))
.Content.ReadFromJsonAsync<Session>();
var (id, endpoint, token) = session!;
IPlaywright? pw = null;
try {
pw = await Playwright.CreateAsync();
var browser = await pw.Chromium.ConnectAsync(endpoint, new() {
Headers = new() { ["Authorization"] = $"Bearer {token}" }
});
var page = browser.Contexts[0].Pages[0];
await page.GotoAsync("https://google.com");
} finally {
try {
if (session is not null) {
var deleted = await (await http.DeleteAsync($"https://api.browser.city/v1/sessions/{id}"))
.Content.ReadFromJsonAsync<DeleteSessionResponse>();
Console.WriteLine($"Runtime seconds: {deleted?.Summary?.Stats?.RuntimeSeconds ?? 0}");
Console.WriteLine($"Cookies stored: {deleted?.Summary?.Storage?.Cookies?.Count ?? 0}");
}
} finally {
pw?.Dispose();
}
}
record Session(string Id, string Endpoint, string Token);
record DeleteSessionResponse(DeleteSessionSummary? Summary);
record DeleteSessionSummary(DeleteSessionStats? Stats, DeleteSessionStorage? Storage);
record DeleteSessionStats(double? RuntimeSeconds);
record DeleteSessionStorage(List<object>? Cookies);import com.fasterxml.jackson.databind.ObjectMapper;
import com.microsoft.playwright.*;
import java.net.URI;
import java.net.http.*;
import java.util.Map;
import java.util.List;
public class Quickstart {
public static void main(String[] args) throws Exception {
var key = System.getenv("BROWSERCITY_API_KEY");
var http = HttpClient.newHttpClient();
var json = new ObjectMapper();
var req = HttpRequest.newBuilder(URI.create("https://api.browser.city/v1/sessions"))
.header("Authorization", "Bearer %s".formatted(key))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("{\"browser\":\"chromium\"}"))
.build();
var created = json.readValue(http.send(req, HttpResponse.BodyHandlers.ofString()).body(), Session.class);
var id = created.id();
var endpoint = created.endpoint();
var token = created.token();
Playwright pw = null;
try {
pw = Playwright.create();
var browser = pw.chromium().connect(endpoint,
new BrowserType.ConnectOptions().setHeaders(Map.of("Authorization", "Bearer %s".formatted(token))));
var page = browser.contexts().get(0).pages().get(0);
page.navigate("https://google.com");
} finally {
try {
var deleteResponse = http.send(HttpRequest.newBuilder(URI.create("https://api.browser.city/v1/sessions/" + id))
.header("Authorization", "Bearer %s".formatted(key)).DELETE().build(), HttpResponse.BodyHandlers.ofString());
if (deleteResponse.statusCode() / 100 != 2) {
throw new RuntimeException("Delete failed: " + deleteResponse.statusCode());
}
var deleteBody = deleteResponse.body();
if (deleteBody.strip().startsWith("{")) {
var deleted = json.readValue(deleteBody, Map.class);
Object runtimeSeconds = 0;
int cookieCount = 0;
if (deleted.get("summary") instanceof Map<?, ?> summary) {
if (summary.get("stats") instanceof Map<?, ?> stats && stats.get("runtimeSeconds") != null) {
runtimeSeconds = stats.get("runtimeSeconds");
}
if (summary.get("storage") instanceof Map<?, ?> storage && storage.get("cookies") instanceof List<?> cookies) {
cookieCount = cookies.size();
}
}
System.out.println("Runtime seconds: " + runtimeSeconds);
System.out.println("Cookies stored: " + cookieCount);
}
} finally {
if (pw != null) pw.close();
}
}
}
record Session(String id, String endpoint, String token) {}
}Real browsers, full identity control, public pricing, and private-by-default sessions. We run the infrastructure so you can focus on your agents.
Control the entire browser identity, or let us handle it: fingerprint, viewport, locale, timezone, and proxy stay in sync, so every session looks like a real, legitimate user.
Skip the boot sequence. Browsers are standing by before you ask, so your agents start interacting with the web immediately.
Pick your browser size and proxy type, and pay only for what you use. We accept credit cards and crypto (Bitcoin, ETH, USDC).
We don't record your sessions. No content logs, no URL history, no stored page content—by default. The fine print lives in our Zero-Logs Policy.
One journey across the live web: find relevant pages, read them efficiently, open a real browser when interaction is required, and act on the page.
Search the live web for relevant pages before opening a browser. Plan your agent’s next move from real results.
Turn any URL into clean markdown with the Request API. The fastest path from a page to your data pipeline.
Open a real cloud browser when interaction is required. Drop-in Playwright compatibility — just change the endpoint.
Click, type, fill forms, and extract content over Humanized REST or MCP — every action behaves like a real human.
Connect via Playwright, REST API, or MCP. Works with every agent framework.
Full browser infrastructure — from coherent identity controls to proxy routing to content extraction.
Take control of the entire browser identity: supply your own Apify-compatible fingerprints, or let us automatically generate a perfectly aligned identity for you.
Our proprietary browser behaves like a real person on a real device, so CAPTCHAs rarely appear—proven on sites protected by Google, Cloudflare, and DataDome.
Sessions are ready in roughly 100ms for general requests, and roughly 150ms when you supply a detailed fingerprint.
First-class mobile support. Render pixel-perfect Android and tablet sessions complete with matching viewports and touch events.
Whether you use our native Model Context Protocol (MCP) server or simple REST API, every automated action behaves exactly like a real human.
Keep your existing Playwright scripts. Just change your connection endpoint to browser.city and run your code unchanged.
Route traffic through managed datacenter, residential, or mobile proxies. Or bring your own proxies on paid plans.
Top up your account balance instantly with Bitcoin, Ethereum, or USDC. No credit card or bank account required.
Identity, network, privacy, and cost stay under your control on every request — and the same platform is reachable through whichever interface fits your workload.
Clear, dimensional pricing for compute and proxy traffic. Start for free with our managed datacenter proxies, or upgrade to unlock residential, mobile, and bring-your-own-proxy (BYOP) networks.
Constrained catalog tier for testing and small workloads.
Monthly commitment tier with credits and higher limits.
Monthly commitment tier with credits and higher limits.
Monthly commitment tier with credits and higher limits.
Monthly commitment tier with credits and higher limits.
Monthly commitment tier with credits and higher limits.
Custom concurrency, Enterprise SSO, SLA, dedicated infrastructure, network access, and volume commitments.
100% of your paid monthly tier converts into usage credits. Need more? Just top up. Paid plans unlock global residential and mobile proxies, plus a $1/GB fee for BYOP traffic.
Browser size metered by session time.
| Size | Resources | Price |
|---|---|---|
| Compute M | 2 vCPU / 2 GB | $0.06/hr |
| Compute L | 4 vCPU / 4 GB | $0.12/hr |
Managed and BYOP traffic by customer-facing network class.
| Network | Price |
|---|---|
| Datacenter | $1/GB |
| Residential | $6/GB |
| Mobile | $8/GB |
| Premium Residential | $12/GB |
| BYOP fee | $1/GB |
Charged once per successfully cleared logical challenge.
| Class | Price |
|---|---|
| Standard CAPTCHA | $0.01/clear |
| Premium CAPTCHA | $0.10/clear |
A safer baseline for your agents: clear controls, strict privacy defaults, and public pricing you can review before you write a single line of code.
We're in private beta — request access and we'll get you set up. Private sessions by default.