# Proxies

Every session browses through a proxy — cdpfleet never browses from its own IPs. Bring your own, or use the [cdpfleet residential proxy](#residential), billed by the GB. Set it at launch; it applies to all of the browser's traffic. Leave it out and the free [Community proxy](#community-proxy) is used — shared, slower and capped, fine for trying things out. On dedicated plans you can use [your own VPN](#own-network) instead.

## cdpfleet residential proxy

No proxy of your own? Send a `cdpfleet-resi` token as `proxy` and choose the price tier, the exit country, the device OS of the residential IP, and whether the IP stays the same. The upstream is configured on our servers; the token is all you ever send. Traffic (up and down, 1 GB = 109 bytes) is billed at the token's tier from a prepaid USD balance you top up in the [dashboard](https://cdpfleet.com/app#proxies), separately from your threads. Every account starts with **$5 free credit**.

| Tier | Token | Price per GB | $5 buys |
| --- | --- | --- | --- |
| Tier 1 | `cdpfleet-resi…` or `cdpfleet-resi-tier-1…` | $5.00 | 1 GB |
| Tier 2 | `cdpfleet-resi-tier-2…` | $2.50 | 2 GB |
| Tier 3 | `cdpfleet-resi-tier-3…` | $1.00 | 5 GB |
| Tier 4 | `cdpfleet-resi-tier-4…` | $0.50 | 10 GB |

Use Tier 1 for the pages that matter (logins, protected pages) and a cheaper tier for bulk traffic such as CDN assets and images. The pools behind each tier can differ and may change. Country and sticky sessions work on every tier; device OS targeting on Tier 1 and 2. Mix tiers in one session with [`proxy_rules`](#rules):

```jsonc
"proxy": "cdpfleet-resi"                                        // Tier 1: a new residential IP per connection, any country
"proxy": "cdpfleet-resi-country-us"                             // exits in the United States
"proxy": "cdpfleet-resi-country-us-os-windows"                  // … from Windows devices
"proxy": "cdpfleet-resi-country-de-session-cart1-lifetime-30"   // the same German IP for up to 30 minutes
"proxy": "cdpfleet-resi-tier-4-country-us"                      // Tier 4 ($0.50/GB), US exits
```

```json
{
  "proxy": "cdpfleet-resi-country-us",
  "proxy_rules": [
    {
      "hosts": [
        "*.cloudfront.net",
        "*.akamaized.net",
        "static.*"
      ],
      "proxy": "cdpfleet-resi-tier-4-country-us"
    }
  ]
}
```

| Part | Values | Meaning |
| --- | --- | --- |
| `-tier-N` | `1`–`4` | Price tier (table above). Without it, Tier 1. |
| `-country-XX` | any ISO 3166 two-letter code (`us`, `gb`, `de`, `jp`…) | Exit country. Without it, any country. |
| `-os-…` | `windows`, `android`, `ios`, `mac` | The kind of device the residential IP belongs to — **Tier 1 and 2 only** (a Tier 3/4 token with an OS returns `400 invalid_proxy`). Availability varies by country; iOS and Mac pools are smaller. |
| `-session-ID` | 1–10 of `A–Z a–z 0–9 _` | Sticky session: every connection uses the same IP. Reuse the name in a later browser session to keep the IP; names are private to your account. |
| `-lifetime-MIN` | 1–1440, only after a session | How long the sticky IP is kept (default 30 minutes). |

-   The parts go in this order; a token that doesn't match returns `400 invalid_proxy` saying which part is wrong.
-   Use it as the whole `proxy`, or as a single rule's proxy in `proxy_rules` (for example your own datacenter proxy by default and ours for one site) — not inside a list of proxies.
-   When the balance is used up, launches with the token return `402 proxy_balance_exhausted`. Traffic is metered about once a minute; a session may run up to $0.50 past zero before it is ended, and that overdraft comes off your next top-up.
-   Residential IPs are real people's connections: a few percent of connections fail and are retried by the browser, and a sticky IP can go offline before its lifetime ends. The dashboard's Proxy traffic page shows usage per host, marked *cdpfleet residential*.
-   The balance is in USD and doesn't expire; each GB is charged at the tier of the token that carried it. Check it with [`GET /v1/me/proxy-balance`](https://cdpfleet.com/docs/api).

## VPN Tunnel: UDP/WebRTC full support

A proxy carries TCP, so a normal proxied session sends no UDP at all: WebRTC shows only an anonymous mDNS name and no public address, and sites that offer HTTP/3 fall back to HTTP/2. With `"vpn_tunnel": true` the browser gets a network of its own whose only way out is the residential proxy — **all** of its traffic, UDP included, leaves through the residential exit, as on a home connection:

-   WebRTC reports the residential exit IP as the browser's public address (a `srflx` candidate), the same IP the page sees.
-   HTTP/3 (QUIC) works on Chromium-based browsers, Firefox and Camoufox. WebKit on Linux has no HTTP/3, so there the tunnel adds WebRTC.
-   The TLS fingerprint, the exit IP and everything else about the session stay the same. The server's own IP is never used: if an exit doesn't carry UDP, UDP simply fails.

### A tunnel to the proxy, not a VPN

The name says tunnel because the browser's whole network goes through it, but the exit is still the residential proxy, and the proxy is what opens the connections to the site. That decides which fingerprints the site sees:

| What the site sees | Proxy (default) | VPN Tunnel | A real VPN (WireGuard, OpenVPN) |
| --- | --- | --- | --- |
| IP address | The residential exit | The residential exit | The VPN server |
| TCP/IP fingerprint (TTL, window size, TCP options, MSS — what p0f-style checks read) | The exit's device: the proxy opens a new TCP connection to the site | The exit's device — measured identical to the proxy for the same exit | The browser's own machine (a Linux server), with TTL lowered by the hops and MSS set by the VPN's MTU |
| Timing: TCP handshake vs. request round trip | A gap, as with any proxy (the handshake ends at the exit) | The same gap | No gap — one end-to-end connection |
| TLS / JA4, HTTP/2 and HTTP/3 fingerprints, headers | The browser | The browser | The browser |
| UDP: WebRTC public address, HTTP/3 (QUIC) | None — no UDP leaves | Through the exit: WebRTC shows the exit IP, HTTP/3 works | Through the VPN server |

So VPN Tunnel adds UDP to what the proxy already does and changes nothing at the TCP level: the connection-level fingerprint stays the residential device's, which is what keeps it consistent with a residential IP (pick the device OS with `-os-…` in the token). With a real VPN the site would see a Linux server's TCP stack behind a VPN server's IP — a different trade-off, not a stronger version of this one.

```json
{
  "proxy": "cdpfleet-resi-country-us-session-shop1-lifetime-30",
  "vpn_tunnel": true,
  "headless": "new"
}
```

-   **Tier 1 and Tier 2, or your own proxy on dedicated plans:** the default `proxy` must be a `cdpfleet-resi` token on Tier 1 or 2 (a token without `-tier-N` is Tier 1). On dedicated plans your own proxy works too — UDP then needs a SOCKS5 proxy that relays UDP, and nothing is billed. Tier 3/4, a pool, or your own proxy on other plans returns `400 tunnel_not_available` with a `reason`. Every browser supports it.
-   **Sticky works best:** with a `-session-…` token one IP carries everything. With a rotating token, WebRTC and HTTP/3 may show a different residential IP than the page.
-   `proxy_rules` still route page traffic by host, but UDP (WebRTC, HTTP/3) can leave through a rule's proxy instead of the default, because a UDP flow carries no host for the rules to match. For WebRTC that matches the page's exit, don't combine the tunnel with `proxy_rules`. A [live swap](#live-swap) must keep a Tier 1/2 token, or it's refused and the route stays as it was.
-   UDP traffic is billed at the token's tier like the rest and listed as host *(udp)* on the dashboard's Proxy traffic page. The tunnel adds about 0.1 s to the launch; if it can't be set up the launch fails with a `503` — retry, like any 503.
-   In the dashboard's code generator: choose the cdpfleet residential proxy on Tier 1 or 2 and tick **VPN Tunnel: UDP/WebRTC full support**.

## Community proxy (free, every plan)

The proxy included with the free [Community plan](https://cdpfleet.com/docs/pricing#community) is available on paid plans too, at no charge: leave `proxy` out, or send a `cdpfleet-plan` token as `proxy` for a country or a sticky exit. Each plan group (Community, shared, dedicated) has its own Community proxy pool.

```jsonc
"proxy": "cdpfleet-plan"                                         // any exit
"proxy": "cdpfleet-plan-country-de"                              // an exit in Germany
"proxy": "cdpfleet-plan-country-us-session-shop1-lifetime-30"    // the same US exit for 30 minutes
```

-   **Free, so not guaranteed:** it's shared by everyone who uses it, so it's slower than your own proxies or the [cdpfleet residential proxy](#residential) and speed drops at peak times. Launches with it share the Community plan's capacity cap: when that's full they're refused with `503 community_capacity_full` (retry after `Retry-After`). Use it for trying things out, light jobs and pages that aren't sensitive to speed or reputation — not for work that has to run on time.
-   The token works as the session's `proxy` only — not inside `proxy_rules`, a list of proxies or a live swap.
-   The dashboard's Proxies → Community proxy tab and the code generator build the token for you.

## Own network: your VPN (dedicated plans)

On dedicated plans a session can use **your own VPN instead of a proxy**: the browser gets a network of its own whose only way out is your VPN, so every request — TCP and UDP, WebRTC, HTTP/3, DNS — leaves from your VPN server. Send `vpn` in the launch and no `proxy`. Nothing is billed for the traffic.

| `type` | `config` | What the site sees at the TCP level |
| --- | --- | --- |
| `wireguard`, `amneziawg` | wg-quick `.conf` text (AmneziaWG fields Jc, Jmin, Jmax, S1–S4, H1–H4, I1–I5 accepted) | An IP-level VPN: the browser's own TCP connection runs end to end, so the site sees our server's Linux network stack behind your VPN server's IP (TTL lowered by the hops, MSS set by the tunnel's MTU — 1380 at WireGuard's default 1420, about 1356–1358 on OpenVPN). No proxy-style timing gap. |
| `openvpn` | `.ovpn` text, plus `username`/`password` if it needs them. Scripts, plugins and management directives are refused. |
| `singbox` | A share link — `vless://` (incl. Reality), `vmess://`, `trojan://`, `ss://`, `hysteria2://` or `hy2://`, `tuic://` — or a sing-box outbound as JSON (also SSH) | Proxy-like: the connection ends on our side and your server opens a new one, so the site sees **your server's** network stack and the timing gap of a proxy. |

**Save it once, launch by name:** add the VPN on the dashboard's [Proxies → My VPNs](https://cdpfleet.com/app#proxies/vpn) page (stored encrypted), then send its name. The server looks the config up at launch, so no VPN secret goes into your code; the code generator offers your saved VPNs next to your proxies.

```jsonc
"vpn": "home-wg"                      // a VPN saved in the dashboard (name, case-insensitive)
"vpn": { "saved": "home-wg" }         // the same, as an object

// Or send the config itself — read it from a file or an environment variable, not from your source:
"vpn": { "type": "wireguard", "config": "<contents of wg0.conf>" }
"vpn": { "type": "openvpn", "config": "<contents of client.ovpn>", "username": "…", "password": "…" }
```

-   **Ready when it works:** the launch returns only after a real HTTPS request through your VPN has succeeded (within about 15 s); otherwise `400 vpn_connect_failed`.
-   **No leaks:** DNS goes only through the VPN (the VPN's DNS, or 1.1.1.1 through the tunnel when it names none); IPv6 is off in the session; if the VPN drops, the session goes offline — our servers' IP is never used. WebRTC shows your VPN server's IP.
-   **Either a VPN or a proxy:** `vpn` can't be combined with `proxy`, `proxy_rules` or a live proxy swap (`400 vpn_not_available`), nor with `vpn_tunnel` — it already carries UDP (`400 invalid_vpn_config`). Config, username and password together: up to 64 KB.
-   **Hysteria2 and TUIC** run over QUIC, which resets roughly one new connection in twelve at the start. Browsers retry, so pages load normally, but a single `request` from your code that isn't retried can fail — retry it.
-   Every browser supports it. Plans without dedicated threads get `403 vpn_requires_dedicated`.
-   Dedicated plans can also use [VPN Tunnel](#vpn-tunnel) with their own proxy, if they'd rather keep a proxy and add UDP.

## Formats

```jsonc
"proxy": "http://user:pass@host:8080"          // HTTP or HTTPS proxy
"proxy": "socks5://user:pass@host:1080"        // SOCKS5, with or without auth
"proxy": "host:8080"                           // no scheme = http://
"proxy": { "server": "http://host:8080", "username": "user", "password": "pass" }
```

SOCKS5 — including authenticated SOCKS5 — works on every browser.

## Pools

Pass a list and requests are spread across it round-robin:

```jsonc
"proxy": ["http://u:p@res1.example:8080", "http://u:p@res2.example:8080", "socks5://u:p@res3.example:1080"]
```

## Per-host rules

Route specific destination hosts through specific proxies with `proxy_rules`; everything else uses `proxy`. Hosts support `*` wildcards. Rules are a good way to send heavy static assets through a cheaper pool:

```json
{
  "proxy": "http://u:p@residential.example:8080",
  "proxy_rules": [
    {
      "hosts": [
        "*.cloudfront.net",
        "static.*"
      ],
      "proxy": [
        "http://u:p@dc1.example:4444",
        "http://u:p@dc2.example:4444"
      ]
    },
    {
      "hosts": [
        "api.example.com"
      ],
      "proxy": "http://u:p@special.example:8080"
    }
  ]
}
```

**On Camoufox**, a few IP-lookup services — `api.ipify.org`, `checkip.amazonaws.com`, `ipinfo.io`, `icanhazip.com`, `ifconfig.co`, `ipecho.net` — always go through the default `proxy` when rules are set, because Camoufox uses them to match its location to the exit. A rule can't redirect them there, and their traffic counts as the default route. To check a rule's exit IP on Camoufox, use another echo service, e.g. `https://ident.me`. On every other browser, rules for these hosts apply as written ([case 07](https://cdpfleet.com/docs/cases/per-host-proxy-rules)).

## Swapping the proxy live

You can change a running session's proxy without restarting the browser — handy for rotating IPs mid-session. Every session is swappable — no launch option needed. Send the new configuration to the same host as your `wsUrl`:

```http
POST https://router01.cdpfleet.com/admin/session/proxy
x-api-key: cdpf_...
content-type: application/json

{ "session_id": "46903d7c-…", "proxy": "http://u:p@new-exit.example:8080" }
```

-   **The update replaces the whole route.** Always send both `proxy` and the complete `proxy_rules` you want; sending only `proxy` drops your rules.
-   New connections use the new proxy immediately; already-open connections finish on the old one.
-   **When a swap is refused:** sessions on your own VPN (`400 vpn_not_available`: the browser's network is your VPN); [VPN Tunnel](#vpn-tunnel) sessions unless the new proxy is another Tier 1/2 `cdpfleet-resi` token (`400 tunnel_not_available`); plans with a fixed plan proxy (`403`, swap not included); a swap onto residential with no balance (`402 proxy_balance_exhausted`); a `"direct"` rule without direct access on your plan (`403`).
-   Responses: `200` updated · `404` no such session of yours · `409` the session has no swappable route · `403` your plan doesn't include live swap or direct rules · `402` residential balance used up · `400` VPN or tunnel limits above.
-   Use the host of the session's `wsUrl` (for example `router01.cdpfleet.com`).

Node.js example

```js
const host = new URL(wsUrl).host; // e.g. router01.cdpfleet.com
const r = await fetch(`https://${host}/admin/session/proxy`, {
  method: 'POST',
  headers: { 'x-api-key': KEY, 'content-type': 'application/json' },
  body: JSON.stringify({ session_id: sessionId, proxy: 'http://u:p@new-exit.example:8080' }),
});
if (!r.ok) throw new Error(`swap failed: ${r.status} ${await r.text()}`);
```

The swap applies to new connections; see the [live proxy swap case](https://cdpfleet.com/docs/cases/live-proxy-swap) for moving open ones over. Get the full launch code in the [code builder](https://cdpfleet.com/docs/builder).

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