Traffic accounting
Which bytes count, which don't, how the billing multiplier applies, and why your own numbers differ from the platform's.
This matters for the per-gigabyte line (dynamic residential). The accounting is described down to the byte so you can reconcile.
The rule in one sentence
Counted
- Every byte inside the tunnel once CONNECT succeeds — TLS handshake records, HTTP headers, request bodies, response bodies
- The reconstructed request line and headers in ordinary HTTP forward mode
- Chunked body wire framing (including the chunk-length markers)
- Both upload and download
Not counted
- The
CONNECTrequest line and headers you send to the gateway - The
HTTP/1.1 200 Connection Establishedthe gateway sends back - SOCKS5 greeting, authentication sub-negotiation, CONNECT request and reply
- The CONNECT / SOCKS handshake between gateway and exit
- TCP / IP / Ethernet packet headers
What one HTTPS request actually costs
Visiting an HTTPS page, the billed bytes break down roughly like this:
| Part | Typical size | Billed |
|---|---|---|
| Client-to-gateway CONNECT request | ~200 B | No |
| The gateway's 200 response | ~40 B | No |
| TLS ClientHello / ServerHello / certificate / Finished | 3–6 KB | Yes |
| HTTP request headers (encrypted) | 0.5–2 KB | Yes |
| HTTP response headers | 0.5–2 KB | Yes |
| Response body | Depends | Yes |
So "an API call returning a few dozen bytes of JSON" actually bills around 5–10 KB, most of it TLS handshake. Reuse connections for this kind of workload.
The billing multiplier
Raw bytes are multiplied by a product multiplier before being deducted from your balance. The multiplier is expressed in parts per million (PPM), and the accumulated value is floored.
billed bytes = floor(accumulated raw bytes × multiplier ÷ 1,000,000)
A multiplier of 1,000,000 is 1:1. Check the product description or the console's product detail for the actual value.
Settlement and statistical dimensions
Daily aggregates settle on Beijing-time calendar days. Keep that in mind when reconciling across timezones — your UTC-based daily consumption will differ from the platform's by several hours' worth.
The dimensions available in usage statistics are covered in Usage statistics.
Hourly and hourly-per-domain detail is retained for 60 days, after which only daily aggregates remain. Export regularly if you need longer retention.
Why your numbers don't match the platform's
When your own byte counting disagrees with the platform's, it's nearly always one of these:
| Your counting | Platform counting | Difference |
|---|---|---|
| Response body only | TLS handshake + request headers + response headers + body | 5–10 KB more per connection |
| Decompressed size | Actual bytes on the wire (compressed) | Platform's number is smaller |
| Successful requests only | Every byte written to the socket, including partial responses of failed requests | Platform's number is larger |
| Days split by UTC | Days split by Beijing time | An 8-hour boundary offset |
| Retries excluded | Every retry counted | Platform's number is larger |
Reducing traffic
Ordered by impact:
Make sure compression is on
curl -H 'Accept-Encoding: gzip, deflate, br' ...
HTML / JSON / CSS / JS typically compress 60–80%. This is the biggest single saving.
Block images and fonts in browser automation
# Playwright
def block_heavy(route):
if route.request.resource_type in {"image", "media", "font"}:
route.abort()
else:
route.continue_()
context.route("**/*", block_heavy)
Images and fonts routinely account for 60–80% of a modern page's first-paint traffic.
Reuse connections
Each new HTTPS connection carries 3–6 KB of TLS handshake overhead. With dense request patterns, reuse saves a meaningful amount.
Note this conflicts with rotating IPs — handshake overhead is the cost of changing IP. The compromise is reusing connections within a sticky session and only rotating when necessary.
Probe with HEAD
Use HEAD instead of GET when you only need to know whether a resource exists or want the headers:
curl -I -x 'http://USER-country-US:PASS@GATEWAY_HOST:58971' https://example.com/large-file
Don't fetch pages you don't need
Obvious, but in practice the largest waste is usually crawling a whole site and using a small fraction of it. Decide what you actually need first.
Per-IP product lines don't consume traffic
Static residential, datacenter and unlimited residential never deduct from the traffic pool.
Unlimited residential has two billing modes: the port edition charges by port count × validity period with a 6 Mbps aggregate cap per endpoint; the bandwidth edition charges by account-wide aggregate bandwidth × validity period. Neither edition deducts gigabytes.
How long a balance lasts
Dynamic residential traffic accumulates into the pool on purchase. In the current implementation there is no code-level automatic expiry or forfeiture — the balance is not zeroed out by the passage of time.
How long a quote lasts
Dynamic residential quotes are valid for 5 minutes by default, shortened further if a promotion ends or the product is delisted sooner.
So a flow of "get a quote → show the user → the user deliberates for ten minutes → place the order" will fail. Either shorten the decision window or re-quote before ordering.
Unpaid orders
Expire after 30 minutes by default, with inventory automatically returned. Stripe checkout links are retained for 30 days.
Related
- Inspecting usage → Usage statistics
- Setting sub-account caps → Proxy sub-accounts
- What running out looks like → Error reference