Documentation menu

How pay-per-GB traffic is counted

Pay-per-GB (PPG) proxies bill the traffic between your client and the Litport hub. This page explains what counts, what happens when you disconnect early, and how to cut billed traffic. It covers TCP connections through HTTP CONNECT and SOCKS5 without cache mode.

What counts as traffic#

Litport counts every byte your client and the hub exchange, in both directions, while the connection is open.

Part of the connection Counted
Proxy handshake: the CONNECT request and response, or the SOCKS5 negotiation Yes
TLS handshake and record overhead, including TLS to the proxy itself Yes
Your request, including any upload body Yes
The response Yes, as far as the hub has sent it to you

Is upload billed?#

Yes. Upload and download are both billed, byte for byte.

Is TLS overhead billed?#

Yes. The TLS handshake and record framing are bytes through the hub. See what an https:// proxy costs.

Is there a minimum per request?#

No. Traffic is billed in exact bytes per token and hour, with no per-request minimum and no rounding up.

What about cache mode?#

With cache mode on, the hub reads your HTTPS requests itself. Cache hits are free; misses and bypasses are billed as described in Cache options and troubleshooting. The rest of this page covers traffic without cache mode.

Am I billed for a request I cancel?#

You are billed for what was transferred until you disconnected, not for the whole response. When your client closes the connection, the hub ends the tunnel and closes its upstream connection. Bytes the hub had already sent toward you still count, even if your client never read them: they were in transit or in buffers when you closed.

Disconnecting early saves the most on large responses and slower connections. On a fast connection, much of a small response may already be on its way when you disconnect.

Measured results#

We tested through one hub, using HTTP CONNECT, SOCKS5, and TLS to the proxy, on two residential pools and one datacenter pool. The figures are medians per request, failed requests included. Your figures depend on response size, speed, and your client.

What the client did Requests Billed, median per request
Read a whole 220 KB body 290 230 KB; 235 KB with TLS to the proxy
Disconnected after about 50 KB of a 220 KB body, residential pools 1,160 86–95 KB
The same with a slow body (220 KB sent over 5 seconds) 1,100 56 KB
Disconnected after about 50 KB of a 2 MB or 5 MB body, residential pools 200 76–85 KB
Disconnected after about 50 KB of a 220 KB body, datacenter pool 30 192 KB
Stopped reading after about 50 KB but kept the connection open for 20 seconds 30 230 KB
Disconnected 3 seconds after sending a request whose response came 10 seconds later 630 5.8–5.9 KB
Disconnected right after the TLS handshake 600 5.8 KB

How to cut billed traffic#

  1. Disconnect as soon as you have what you need. Count the bytes you receive, not the decompressed size.
  2. Close the connection to the proxy. Only stopping reading in your application does not stop the transfer or the billing; see the results above.
  3. Don't return a connection you cut short to a keep-alive pool.
  4. If you disconnect before any response, you pay about the handshake plus the request, as in the delayed-response test above. A response that is already on its way when you disconnect is counted. Litport can't tell you whether the site received or processed a request that was still in transit.
  5. In a browser, cancelling a request may keep the proxy connection open. Measure billed traffic for your setup before relying on it.
  6. Serve repeated static files from the static response cache, and block images, media, and fonts you don't need.
  7. Check the result per token in Traffic statistics.

Node.js example#

This closes the tunnel once 50 KB of the response has arrived. In our tests that was billed about 94 KB, against about 230 KB for reading the whole response. The 94 KB is more than 50 KB because it also includes the TLS handshake, the request and the headers (about 7 KB), plus data that was already on its way when the tunnel closed.

import https from 'node:https'
import { HttpsProxyAgent } from 'https-proxy-agent'

const agent = new HttpsProxyAgent('http://USERNAME:[email protected]:1337')

const req = https.get('https://example.com/page', { agent }, (res) => {
  let received = 0
  res.on('data', (chunk) => {
    received += chunk.length
    if (received >= 50_000) req.destroy() // closes the tunnel; counting stops here
  })
})
req.on('error', () => {})