cdpfleet / Bot protection
Measured, dated
What gets through where.
Two weeks of measurements: twelve browsers and a returning profile on real sites behind each vendor, and four setups on the vendors' own pages, through your own proxy and residential exits, one load per cell, nothing clicked. Dated snapshots, not promises.
- 6vendors
- 13setups on real sites
- 0CAPTCHAs solved
On real sites
Three or four real sites per vendor (unnamed), twelve browsers and a returning Camoufox profile, one sticky residential exit per site, five runs. Each cell: loads that got the real page out of loads measured. Every setup, every vendor: the scoreboard.
| Vendor | Headless Chrome | Headful Chrome | Camoufox | Camoufox, returning |
|---|---|---|---|---|
| Cloudflare · 3 sites · 2026-10-26 | 5/15 | 14/14 | 15/15 | 15/15 |
| DataDome · 3 sites · 2026-10-27 | 4/14 | 15/15 | 7/15 | 7/15 |
| Akamai · 3 sites · 2026-10-28 | 5/15 | 9/14 | 12/15 | 15/15 |
| HUMAN · 3 sites · 2026-10-29 | 5/15 | 9/14 | 13/15 | 1/15 |
| Kasada · 2 sites · 2026-10-30 | 0/10 | 1/10 | 6/10 | 7/7 |
| AWS WAF · 2 sites · 2026-10-30 | 5/10 | 9/9 | 10/10 | 9/9 |
- Cloudflare — case 70, 3 sites, 2026-10-26: start with Edge, headful (15/15), Brave, headful (15/15), Opera, headful (15/15), Yandex, headful (15/15).
- DataDome — case 71, 3 sites, 2026-10-27: start with Chrome, headful (15/15).
- Akamai — case 73, 3 sites, 2026-10-28: start with Brave, headful (15/15), Opera, headful (15/15), Camoufox, returning profile (2nd visit) (15/15).
- HUMAN — case 75, 3 sites, 2026-10-29: start with Whale, headful (14/15).
- Kasada — case 77, 2 sites, 2026-10-30: start with Camoufox, returning profile (2nd visit) (7/7). Never got in: Chrome, headless, Edge, headful, Opera, headful, Yandex, headful, Whale, headful, Chromium, headless, Patchright, headful, Firefox, headful, WebKit, headful.
- AWS WAF — case 77, 2 sites, 2026-10-30: start with Edge, headful (10/10), Brave, headful (10/10), Opera, headful (10/10), Yandex, headful (10/10).
On the vendors' own pages
| Vendor (page) | Headless Chromium | Headful Chrome / Edge | Camoufox | Notes — measured |
|---|---|---|---|---|
| Cloudflare challenge (scrapingcourse.com) | challenge, every cell | challenge, every cell | cleared by itself in 1–18 s | Network and tier changed nothing; the browser decided. Case 64, 2026-10-21 |
| Cloudflare background check (nowsecure.nl) | content | content | content | Every setup got the page and a cf_clearance cookie. Case 64, 2026-10-21 |
| DataDome (datadome.co) | blocked (403) 19/20 | mostly content, CAPTCHA in some runs | mostly content, CAPTCHA in some runs | Decided on the first response; no consistent network effect. Case 65, 2026-10-22 |
| Akamai Bot Manager (akamai.com) | blocked (403) 10/10 | content, every cell | content, every cell | _abck stayed unvalidated and the page was served anyway. Case 67, 2026-10-23 |
| HUMAN (humansecurity.com) | press-and-hold 10/10 | content 10/10 on own proxy, 10/15 on residential | press-and-hold 12/15 | HUMAN and Akamai disagreed about Camoufox. Case 67, 2026-10-23 |
| reCAPTCHA v3 / hCaptcha demos | score 0.9 / widget shown | score 0.9 / widget shown | score 0.9 / widget shown | The demos don't separate browsers. Case 68, 2026-10-24 |
One load per cell, nothing clicked, five runs per case (one per language). Outcomes: content (the real page), cleared (an automatic check passed by itself), challenge (a CAPTCHA or press-and-hold), blocked (a block page). Camoufox is based on Firefox source; cdpfleet is not affiliated with Mozilla.
Notes from the vendors' pages
- Cloudflare: start with Camoufox when a page shows Cloudflare's interstitial. On scrapingcourse.com it cleared by itself in 1–18 s while headless Chromium, headful Chrome and Edge stayed on the challenge in every cell (case 64, 2026-10-21). A profile that had cleared once loaded the page straight away on the next visit from the same exit.
- DataDome: start headful (Chrome, Edge or Camoufox) and keep a
profile. Headless Chromium was blocked 19 times in 20; the headful setups mostly got the page, and a returning profile never did worse than its first visit, turning Chrome's CAPTCHA into content in 3 of 3 runs (case 65, 2026-10-22). - Akamai: any headful browser. Headful Chrome, Edge and Camoufox got akamai.com in every cell; only headless Chromium was turned away (case 67, 2026-10-23).
- HUMAN: headful Chrome or Edge, best on your own proxy (content in 10 of 10 cells there, 10 of 15 on residential exits). Camoufox met the press-and-hold in 12 of 15 cells (case 67, 2026-10-23).
- Unknown vendor: find out first. The cookies and request hosts each vendor leaves (
__cf_bm,datadome,_abck,_px*and so on) identified it on 19–20 of 20 public sites (case 62, 2026-10-20).
// 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: 'cdpfleet-resi-country-us-session-shop1-lifetime-30',
headless: false,
geoip: true,
profile: 'shop-visitor',
}),
});
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 context = browser.contexts()[0]; // the saved profile — a new context isn't saved
const page = context.pages()[0] ?? await context.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": "cdpfleet-resi-country-us-session-shop1-lifetime-30",
"headless": False,
"geoip": True,
"profile": "shop-visitor",
},
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})
context = browser.contexts[0] # the saved profile — a new context isn't saved
page = context.pages[0] if context.pages else context.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": "cdpfleet-resi-country-us-session-shop1-lifetime-30",
"headless": false,
"geoip": true,
"profile": "shop-visitor"
}
""";
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)));
BrowserContext context = browser.contexts().get(0); // the saved profile — a new context isn't saved
Page page = context.pages().isEmpty() ? context.newPage() : context.pages().get(0);
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": "cdpfleet-resi-country-us-session-shop1-lifetime-30",
"headless": false,
"geoip": true,
"profile": "shop-visitor"
}
""";
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 context = browser.Contexts[0]; // the saved profile — a new context isn't saved
var page = context.Pages.Count > 0 ? context.Pages[0] : await context.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": "cdpfleet-resi-country-us-session-shop1-lifetime-30",
"headless": false,
"geoip": true,
"profile": "shop-visitor"
}`
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)
}
context := browser.Contexts()[0] // the saved profile — a new context isn't saved
var page playwright.Page
if pages := context.Pages(); len(pages) > 0 {
page = pages[0]
} else if page, err = context.NewPage(); 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
}
Why outcomes vary by site and day
- Real sites disagreed with the vendors' own pages. HUMAN's own site challenged Camoufox in 12 of 15 cells; on real HUMAN sites fresh Camoufox got the page 13 of 15 times (case 75). On the hardest Akamai site, Brave and Opera got in every run while headful Chrome and Edge were blocked (case 73).
- A returning profile can help or hurt. It took Camoufox from 2 of 5 to 5 of 5 on the hardest Akamai site, but on HUMAN's real sites the second visit was challenged 14 times in 15 (cases 73, 75).
- Kasada and AWS WAF are opposites. Kasada turned away every browser but Camoufox on its two sites (108 of 110 other loads got a blank page); AWS WAF checked every load and let nearly everyone through after about 5 seconds, except headless on one site (case 77).
- Each site sets its own rules. The same vendor can be strict on one site and lenient on another, which is why these cases use the vendors' own pages and say "on these pages on this date" (case 65, case 67).
- Vendors change their checks all the time. Every result here is a dated snapshot.
- The network mattered less than the browser. Tier 1 vs Tier 4 never turned a Chromium challenge into a pass on Cloudflare (case 64), DataDome showed no consistent network effect (case 65), and the rotating own proxy accounted for most of the demo-page misses (case 68).
- Not every visit clears. Camoufox's first visit to the Cloudflare challenge stayed on it in two later runs, so there was nothing for a profile to skip (case 64).
What didn't help
- VPN Tunnel didn't change a verdict. It makes WebRTC show the exit IP and enables HTTP/3, but Cloudflare's and DataDome's verdicts were the same with and without it on these pages (case 69, 2026-10-24).
humanizemade no measurable difference on DataDome's pages: the page after the cursor moves loaded 5 of 5 times with it on and 4 of 5 with it off (case 65, 2026-10-22).- CAPTCHA demo scores don't rank browsers. Google's v3 demo gave every setup 0.9, headless Chromium included, the same browser the real protections blocked (case 68, 2026-10-24).
- Bot-test pages aren't the target site. Public fingerprint test pages flagged headless Chromium everywhere and disagreed about the rest (case 63, 2026-10-20). Judge a setup on the site you care about.
When to stop
- These cases measure; they don't defeat. Every case loads public pages once per setup, clicks nothing and solves no CAPTCHA. When a site shows a challenge, that is the site's answer.
- Don't farm CAPTCHAs or hammer a site. Retrying until something passes wears the site down and burns your exits. Back off, honour
Retry-After(case 53), or hand the page to a person in live view. - Respect the site. Read its terms, prefer its API or a data feed where one exists, and keep your request rate polite. No setup here is a promise of access.