“My requests are timing out” is one of the most common support messages we get, and it’s also one of the least specific. A timeout is a symptom, not a cause. The same error surfaces whether the gateway couldn’t find you a matching exit IP, your client gave up after 5 seconds on a connection that needed 8, the target site is slow, or your own container is misconfigured and never reaching the proxy at all.
This is a diagnostic guide: how to identify which of those is actually happening, in the order that finds it fastest. It’s the companion to reducing latency, which is about making a working setup faster; this one is about a setup that’s hanging or failing, and why.
Step 0: is it actually a timeout?
Before diagnosing, classify precisely, because three different failures get reported as “timing out” and they have different fixes:
- Connect timeout — your client couldn’t establish a connection to the gateway at all. This points at your side: network egress, firewall, wrong host/port, or container config.
- Read / response timeout — you connected fine, the request went through, but no response came back in time. This points at the exit or the target: no matching IP, a slow exit device, or a slow target site.
- Not a timeout at all — a
407(auth), a502(no IP matched your filter), or a hung CAPTCHA page. These are often reported as timeouts by wrapper code that catches everything as one exception.
Most clients let you separate connect and read timeouts explicitly. Doing so is the single highest-value diagnostic step, and it’s usually a one-line change:
import requests
# (connect_timeout, read_timeout) - separate them, don't pass a single numberr = requests.get(url, proxies=proxies, timeout=(10, 30))If it fails in the first 10 seconds, it’s a connect problem. If it survives connect and dies at 30, it’s a read problem. Read on to the matching section.
Cause 1: your geo filter is too tight
This is the most common real cause, and the most easily fixed.
Every targeting flag narrows the pool of eligible exit IPs. country-us selects from an enormous set. country-us-city-scranton-asn-12345 may select from almost nothing. When few or no exits match, requests wait, then fail, and depending on your client that surfaces as a timeout or a 502.
Diagnose it by loosening one flag at a time:
# Does it work with country only?curl -x customer-USER-country-us:PASS@p.shifter.io:443 https://api.ipify.org --max-time 30
# Then add the city back and comparecurl -x customer-USER-country-us-city-chicago:PASS@p.shifter.io:443 https://api.ipify.org --max-time 30If country-only succeeds and the narrower filter times out, you’ve found it. Fix: keep only the precision your data genuinely needs. If your use case truly requires that city, expect a smaller pool and lower throughput, and budget for it (when city-level targeting matters covers when it’s worth the cost).
Cause 2: your timeout is tuned for datacenter, not residential
A close second, and it produces “timeouts” on requests that were never actually broken.
Residential traffic routes through a real consumer device on a home network, so it has a latency floor that datacenter proxies don’t (residential vs datacenter). A 5-second total timeout, perfectly reasonable for datacenter, will cut off a healthy residential request mid-flight and report it as a failure.
Diagnose it by measuring before you tune: collect p50 and p95 latency for your actual target through the proxy (how to test proxy speed, success rate, and location accuracy has the method). If your timeout sits below your p95, you’re manufacturing failures.
Fix: set the timeout above your measured p95 with headroom, not by guesswork. As a starting point, a connect timeout around 10s and a read timeout of 30s or more is sane for residential; then tighten based on your own numbers.
Cause 3: the target is slow, not the proxy
Easy to confirm, easy to get wrong. Time the same request path against a fast, neutral endpoint and against your real target through the same proxy:
# Neutral endpoint - measures proxy overheadrequests.get("https://api.ipify.org", proxies=proxies, timeout=(10, 30))
# Your real target - measures proxy overhead + target latencyrequests.get("https://your-target.example/page", proxies=proxies, timeout=(10, 30))If the neutral endpoint is fast and the target is slow, the proxy isn’t your problem, and no amount of proxy tuning will fix it. Raise the read timeout for that target, or reduce how much of the page you pull.
Cause 4: concurrency is too high
Timeouts that appear only under load and vanish when you test a single request point here.
Two mechanisms: you may be exhausting local resources (connection pool slots, file descriptors, event-loop capacity), so requests queue on your own side before they ever leave; or the target is rate-limiting you and hanging rather than returning a clean 429.
Diagnose it by dropping concurrency to 1 and retesting. If timeouts disappear, it’s load-related. Fix: apply per-host concurrency limits rather than one global number, which is the architecture in proxy load balancing.
Cause 5: connection handling
Two opposite mistakes, both producing timeouts:
No connection reuse. Creating a fresh connection per request means paying a full TCP + TLS handshake through the proxy every time, which is slow and gives your timeout much less room. Use a session/client with pooling.
Stale pooled connections. If you pool connections but rotate exit IPs per request, pooled sockets can point at exits that are no longer valid, and those hang. Pair pooling with a sticky session so the pooled connection stays on one exit, and recycle connections periodically.
Cause 6: the exit device itself
Residential exits are real consumer devices on real home networks. Some are on congested links, some are mobile, some drop off mid-request. A small percentage of slow or failed requests is normal and expected on residential, not a defect.
Fix: don’t raise your timeout to accommodate the worst device, that just makes every failure slower. Fail fast and retry on a new identity, which gets you a different exit. Yesterday’s failover guide covers classifying transport failures and retrying correctly. Pool quality determines how thick that tail is (IP reputation).
Cause 7: it never reached the proxy at all
Worth checking early if everything times out, especially in containers.
Confirm the request is actually egressing through the gateway:
curl -x customer-USER-country-us:PASS@p.shifter.io:443 https://api.ipify.org# Returns a residential IP -> proxy is working.# Returns your own IP -> your client is ignoring the proxy.# Hangs entirely -> local egress is blocked (firewall, VPN, corporate network).In Docker and Kubernetes this is a frequent cause: the client doesn’t honor HTTP_PROXY at all, or NO_PROXY is misconfigured, or localhost doesn’t mean what you think inside a container. The Docker configuration guide covers those specifically.
Cause 8: auth or credential errors in disguise
A malformed username (a typo in a targeting flag, an unsupported parameter) or wrong credentials can present as a hang or a generic failure depending on how your client handles a 407. If your loosest possible config still fails, verify the credential string character by character before assuming a network problem.
The diagnostic order
Run these in sequence; each one eliminates a large class of causes:
- Separate connect from read timeouts. Connect failure means your side; read failure means exit or target.
- Verify you’re on the proxy at all (the ipify check above).
- Test with
countryonly. If that works, your geo filter was too tight. - Compare a neutral endpoint against your target. Isolates proxy overhead from target slowness.
- Drop concurrency to 1. If the timeouts vanish, it’s load, not the proxy.
- Check your timeout against your measured p95. If it’s below, you’re creating the failures.
Six checks, and in practice one of them explains nearly every timeout report we see.
When timeouts are actually fine
A small tail of slow and failed requests is inherent to residential proxies, because real consumer devices are inherently variable. Chasing a 100% success rate with ever-longer timeouts is the wrong goal, it makes your failures slower without making them fewer.
The right target is an SLO: define an acceptable success rate and p95 for your workload, fail fast on the tail, and retry on a fresh identity. A pipeline that fails a request in 30 seconds and succeeds on retry is healthier than one that waits 120 seconds hoping.
FAQ
Why do I get timeouts with a city or ASN filter but not with country alone? Because each flag narrows the eligible exit pool. Country + city + ASN can leave very few matching IPs, so requests wait and then fail. Loosen to the precision your data actually needs, and expect lower throughput when you genuinely need tight targeting.
What timeout values should I use for residential proxies? Measure first: your timeout should sit above your observed p95, with headroom. As a starting point, roughly 10s connect and 30s+ read is sane for residential, then tune from your own numbers. Timeouts tuned for datacenter will cut off healthy residential requests.
How do I tell if the proxy or the target is slow? Time a fast neutral endpoint and your real target through the same proxy. The neutral endpoint measures proxy overhead; the difference is the target’s own latency. If the neutral endpoint is fast, the proxy isn’t the problem.
Everything times out, even simple requests. What’s wrong? Check you’re reaching the proxy at all: curl an IP-echo endpoint through it. Your own IP means the client is ignoring the proxy; a total hang means local egress is blocked (firewall, VPN, container config). Then verify your credentials and flags.
Should I just increase my timeout? Usually not. If the cause is a tight geo filter, a slow target, or a bad exit device, a longer timeout just makes the failure take longer. Fix the cause, and for the unavoidable tail, fail fast and retry on a new identity instead.
The bottom line
A timeout is a symptom with at least eight distinct causes, and the fix depends entirely on which one you have. Separate connect from read, confirm you’re actually on the proxy, loosen your geo filter, isolate target slowness from proxy overhead, test at concurrency 1, and check your timeout against your measured p95. That sequence resolves the overwhelming majority of cases, usually in minutes.
And accept the tail: residential exits are real devices, so some variability is the cost of real-user trust. Fail fast, retry on a fresh identity, and judge the setup on success rate and p95 rather than on whether any request ever times out. If you’re still stuck after the six checks, the residential gateway docs and our team can help narrow it down, bring your connect/read split and a sample of the failing credential string, and the answer is usually quick.