[cdpfleet](https://cdpfleet.com/) / Web scraping

For scrapers

# Scrape like *a real visitor*.

Pick the browser a site should see — real Chrome, Edge, a Camoufox device persona or a stealth-patched Chromium — send it through your proxy or a residential exit by country, and check what the site reads against measurements, not folklore.

[Build the code](https://cdpfleet.com/docs/builder)[The measured cases](https://cdpfleet.com/docs/cases)

-   **12**real desktop browsers
-   **$0.50/GB**cheapest residential tier
-   **0**second IPs leaked over WebRTC

## Which browser for which protection

| The site checks… | Use | Why — measured |
| --- | --- | --- |
| That it's really Chrome (client hints, TLS) | Google Chrome or Microsoft Edge | Each sends its own real JA4 and HTTP/2 fingerprint, nothing patched ([case 01](https://cdpfleet.com/docs/cases/tls-fingerprints)); Chrome's brand is in the client hints, Playwright's Chromium lacks it ([Chrome vs Chromium](https://cdpfleet.com/docs/compare/chrome-vs-chromium)). |
| The device: screen, fonts, WebGL, OS | Camoufox with `os` and `geoip` | Spoofs a whole device at the engine level and matches locale and timezone to the exit ([Camoufox vs Patchright](https://cdpfleet.com/docs/compare/camoufox-vs-patchright), fonts in [case 52](https://cdpfleet.com/docs/cases/fonts-fingerprint)). Based on Firefox source; not affiliated with Mozilla. Needs a proxy. |
| Automation leaks: CDP, the console | Patchright (or Rebrowser on Playwright 1.52) | Chromium with the automation leaks patched; it delivers no console events, so logging costs it less than Playwright's Chromium ([case 43](https://cdpfleet.com/docs/cases/cdp-detectability), [Patchright vs Rebrowser](https://cdpfleet.com/docs/compare/patchright-vs-rebrowser)). |
| Headless: `HeadlessChrome`, plugins, permissions | Any Chromium build, headful | Headful removes the obvious tells with the same build, for one extra thread; the software GPU and the server's cores stay visible either way ([case 16](https://cdpfleet.com/docs/cases/headless-tells), [case 05](https://cdpfleet.com/docs/cases/stealth-builds)). |

A Camoufox Windows persona on a sticky US residential exit

 

```node
// npm install playwright@1.60.0
// 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',
    os: 'windows',
    geoip: true,
    headless: true,
  }),
});
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
```

```python
# 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",
        "os": "windows",
        "geoip": True,
        "headless": True,
    },
    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
```

```java
// 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",
          "os": "windows",
          "geoip": true,
          "headless": true
        }
        """;
    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
    }
  }
}
```

```csharp
// 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",
      "os": "windows",
      "geoip": true,
      "headless": true
    }
    """;
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
// go get github.com/playwright-community/playwright-go@v0.6000.0
//
// 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",
	  "os": "windows",
	  "geoip": true,
	  "headless": true
	}`
	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
}
```

## What a site reads before your page even loads

-   **TLS and HTTP/2 come from the engine, not your code:** Chrome and Edge differ by one TLS extension and share their HTTP/2 fingerprint; Camoufox's TLS is Linux Firefox's whatever OS it claims (as a real Firefox's is on every OS); WebKit speaks HTTP/1.1 through a proxy, so use it for rendering tests, not to impersonate ([case 01](https://cdpfleet.com/docs/cases/tls-fingerprints)).
-   **Header order is a fingerprint too:** setting `locale` or `extraHTTPHeaders` moves `accept-language` up, and `route.continue({ headers })` reorders everything — an order real Chrome doesn't send ([case 09](https://cdpfleet.com/docs/cases/headers-and-h2)).
-   **`navigator.webdriver` is `false`** on every Chromium build on the fleet, headless included ([case 16](https://cdpfleet.com/docs/cases/headless-tells)).
-   **No WebRTC leak:** a session that uses a proxy can't send UDP past it, so no setup exposed a second public IP; Chromium, Chrome and Firefox show only anonymous mDNS names, and Camoufox reports the exit ([case 54](https://cdpfleet.com/docs/cases/webrtc-ip-leak)).
-   **Treat stealth as a floor, not a guarantee:** these are first-line checks; serious vendors add canvas, audio, timing and behaviour ([case 05](https://cdpfleet.com/docs/cases/stealth-builds)).
-   **Every signal in one place:** TLS, headers, client hints, canvas and WebGL, fonts, WebRTC, CDP tells and timezone vs IP, with what each fleet browser sends — [what a page can read about your browser](https://cdpfleet.com/docs/fingerprinting).
-   **A fingerprint isn't a verdict:** the twelve setups of the lab week fall into six JA4 groups, and on 8 of 16 protected sites, browsers with identical JA4, peetprint and HTTP/2 fingerprints got opposite outcomes on 2026-10-26..30 — the TLS fingerprint alone didn't decide ([case 84](https://cdpfleet.com/docs/cases/ja4-vs-vendor-verdicts)).
-   **Brave changes its fingerprint per site:** canvas, audio, plugins and window size differ between two sites in one session and with every new context, while Chrome reports the same values everywhere; CreepJS names Brave and marks those values as lies ([case 83](https://cdpfleet.com/docs/cases/brave-farbling)).
-   **Behaviour is scored too:** on a behaviour-test form, plain Playwright clicks in Chrome were flagged every time; what the page scored in Camoufox was how fast the form was filled, and `humanize` changed the cursor path, not where it clicked ([case 81](https://cdpfleet.com/docs/cases/behaviour-scoring-humanize)).

## Pay for less

-   **Fetch first:** a plain GET through your proxy tells you in a second whether the data is already in the HTML — one of three pages in the test needed no browser at all ([case 19](https://cdpfleet.com/docs/cases/fetch-first)).
-   **Residential by tier:** the cdpfleet residential proxy costs $5.00 / $2.50 / $1.00 / $0.50 per GB for Tiers 1–4, from one prepaid balance. Keep the page on Tier 1 and send image hosts through Tier 4 with `proxy_rules`: on a gallery, images were about two thirds of the bytes and a load cost well under half ([case 51](https://cdpfleet.com/docs/cases/resi-tiers-mix)). Or keep your own proxy and send only the one strict host through residential ([recipe](https://cdpfleet.com/docs/examples#resi-for-one-host)).
-   **Don't load what you don't need:** block images and fonts to save proxy bytes ([case 08](https://cdpfleet.com/docs/cases/bandwidth-diet)), and block analytics and beacons so the page doesn't report your visit — the Guardian sent 13–43 telemetry requests per load, some after the scraper had left ([case 59](https://cdpfleet.com/docs/cases/intercept-and-block-telemetry)).
-   **Read the API the page reads:** log in once, borrow the token the app sends to its own API, and fetch every page of it from inside the browser — all pages in about a second instead of clicking through ([case 61](https://cdpfleet.com/docs/cases/scrape-a-paginated-json-api-with-a-token)).
-   **One session for many captures:** a screenshot, PDF and Markdown of three pages billed 13–17 thread-seconds from one session, against 39–55 for nine Function calls — and your own session was faster in 35 of 45 captures ([case 85](https://cdpfleet.com/docs/cases/function-vs-your-own-browser)).
-   **A whole site as a job:** a bounded crawl of a 1,000-book sandbox ran 21–29 pages a minute at about 8–11 thread-seconds per page, stopped and resumed without fetching a page twice ([case 86](https://cdpfleet.com/docs/cases/crawl-a-site-as-a-job)).
-   **Memory, not tabs, is the ceiling:** a long article opened tab after tab ran out at 37 tabs on 4 GB and reached the 50-tab cap with `"memory": 2` ([case 80](https://cdpfleet.com/docs/cases/tabs-and-memory-by-plan)).

Pages on Tier 1, image hosts on Tier 4, in one session

 

```node
// npm install playwright@1.60.0
// Browsers run on cdpfleet, so no `npx playwright install` is needed.
import { chromium } from 'playwright';

const KEY = process.env.CDPFLEET_API_KEY;

// 1. Launch the browser
const res = await fetch('https://starter.cdpfleet.com/chromium/session', {
  method: 'POST',
  headers: { 'x-api-key': KEY, 'content-type': 'application/json' },
  body: JSON.stringify({
    proxy: 'cdpfleet-resi-country-us',
    headless: 'new',
    proxy_rules: [
      {
        name: 'images',
        hosts: [
          'upload.wikimedia.org',
          '*.cloudfront.net',
        ],
        proxy: 'cdpfleet-resi-tier-4-country-us',
      },
    ],
  }),
});
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 chromium.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
```

```python
# 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/chromium/session",
    headers={"x-api-key": KEY},
    json={
        "proxy": "cdpfleet-resi-country-us",
        "headless": "new",
        "proxy_rules": [
            {
                "name": "images",
                "hosts": [
                    "upload.wikimedia.org",
                    "*.cloudfront.net",
                ],
                "proxy": "cdpfleet-resi-tier-4-country-us",
            },
        ],
    },
    timeout=60,
)
res.raise_for_status()
ws_url = res.json()["wsUrl"]

# 2. Connect and drive it
with sync_playwright() as p:
    browser = p.chromium.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
```

```java
// 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",
          "headless": "new",
          "proxy_rules": [
            {
              "name": "images",
              "hosts": [
                "upload.wikimedia.org",
                "*.cloudfront.net"
              ],
              "proxy": "cdpfleet-resi-tier-4-country-us"
            }
          ]
        }
        """;
    HttpResponse<String> res = HttpClient.newHttpClient().send(
        HttpRequest.newBuilder(URI.create("https://starter.cdpfleet.com/chromium/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.chromium().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
    }
  }
}
```

```csharp
// 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",
      "headless": "new",
      "proxy_rules": [
        {
          "name": "images",
          "hosts": [
            "upload.wikimedia.org",
            "*.cloudfront.net"
          ],
          "proxy": "cdpfleet-resi-tier-4-country-us"
        }
      ]
    }
    """;
var res = await http.PostAsync("https://starter.cdpfleet.com/chromium/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.Chromium.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
// go get github.com/playwright-community/playwright-go@v0.6000.0
//
// 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",
	  "headless": "new",
	  "proxy_rules": [
	    {
	      "name": "images",
	      "hosts": [
	        "upload.wikimedia.org",
	        "*.cloudfront.net"
	      ],
	      "proxy": "cdpfleet-resi-tier-4-country-us"
	    }
	  ]
	}`
	req, _ := http.NewRequest("POST", "https://starter.cdpfleet.com/chromium/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.Chromium.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
}
```

## When the site pushes back

-   **Honour `Retry-After`, then move:** a crawler that retried a 429 at once was challenged and got 3–4 of 8 pages; one that waited as told and swapped the session to another proxy when its exit was burned got 8 of 8, with its login intact ([case 53](https://cdpfleet.com/docs/cases/soft-block-backoff), live swap in [case 06](https://cdpfleet.com/docs/cases/live-proxy-swap)).
-   **See the block yourself:** open the same browser and exit in live view, click through the challenge or the consent wall by hand, then let your code continue in that page ([Launch interactive](https://cdpfleet.com/launch-interactive), [case 58](https://cdpfleet.com/docs/cases/launch-interactive-to-code)).
-   **Retry the fleet, not the site:** a `503` from the launch means the fleet is busy and `429 threads_exceeded` means no free thread — back off and retry ([worker pool](https://cdpfleet.com/docs/cases/worker-pool)).

## When not to use a browser

-   **The data is in the HTML:** a plain HTTP client through the same proxy is cheaper and faster ([fetch first](https://cdpfleet.com/docs/cases/fetch-first)).
-   **You want one call per page, not a browser:** request APIs bill per page — compare them with our Functions on the [ScrapingBee](https://cdpfleet.com/docs/compare/cdpfleet-vs-scrapingbee), [Zyte](https://cdpfleet.com/docs/compare/cdpfleet-vs-zyte), [Nimble](https://cdpfleet.com/docs/compare/cdpfleet-vs-nimble) and [Scrapfly](https://cdpfleet.com/docs/compare/cdpfleet-vs-scrapfly) pages.
-   **You need captchas solved for you:** there is no built-in solver. Use any solver through Playwright, or hand the browser to a person in [live view](https://cdpfleet.com/live-view).
-   **You want to look like a phone:** desktop browsers emulate phone screens, but a real device is a different story — see [mobile](https://cdpfleet.com/mobile).

## Related

Cases, recipes, posts and comparisons about this — updated as new ones are published.

### Reference docs

The details, options and errors.

-   [Fingerprinting](https://cdpfleet.com/docs/fingerprinting)What a page can read about your browser, per fleet browser.
-   [Proxies](https://cdpfleet.com/docs/proxies)Your own, pools, per-host rules, residential.
-   [Camoufox](https://cdpfleet.com/docs/browsers/camoufox)Persona options.
-   [Comparisons](https://cdpfleet.com/docs/compare)Browser vs browser, measured.
-   [Scraping examples](https://cdpfleet.com/docs/cases#for-scraping)Every measurement for scraping, in five languages.

### Cases 37

Real problems solved end to end, run on production in five languages.

-   [Case 89: Watch a page live: its XHR calls, DOM changes and WebSocket messages over SSE and a signed webhook](https://cdpfleet.com/docs/cases/watch-a-page-live)Keep a Chrome of yours on a page that updates itself (the ISS position, polled about once a second), and get every matching XHR response and every change to one…[Code on GitHub](https://github.com/cdpfleet/cdpfleet/tree/main/cases/89-watch-a-page-live)
-   [Case 87: Geo compare: the same pages from five countries in one call, and reading the diff](https://cdpfleet.com/docs/cases/geo-compare)One `POST /v1/functions/geo` per page loads it from the US, Germany, the UK, Japan and Brazil at once and returns each country's Markdown and HTML plus a diff…[Code on GitHub](https://github.com/cdpfleet/cdpfleet/tree/main/cases/87-geo-compare)
-   [Case 86: Crawl a whole site as a job: map, crawl, stop, resume, results, zip and a signed webhook](https://cdpfleet.com/docs/cases/crawl-a-site-as-a-job)Map books.toscrape.com, crawl 100 pages of it as a background job, stop it part-way and resume it, then read the results as JSON lines and as a zip archive, and…[Code on GitHub](https://github.com/cdpfleet/cdpfleet/tree/main/cases/86-crawl-a-site-as-a-job)
-   [Case 84: Does the TLS fingerprint (JA4) explain which browsers got in? Twelve browsers against six vendors](https://cdpfleet.com/docs/cases/ja4-vs-vendor-verdicts)Each of the twelve browsers from the real-site lab week loads a TLS echo page once, so we know the JA4, peetprint and HTTP/2 fingerprint it sends. Grouped by…[Code on GitHub](https://github.com/cdpfleet/cdpfleet/tree/main/cases/84-ja4-vs-vendor-verdicts)
-   [Case 85: A Function or your own browser? Screenshot, PDF and Markdown of the same pages, timed and billed](https://cdpfleet.com/docs/cases/function-vs-your-own-browser)Three pages, three outputs, two ways: one POST to a Function, or launch a browser yourself, connect Playwright, capture and close. Wall time, the thread-seconds each…[Code on GitHub](https://github.com/cdpfleet/cdpfleet/tree/main/cases/85-function-vs-your-own-browser)
-   [Case 83: Brave's fingerprint randomisation per site, per context and per launch, and what public fingerprint pages make of it](https://cdpfleet.com/docs/cases/brave-farbling)Brave adds noise to canvas, audio, cores, memory and the plugin list, keyed to the site and the session. One probe on two made-up sites, the same site again, a…[Code on GitHub](https://github.com/cdpfleet/cdpfleet/tree/main/cases/83-brave-farbling)
-   [Case 81: Behaviour scoring: Camoufox humanize on and off vs plain Chrome clicks on a public bot-test form](https://cdpfleet.com/docs/cases/behaviour-scoring-humanize)A public behavioural bot-test page scores how a demo login form was filled in: clicks, keystrokes, timing. Camoufox with `humanize` off, on and slowed down, and…[Code on GitHub](https://github.com/cdpfleet/cdpfleet/tree/main/cases/81-behaviour-scoring-humanize)
-   [Case 77: Kasada and AWS WAF on real sites: twelve browsers, four sites, one exit each](https://cdpfleet.com/docs/cases/kasada-and-aws-waf-by-browser)Two real sites behind Kasada and two behind AWS WAF, loaded once by each of twelve browsers and by a returning Camoufox profile, through one sticky residential exit…[Code on GitHub](https://github.com/cdpfleet/cdpfleet/tree/main/cases/77-kasada-and-aws-waf-by-browser)

[All cases →](https://cdpfleet.com/docs/cases) 37 match this topic

### Updates 13

Product news and browser releases.

-   [Opera 140: Chromium 157 underneath, HTTPS-First turned on (and off on cdpfleet)](https://cdpfleet.com/docs/updates/opera-140)Stable Opera on the fleet is now 140.0.6074.17, on Chromium 157: HTTPS-First mode (kept off on cdpfleet), Protected Audience gone, TLS unchanged.
-   [Brave 1.99: Chromium 157 underneath, Protected Audience gone, same TLS fingerprint](https://cdpfleet.com/docs/updates/brave-1-99)Stable Brave on the fleet is now 1.99.55, on Chromium 157: four new web features, Protected Audience gone, plain HTTP loads, TLS and HTTP/2 unchanged.
-   [Edge 157: Chromium 157, HTTPS-First kept off on cdpfleet, Protected Audience gone](https://cdpfleet.com/docs/updates/edge-157)Stable Edge on the fleet is now 157.0.4341.42, on Chromium 157: HTML streaming, Protected Audience gone, HTTPS-First kept off on cdpfleet, TLS unchanged.
-   [Whale 5.41: Chromium 150 to 156 in one step, and now Chrome's TLS fingerprint](https://cdpfleet.com/docs/updates/whale-5-41)Stable Whale on the fleet is now 5.41.429.3, on Chromium 156: six Chromium majors at once, Chrome's JA4, plain HTTP still loads, Shared Storage gone.
-   [Chrome 157: HTTPS-First turned on (and off on cdpfleet), Protected Audience gone, same TLS fingerprint](https://cdpfleet.com/docs/updates/chrome-157)Stable Chrome on the fleet is now 157.0.8103.38: HTTPS-First mode (kept off on cdpfleet), Protected Audience gone, TLS and HTTP/2 unchanged.
-   [Kept downloads: files from a session, fetched after it ends](https://cdpfleet.com/docs/updates/kept-downloads)Launch with "downloads": true and every file the browser downloads is kept for 2 days — including files a person clicked in live view or an AI agent fetched through…
-   [50 tabs per session, memory as the ceiling, and the memory option](https://cdpfleet.com/docs/updates/tabs-and-memory)Every plan now allows 50 tabs in one session; what actually limits a session is its memory — 2, 4 or 6 GB by plan — and the new "memory" launch option buys 2–4 times…
-   [Opera 139: Chromium 155 underneath, four new CSS and policy features](https://cdpfleet.com/docs/updates/opera-139)Stable Opera on the fleet is now 139.0.6053.22, on Chromium 155. margin-trim, symbols() and two more arrive; TLS and HTTP/2 unchanged.

[All updates →](https://cdpfleet.com/docs/updates) 13 match this topic

### Browser comparisons 6

Measured side by side on the fleet.

-   [Yandex Browser vs Chrome](https://cdpfleet.com/docs/compare/yandex-vs-chrome)Yandex Browser 26.8 runs on Chromium 150, six majors behind Chrome 156, names itself in the user agent and client hints, puts Russian first in navigator.languages…
-   [Camoufox vs Firefox, headless](https://cdpfleet.com/docs/compare/camoufox-vs-firefox-headless)Headless Firefox and headless Camoufox (both based on Firefox source; not affiliated with Mozilla) side by side: the headless tells a page can read, what Camoufox…
-   [Patchright vs Rebrowser](https://cdpfleet.com/docs/compare/patchright-vs-rebrowser)Two stealth-patched Chromium builds that look the same to a site — same TLS and HTTP/2 fingerprints, no webdriver, no Runtime.enable leak — but Patchright is…
-   [Chrome vs Chromium](https://cdpfleet.com/docs/compare/chrome-vs-chromium)Google's Chrome against the Chromium build Playwright ships: seven majors apart, one brand missing from the client hints, one TLS extension fewer — and, contrary to…
-   [Firefox vs Camoufox](https://cdpfleet.com/docs/compare/firefox-vs-camoufox)Playwright's Firefox build against the anti-detect fork built on it (both based on Firefox source; not affiliated with Mozilla): what Camoufox changes in what a site…
-   [Camoufox vs Patchright](https://cdpfleet.com/docs/compare/camoufox-vs-patchright)Two stealth browsers, two philosophies: a browser based on Firefox source (not affiliated with Mozilla) that spoofs the whole device at the C++ level, or a Chromium…

## Read next

[Monitoring →](https://cdpfleet.com/monitoring)[Pages to text for LLMs →](https://cdpfleet.com/llm-data)[Browsers →](https://cdpfleet.com/browsers)[Residential proxy →](https://cdpfleet.com/residential-proxy)[Live view →](https://cdpfleet.com/live-view)[Pricing →](https://cdpfleet.com/pricing)

---
Source: https://cdpfleet.com/web-scraping · Markdown: https://cdpfleet.com/web-scraping.md · All docs for AI tools: https://cdpfleet.com/llms.txt
