cdpfleet / Browsers / Camoufox
Firefox family · Based on Firefox source; not affiliated with Mozilla
Camoufox, one socket away.
Camoufox is an anti-detect browser based on Firefox source (not affiliated with Mozilla) that spoofs a complete, consistent fingerprint at the engine level. Set its identity with launch options (below) rather than with client-side newContext settings, which would fight the injected identity. A proxy is required, and by default the identity is matched to the proxy's location. POST /session is an alias for this browser.
- /camoufox/sessionlaunch endpoint
- 1.60Playwright client
- 2threads (headful default)
Why Camoufox
- An anti-detect browser based on Firefox source (not affiliated with Mozilla) that builds a complete, consistent fingerprint at the engine level.
- Set the identity at launch — OS, locale, screen, fonts, WebGL, human-like cursor — and match it to the proxy's location by default. A
proxyis required. - Pinned previous versions and persistent profiles that keep the same device between sessions.
Versions on the fleet now
One build per release, updated on the fleet as new versions ship.
Pin a previous major with {"version": "…"} — the reference page lists the ones available now.
New majors are announced on /docs/updates.
Launch it
One HTTPS call to POST /camoufox/session returns a WebSocket URL; connect to it with Playwright's firefox.connect() (client 1.60). A headless session takes 1 thread, a headful one 2.
// npm install [email protected]
// Browsers run on cdpfleet, so no `npx playwright install` is needed.
import { firefox } from 'playwright';
const KEY = process.env.CDPFLEET_API_KEY;
// 1. Launch the browser
const res = await fetch('https://starter.cdpfleet.com/camoufox/session', {
method: 'POST',
headers: { 'x-api-key': KEY, 'content-type': 'application/json' },
body: JSON.stringify({
proxy: 'http://user:[email protected]:8080',
headless: false,
}),
});
if (!res.ok) throw new Error(`launch failed: ${res.status} ${await res.text()}`);
const { wsUrl } = await res.json();
// 2. Connect and drive it
const browser = await firefox.connect(wsUrl, { headers: { 'x-api-key': KEY } });
const page = await browser.newPage();
await page.goto('https://example.com');
console.log(await page.title());
await browser.close(); // ends the session and stops billing
# pip install playwright==1.60.0 requests
# Browsers run on cdpfleet, so no `playwright install` is needed.
import os
import requests
from playwright.sync_api import sync_playwright
KEY = os.environ["CDPFLEET_API_KEY"]
# 1. Launch the browser
res = requests.post(
"https://starter.cdpfleet.com/camoufox/session",
headers={"x-api-key": KEY},
json={
"proxy": "http://user:[email protected]:8080",
"headless": False,
},
timeout=60,
)
res.raise_for_status()
ws_url = res.json()["wsUrl"]
# 2. Connect and drive it
with sync_playwright() as p:
browser = p.firefox.connect(ws_url, headers={"x-api-key": KEY})
page = browser.new_page()
page.goto("https://example.com")
print(page.title())
browser.close() # ends the session and stops billing
// Maven: com.microsoft.playwright:playwright:1.60.0 and com.google.code.gson:gson:2.11.0
// Run with PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1: browsers run on cdpfleet.
import com.google.gson.JsonParser;
import com.microsoft.playwright.*;
import java.net.URI;
import java.net.http.*;
import java.util.Map;
public class Example {
public static void main(String[] args) throws Exception {
String key = System.getenv("CDPFLEET_API_KEY");
// 1. Launch the browser
String body = """
{
"proxy": "http://user:[email protected]:8080",
"headless": false
}
""";
HttpResponse<String> res = HttpClient.newHttpClient().send(
HttpRequest.newBuilder(URI.create("https://starter.cdpfleet.com/camoufox/session"))
.header("x-api-key", key)
.header("content-type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build(),
HttpResponse.BodyHandlers.ofString());
if (res.statusCode() != 200) {
throw new RuntimeException("launch failed: " + res.statusCode() + " " + res.body());
}
String wsUrl = JsonParser.parseString(res.body()).getAsJsonObject().get("wsUrl").getAsString();
// 2. Connect and drive it
try (Playwright playwright = Playwright.create()) {
Browser browser = playwright.firefox().connect(wsUrl,
new BrowserType.ConnectOptions().setHeaders(Map.of("x-api-key", key)));
Page page = browser.newPage();
page.navigate("https://example.com");
System.out.println(page.title());
browser.close(); // ends the session and stops billing
}
}
}
// dotnet add package Microsoft.Playwright --version 1.60.0
// Browsers run on cdpfleet, so no `playwright install` is needed.
using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using Microsoft.Playwright;
var key = Environment.GetEnvironmentVariable("CDPFLEET_API_KEY")!;
// 1. Launch the browser
using var http = new HttpClient();
http.DefaultRequestHeaders.Add("x-api-key", key);
var body = """
{
"proxy": "http://user:[email protected]:8080",
"headless": false
}
""";
var res = await http.PostAsync("https://starter.cdpfleet.com/camoufox/session",
new StringContent(body, Encoding.UTF8, "application/json"));
if (!res.IsSuccessStatusCode)
throw new Exception($"launch failed: {(int)res.StatusCode} {await res.Content.ReadAsStringAsync()}");
var wsUrl = (await res.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("wsUrl").GetString()!;
// 2. Connect and drive it
using var playwright = await Playwright.CreateAsync();
var browser = await playwright.Firefox.ConnectAsync(wsUrl, new BrowserTypeConnectOptions
{
Headers = new Dictionary<string, string> { ["x-api-key"] = key },
});
var page = await browser.NewPageAsync();
await page.GotoAsync("https://example.com");
Console.WriteLine(await page.TitleAsync());
await browser.CloseAsync(); // ends the session and stops billing
// go get github.com/playwright-community/[email protected]
//
// One-time driver setup (needs Node.js 18+): playwright-go can no longer download the
// 1.60.0 driver itself, so build it from npm and point PLAYWRIGHT_DRIVER_PATH at it:
// mkdir -p ~/.cache/pw-driver-1.60.0 && cd ~/.cache/pw-driver-1.60.0 &&
// curl -sL https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz | tar xz &&
// ln -sf "$(command -v node)" node
// export PLAYWRIGHT_DRIVER_PATH=~/.cache/pw-driver-1.60.0
// Browsers run on cdpfleet, so no browsers are downloaded (SkipInstallBrowsers).
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"strings"
"github.com/playwright-community/playwright-go"
)
func main() {
key := os.Getenv("CDPFLEET_API_KEY")
// 1. Launch the browser
body := `{
"proxy": "http://user:[email protected]:8080",
"headless": false
}`
req, _ := http.NewRequest("POST", "https://starter.cdpfleet.com/camoufox/session", strings.NewReader(body))
req.Header.Set("x-api-key", key)
req.Header.Set("content-type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
msg, _ := io.ReadAll(res.Body)
log.Fatalf("launch failed: %s %s", res.Status, msg)
}
var session struct {
WsURL string `json:"wsUrl"`
}
if err := json.NewDecoder(res.Body).Decode(&session); err != nil {
log.Fatal(err)
}
// 2. Connect and drive it (Install fetches only the Playwright driver, once)
opts := &playwright.RunOptions{SkipInstallBrowsers: true}
if err := playwright.Install(opts); err != nil {
log.Fatal(err)
}
pw, err := playwright.Run(opts)
if err != nil {
log.Fatal(err)
}
defer pw.Stop()
browser, err := pw.Firefox.Connect(session.WsURL, playwright.BrowserTypeConnectOptions{
Headers: map[string]string{"x-api-key": key},
})
if err != nil {
log.Fatal(err)
}
page, err := browser.NewPage()
if err != nil {
log.Fatal(err)
}
if _, err := page.Goto("https://example.com"); err != nil {
log.Fatal(err)
}
title, _ := page.Title()
fmt.Println(title)
browser.Close() // ends the session and stops billing
}
Launch options
| Option | What it does |
|---|---|
proxy_rules | Send specific destination hosts through specific proxies. |
inactivity_timeout | End the session after this long with no traffic on its WebSocket. |
overall_timeout | Hard cap on the session's total lifetime, regardless of activity. |
vpn_tunnel | VPN Tunnel: UDP/WebRTC full support — all of the browser's traffic, UDP included, goes through the residential exit. |
vpn | Own network (dedicated plans): send all of the browser's traffic through your own VPN instead of a proxy. |
headless | Run without a display. |
version | Pin an older major version. |
os | Operating system of the generated fingerprint. |
locale | Browser locale(s). |
geoip | Match timezone, locale, geolocation and WebRTC IP to the proxy's exit IP. |
humanize | Human-like cursor movement. |
block_images | Block all images. |
block_webrtc | Disable WebRTC entirely. |
block_webgl | Disable WebGL. |
disable_coop | Disable Cross-Origin-Opener-Policy. |
screen | Constrain the fingerprint's screen size. |
window | Fixed outer window size. |
fingerprint | Use a complete BrowserForge fingerprint. |
config | Override individual fingerprint properties. |
fonts | Extra font families to expose. |
custom_fonts_only | Expose only the fonts in fonts. |
webgl_config | Force a specific WebGL vendor/renderer pair. |
ff_version | Firefox major version to claim in the fingerprint. |
main_world_eval | Allow scripts in the page's main world. |
screencast | Stream the page to your code (Playwright page.screencast). |
screen_size | Resolution of the session's own display (headful only). |
keep_alive | Keep the session when your client disconnects (dedicated threads only). |
start_url | Open this page at launch so the session can be driven in live view with no client connected. |
profile | Restore a saved browser profile and save it again when the session ends. |
record | Opt this session out of recording with false. |
Every session also needs a proxy — yours, or the residential proxy.