Async proxy checking engine — library first, CLI included.
Raw-asyncio core (no HTTP framework in the hot path) checks SOCKS4/SOCKS5/HTTP/HTTPS proxies at hundreds of concurrent connections, then enriches survivors with GeoIP, download speed, anonymity classification, and content-tamper detection.
Status: alpha (v0.2) — API may still shift before 1.0.
Python 3.10+ · MIT
| proxpy | typical aiohttp-based checkers | |
|---|---|---|
| Transport | raw asyncio handshakes (SOCKS5 per RFC 1928, CONNECT tunnels, TLS upgrade) | HTTP-framework wrappers |
| Anonymity detection | inspects leak headers (X-Forwarded-For, Via, Forwarded, …) → elite / anonymous / transparent |
usually "exit IP == your IP?" only |
| Auth proxies | full user:pass on all protocols + Proxy-Authorization | often dropped silently |
| HTTPS targets | real CONNECT tunnel + TLS upgrade through the proxy | plain-HTTP target only |
| Content-tamper (hijack) detection | yes — hashes a reference page fetched through the proxy | no |
| Source benchmarking | built-in preset comparison with p50/p95 latency stats | no |
| Streaming results | check_stream() async generator, cancel-safe |
batch only |
pip install proxpy # library
pip install "proxpy[cli]" # + rich TUI / typer CLIRequires Python 3.10+. Optional: drop GeoLite2-Country.mmdb into
~/.config/proxpy/ for instant local GeoIP lookups (otherwise an HTTPS API is used).
import asyncio
from proxpy import check, check_stream, check_one
async def main():
# Batch: fetch a list, return sorted valid proxies (+ metadata)
result = await check(
"https://raw.githubusercontent.com/monosans/proxy-list/main/proxies/socks5.txt",
protocol=None, # None = auto-detect per proxy hint / probe all
concurrency=200,
timeout=5.0,
limit=500,
geoip=True,
)
print(f"{len(result.valid)} alive of {result.total} checked")
for p in result.valid[:10]:
print(p.address, p.protocol.value, f"{p.ping_ms}ms", p.country_code)
asyncio.run(main())from proxpy import check_stream
async for proxy in check_stream(source_url, concurrency=200):
print(proxy.address, proxy.ping_ms)
# stop early = remaining checks are cancelled automaticallyp = await check_one("socks5://user:pass@1.2.3.4:1080")
print(p.valid, p.protocol, p.ping_ms)from proxpy import check_anonymity, check_hijack
level = await check_anonymity(proxy, protocol) # elite / anonymous / transparent
clean = await check_hijack(checked_proxy) # True=clean False=tampered None=n/aOr in one call:
result = await check(src, check_anonymity_flag=True, check_hijack_flag=True)
for p in result.valid:
if p.is_hijacked is False and p.anonymity_level == "elite":
... # best-quality proxiesEvery CheckedProxy carries: ip, port, address, protocol, ping_ms, speed_kbs, country, country_code, anonymity_level, is_hijacked — and serializes via to_dict().
await proxpy.acleanup() # closes shared HTTP clients; call when done (async ctx)# Check a source with live progress; interactive table output
proxpy --source proxies.txt -t socks5 -c 200
# Built-in presets, filter by country/ping, export
proxpy --preset monosans-s5 --country DE,NL --cull 400 --export alive.txt
# Machine-readable
proxpy --preset speedx-http -f json
proxpy --source list.txt -f csv --top 20
# Flagship features
proxpy --source list.txt --anonymity --hijack # adds columns to table, fields to json/csv
proxpy --source list.txt --check-speed # KB/s column
# Single proxy
proxpy check 1.2.3.4:1080 -t all
# Compare sources by quality
proxpy benchmark speedx-s5 monosans-s5 proxifly-all --top 5
proxpy preset --add mylist https://example.com/list.txtCredentials in exports are redacted (ip:port:***:***) by default;
pass --export-credentials to write them in clear text.
Config lives at ~/.config/proxpy/config.toml; env overrides:
PROXPY_THREADS, PROXPY_TIMEOUT, PROXPY_CHECK_URL, PROXPY_SPEED_URL, PROXPY_GITHUB_TOKEN.
- GeoIP uses an HTTPS API (plaintext fallback only as last resort).
- Private/reserved-range entries can be dropped at parse time:
parse_proxies(text, skip_private=True). - A free-list proxy is a man-in-the-middle by design. The hijack detector exists precisely because "alive" never means "trustworthy".
git clone <repo> && cd proxpy
uv sync --extra cli
uv run pytest -q # 290+ tests incl. loopback integration servers
uv run ruff check proxpy tests
uv run python -m mypy proxpy --ignore-missing-importsMIT — see LICENSE.