docs
How proxycanary reads, probes and reports.
Everything the checker does, in the order it does it. If something here disagrees with what you see on the site, the site is the bug.
Proxy formats
One proxy per line, or separated by commas or spaces. Junk lines are skipped and counted; duplicates are collapsed.
203.0.113.10:8080
user:[email protected]:8080
203.0.113.10:8080:user:pass
socks5://203.0.113.10:1080
http://user:[email protected]:3128A scheme (http, https, socks4, socks5) pins the protocol. Without one, the protocol is detected. Credentials are used for the probe and echoed back to you in the results.
Protocols and detection
- http
- Plain HTTP proxy. The judge request is sent with an absolute URL.
- https
- HTTP proxy that accepts CONNECT. We tunnel a TLS session to the judge's port 443.
- socks4
- SOCKS4 CONNECT to the judge, then a plain HTTP request inside the tunnel.
- socks5
- SOCKS5 CONNECT, with username/password auth when credentials are given.
With no scheme and protocol set to Auto, the order is http, then socks5, then socks4. The first protocol that yields a valid judge response wins. A refused connection or a connect timeout stops the sequence early, since another handshake will not change that.
Anonymity levels
The judge is a plain-HTTP endpoint that returns the address it saw the request come from and every header it received. The level is decided from that, not from anything the proxy claims about itself.
- transparent
- Your real address appeared in a forwarded header (X-Forwarded-For, Forwarded, X-Real-IP, Via and friends).
- anonymous
- Your address was hidden, but a header gave the proxy away (Via, X-Forwarded-For with another address, Proxy-Connection, X-Cache, ...).
- elite
- Neither. The judge saw an ordinary request from the exit address.
CONNECT tunnels (the https protocol) carry no proxy headers by design, so their anonymity is judged from the plain-HTTP attempt when one succeeded.
Network kinds
The exit address is looked up in an IP intelligence database. Three flags come back and are shown as one label:
- mobile
- The exit belongs to a carrier range, the kind phones get their addresses from.
- dc
- A hosting or cloud provider range. These are the first to be blocked by anti-bot systems.
- isp
- Anything else: a consumer or business ISP line, usually called residential.
Country, city, ISP and ASN come from the same lookup. Lookups are cached for 30 days, so a range that changes hands may lag by up to that long.
Limits
- per run
- 10,000 proxies. Longer lists are cut at 10,000.
- concurrency
- 200 probes at a time, shared across all runs on the service.
- timeout
- 1 to 10 seconds per proxy, default 5. Covers connect plus the full request.
- bulk runs
- 30 per 10 minutes per address.
- single checks
- 60 per minute per address.
API
The same checker the site uses. No key. Send JSON, read server-sent events. Cancel a run by closing the connection.
POST /api/check
curl -N -X POST https://proxycanary.com/api/check \
-H "Content-Type: application/json" \
-d '{
"proxies": ["203.0.113.10:8080", "socks5://198.51.100.7:1080"],
"protocol": "http", // optional: http | https | socks4 | socks5
"timeoutMs": 5000 // optional: 1000..10000
}'Events, in order: one start, one result per proxy (alive rows may arrive twice, the second time with geo), one done.
event: start
data: {"type":"start","runId":"…","total":2,"skipped":0}
event: result
data: {"type":"result","result":{"id":"0","proxy":{"host":"203.0.113.10","port":8080},
"status":"alive","protocol":"http","latencyMs":112,"connectMs":38,
"anonymity":"elite","exitIp":"203.0.113.10","countryCode":"DE",
"country":"Germany","asn":"AS24940","mobile":false,"hosting":true}}
event: result
data: {"type":"result","result":{"id":"1","proxy":{"host":"198.51.100.7","port":1080},
"status":"dead","error":"connect_timeout"}}
event: done
data: {"type":"done","runId":"…","alive":1,"dead":1,"durationMs":5210}POST /api/check/single
curl -X POST https://proxycanary.com/api/check/single \
-H "Content-Type: application/json" \
-d '{"proxy": "203.0.113.10:8080"}'Returns one JSON object with the fields above plus judgeHeaders (what the judge received), intel (the full network lookup) and triedProtocols. The id is the report id used by GET /api/report/:id and the share link at /r/:id.
Errors
- connect_timeout
- No TCP connection within the timeout.
- connection_refused
- Port closed or firewalled.
- read_timeout
- Connected, but no complete response in time.
- auth_required
- The proxy wants credentials (407 or SOCKS auth failure).
- judge_status_NNN
- The proxy answered with an HTTP status instead of relaying (403, 503, ...).
- bad_judge_response
- Something answered, but not the judge. Usually a captive page or a block page.
- tampered_response
- A judge-shaped response that did not carry our request. Treated as dead.
- not_socks
- The declared SOCKS version was not spoken on that port.