Choosing a proxy type
A decision procedure for picking the cheapest pool that will work.
The temptation is to reach for residential proxies because they have the highest success rate. They are also the most expensive per gigabyte, and for a large share of workloads they are unnecessary. Work down this list and stop at the first line that matches.
- 1Does the target serve the same content to a datacenter IP as to a home connection? If yes, use datacenter. It is roughly fifty times cheaper per gigabyte and considerably faster.
- 2Does the target need a residential-looking address but you also need the address to stay fixed for hours? Use ISP. You get datacenter speed on an address registered to a consumer ISP.
- 3Is the target a mobile app API, or does it treat carrier IPs differently? Use mobile. Carrier-grade NAT means these addresses are shared by thousands of real subscribers, which makes them very hard to block.
- 4Is the target behind a serious anti-bot vendor, or does it personalise by neighbourhood? Use residential.
- 5Does a partner need to allowlist your egress address? Use dedicated.
Cost comparison at 100 GB
| Product | Unit price | 100 GB | Median latency |
|---|---|---|---|
| Datacenter | $0.55 / GB | $55 | 0.18 s |
| ISP | $2.40 / IP / mo | unmetered | 0.22 s |
| Residential | $3.20 / GB | $320 | 0.64 s |
| Mobile | $4.80 / GB | $480 | 0.88 s |
Test before you commit
Success rates are workload-specific. Run a few hundred requests against your real target on the cheaper pool before assuming you need the expensive one — the free gigabyte exists precisely for this.
Mixing products
Nothing stops you using several at once, and most mature pipelines do. A common pattern is to attempt every URL on datacenter, then retry only the failures on residential. If your datacenter success rate is 70%, that single change cuts the bill by about two thirds against a residential-only run.
DC = "http://wp-acc4821:s3cr3t-pass@dc.wproxy.io:8000"
RES = "http://wp-acc4821-country-us:s3cr3t-pass@res.wproxy.io:8000"
def fetch(url):
for proxy in (DC, RES):
try:
r = requests.get(url, proxies={"https": proxy}, timeout=20)
if r.status_code == 200:
return r
except requests.RequestException:
continue
raise RuntimeError(f"both pools failed for {url}")