Use residential proxies in Python with the code you already have. No SDK, no client library, no API key: give requests, aiohttp or httpx one proxy URL and every request leaves from a real home IP, in the country you pick, with the browser fingerprint you pick.
One proxy URLrequests, aiohttp and httpx work as they are
Real home IPs219 countries, down to the city
Browser TLS at the gateway139 fingerprints, no curl_cffi
Ludax works with any Python HTTP client through one proxy URL, http://resi-USERNAME:[email protected]:7777: no SDK, no client library, no API key.
Without a session token every new connection leaves from a new residential IP. With -session-<token>-time-<minutes> in the password the IP holds for up to 1000 minutes; without -time- it holds for 1 minute. On the TLS ports add -sameip to hold the IP too.
The location goes in the password after the session: -country-de, then -state-by, then -city-munich.
Residential TLS (gw.ludaxproxy.com:9999) and Residential Premium TLS (gw.ludaxproxy.com:8081) connect to the site with a real browser TLS handshake, chosen in the username (-AE-chrome154, 139 profiles), and need the Ludax CA certificate.
407 means a wrong username or password, or a plan with no data left; 502 means the exit failed and a retry helps. 30 failed logins in 5 minutes block the client IP for 10 minutes.
SOCKS5 runs on Residential (gw.ludaxproxy.com:7575) and Residential Premium (gw.ludaxproxy.com:1080); socks5h:// makes the exit resolve DNS.
Plans are prepaid, with no subscription, from $0.99 for 1 GB of Residential.
Using an AI assistant? Give it this guide
One Markdown file with everything ChatGPT, Claude, Cursor or Copilot needs to write working Ludax code: the URL format, the gateways in force, sessions, TLS, errors and tested examples. Copy it into the chat, or paste this prompt:
Read https://ludaxproxy.com/docs/python.md and use Ludax proxies in my Python scraper.
Two minutes, start to finish. If you see a JSON answer at the end, your Python proxy is connected, and everything after this is options.
Get your username and password
In the dashboard, open Generate. Your username looks like lx_k3m9q2p7xa and is the same for all your plans; each plan has its own 16-character password. In the proxy URL the username gets the product prefix: resi- for Residential, premi- for Residential Premium.
No account yet? Get 1 GB of Residential for $0.99: an email address is all it takes, you pay in crypto, and you are ready in a minute.
That is a real home connection in Germany, picked by -country-de in the password. tls_profile is None because the site sees Python’s own handshake (why that matters). Change de to us, jp or any of the 181 country codes and run it again.
[ 02 / CODE GENERATOR ]
Python proxy code generator: pick, copy, run
Choose the product, the country and how the IP should behave, and the code writes itself for requests, aiohttp or httpx. Type your own username and password to get code you can run as is: they stay in this browser tab and are never sent anywhere.
import requests
proxy = "http://resi-lx_k3m9q2p7xa:[email protected]:7777"
proxies = {"http": proxy, "https": proxy}
# a new IP on every new connection
r = requests.get("https://api.ludaxproxy.com/whoami", proxies=proxies, timeout=30)
print(r.json())
The TLS gateways need the Ludax CA once: download ludax-ca.crt and keep it next to your script. Why?
[ 03 / RECIPES ]
Python proxy recipes: rotating, sticky, geo and async
Each one runs on its own: paste it, put in your username and password, run. The outputs show what you should see.
01
Rotating proxies in Python: a new IP on every request
import requests
USER = "resi-lx_k3m9q2p7xa"
PASS = "YOUR_PASSWORD-country-us"
proxy = f"http://{USER}:{PASS}@gw.ludaxproxy.com:7777"for i inrange(5):
# requests.get opens a new connection each time, so each call gets a new IP
r = requests.get("https://api.ludaxproxy.com/whoami",
proxies={"http": proxy, "https": proxy}, timeout=30)
print(i, r.json()["ip"])
Login, search, add to cart, checkout: anything a site expects from one visitor. A random token per job keeps each job on its own IP.
sticky_loop.py
import secrets
import requests
USER = "resi-lx_k3m9q2p7xa"
PASS = "YOUR_PASSWORD"for job inrange(3):
token = secrets.token_hex(4) # a new random proxy session = a new IP for this job
proxy = f"http://{USER}:{PASS}-session-{token}[email protected]:7777"# requests.Session keeps the site's cookies (your login) from one step to the nextwith requests.Session() as s:
s.proxies = {"http": proxy, "https": proxy}
ips = [s.get("https://api.ludaxproxy.com/whoami", timeout=30).json()["ip"]
for step in ("login", "search", "checkout")]
print(f"job {job} (session {token}): {ips}")
Two different sessions work together here. The proxy session (-session- in the password) keeps the IP; the requests.Session keeps the cookies, so the site still knows you are logged in. A login flow needs both. Proxy sessions hold for up to 1000 minutes on every plan; always send -time-, without it a session lasts 1 minute. On the TLS ports add -sameip after the time (-session-9f2c41ab-time-10-sameip), or only the browser profile is held and the IP still changes.
import requests
defproxy(password):
url = f"http://resi-lx_k3m9q2p7xa:{password}@gw.ludaxproxy.com:7777"return {"http": url, "https": url}
# a country
requests.get("https://api.ludaxproxy.com/whoami", proxies=proxy("YOUR_PASSWORD-country-jp"), timeout=30)
# a region and a city in it (Bavaria, Munich)
requests.get("https://api.ludaxproxy.com/whoami",
proxies=proxy("YOUR_PASSWORD-country-de-state-by-city-munich"), timeout=30)
# everything together: one IP in New York for 30 minutes
requests.get("https://api.ludaxproxy.com/whoami",
proxies=proxy("YOUR_PASSWORD-session-ny01-time-30-country-us-state-ny-city-newyork"), timeout=30)
Order matters: session first, then -country-, -state-, -city-. Codes for every country are in the locations directory (for example Germany, the United States and Japan) and in the dashboard's generator.
04
Async proxies with aiohttp
50 pages, ten at a time, each from a different IP.
async_aiohttp.py
import asyncio
import aiohttp
PROXY = "http://resi-lx_k3m9q2p7xa:[email protected]:7777"
URLS = [f"https://api.ludaxproxy.com/whoami?page={n}"for n inrange(50)]
asyncdeffetch(session, url):
asyncwith session.get(url, proxy=PROXY) as r:
return (await r.json())["ip"]
asyncdefmain():
# limit=10: ten requests in flight; force_close: a new connection, so a new IP, each time
connector = aiohttp.TCPConnector(limit=10, force_close=True)
timeout = aiohttp.ClientTimeout(total=30)
asyncwith aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
ips = await asyncio.gather(*(fetch(session, url) for url in URLS))
print(len(ips), "requests from", len(set(ips)), "different IPs")
asyncio.run(main())
If your project already uses httpx. Needs httpx 0.26 or later for proxy=.
async_httpx.py
import asyncio
import httpx
PROXY = "http://resi-lx_k3m9q2p7xa:[email protected]:7777"
URLS = [f"https://api.ludaxproxy.com/whoami?page={n}"for n inrange(50)]
asyncdefmain():
# max_connections=10: ten in flight; no keep-alive: a new connection, so a new IP, each time
limits = httpx.Limits(max_connections=10, max_keepalive_connections=0)
asyncwith httpx.AsyncClient(proxy=PROXY, limits=limits, timeout=30) as client:
responses = await asyncio.gather(*(client.get(url) for url in URLS))
ips = [r.json()["ip"] for r in responses]
print(len(ips), "requests from", len(set(ips)), "different IPs")
asyncio.run(main())
SOCKS5 proxies in Python without DNS leaks: socks5h://
When your tool speaks SOCKS5. The h makes the gateway resolve the hostname, so no DNS query leaves from your machine. SOCKS5 is on Residential and Residential Premium.
Production scrapers. Retry what a retry can fix (502, timeouts), never 407.
retry.py
import time
import requests
defget(url, proxy, tries=4):
"""GET through Ludax: retry a dropped exit, stop at once on 407 and certificate errors."""
proxies = {"http": proxy, "https": proxy}
for attempt inrange(1, tries + 1):
try:
r = requests.get(url, proxies=proxies, timeout=30)
if r.status_code != 502:
return r # a 407 comes back here too: a retry cannot fix credentials
error = RuntimeError(f"502 Bad Gateway on attempt {attempt}")
except requests.exceptions.SSLError:
raise# on the TLS gateways: pass verify="ludax-ca.crt"except requests.exceptions.ProxyErroras e:
if"407"instr(e):
raise# wrong username or password, or no data left on the plan
error = e # Tunnel connection failed: 502except (requests.exceptions.ConnectionError, requests.exceptions.Timeout) as e:
error = e # the exit dropped mid-requestif attempt < tries:
time.sleep(2 ** (attempt - 1)) # 1, 2, 4 seconds; no wait after the last tryraiseRuntimeError(f"{url}: no answer after {tries} tries") from error
Use it in place of requests.get: r = get("https://example.com", proxy). A 407 or a certificate error stops at once with the real message; a 502 or a dropped connection is tried again after 1, 2 and 4 seconds.
[ 04 / GETTING BLOCKED? ]
Python requests blocked? Fix the TLS fingerprint, keep your code
If a site blocks your Python scraper even from a clean home IP, it is usually not the IP. It is the TLS handshake.
Before a site reads your URL or a single header, your client says hello: the TLS handshake. Chrome says hello one way; Python’s ssl module (so requests, aiohttp and httpx) says it in a way no browser does. Anti-bot systems read that hello as a fingerprint (JA3/JA4) and block on it, however good the IP is.
The usual fix is to switch libraries (curl_cffi, tls-client) and rewrite your code around them. With Residential TLS proxies you change the proxy URL instead: the gateway makes the connection to the site with a real browser’s handshake, HTTP/2 settings and matching headers.
WHAT CHANGES IN YOUR CODE
- proxy = "http://resi-lx_k3m9q2p7xa:[email protected]:7777"+ proxy = "http://resi-lx_k3m9q2p7xa-AE-chrome154:[email protected]:9999"- r = requests.get(url, proxies=proxies, timeout=30)+ r = requests.get(url, proxies=proxies, timeout=30, verify="ludax-ca.crt")
The TLS gateway: gw.ludaxproxy.com:9999 (Residential Premium TLS: gw.ludaxproxy.com:8081).
-AE-chrome154 at the end of the username: the browser to look like. AE also sets a matching User-Agent for you.
ludax-ca.crt, downloaded once: the gateway re-signs HTTPS to send the browser handshake, so your client trusts its CA.
The whoami endpoint reads your handshake the way an anti-bot system does. Plain requests prints None; through the TLS gateway it prints the browser you picked.
TWO WAYS TO LOOK LIKE A BROWSER
curl_cffi / tls-client
Ludax Residential TLS
Your code
A different HTTP library and its own API
Your requests, aiohttp or httpx code, unchanged
Where the handshake is made
On your machine, by a compiled extension
At the gateway
User-Agent and client hints
You keep them consistent yourself
AE sets them to match the profile
Browser profiles
The ones your library version ships
139: Chrome, Edge, Firefox, Safari, Opera, OkHttp
Residential IP
Still needs a proxy
Included: the same request
Try it on the site that blocks you
1 GB of Residential TLS is enough to test a target properly, and the same username keeps working when you scale.
Good to know: AE replaces your User-Agent; with NAE your headers pass through unchanged, so send a User-Agent from the same browser. Apps with certificate pinning refuse a re-signed certificate: use the standard gateways (gw.ludaxproxy.com:7777, gw.ludaxproxy.com:8080) for those. Request and response bodies are never stored. All 139 profiles: TLS profiles.
[ 05 / TROUBLESHOOTING ]
Python proxy errors: 407, 502, SSL and more
Every error a Python client gets from the gateway, what it means and the one thing to do. All codes: status codes.
SYMPTOM, CAUSE, FIX
You see
Why
Fix
407 Proxy Authentication Required
Wrong username or password, a space or quote pasted into the password, or the plan's data is used up or expired.
Copy the credentials again from Generate and check the plan in the dashboard. Do not loop retries: 30 failed logins in 5 minutes block your IP for 10 minutes.
502 Bad Gateway or Tunnel connection failed: 502
The exit IP dropped mid-request or could not reach the site.
Retry (recipe 07). With a sticky session, switch to a new token after two failures. Many at once: check the network status.
CERTIFICATE_VERIFY_FAILED on a TLS gateway
The TLS gateways re-sign HTTPS with the Ludax CA.
Download ludax-ca.crt once: requests verify="ludax-ca.crt", httpx and aiohttp an ssl.create_default_context(cafile="ludax-ca.crt").
The same IP every time, with no session
Your client reuses one open connection (a requests.Session, an httpx client, aiohttp keep-alive).
No. Ludax is an ordinary HTTP proxy. Put your username and password in a proxy URL and pass it to requests, aiohttp or httpx the way you would pass any proxy. There is nothing to install from us and no API key.
02How do I get a new IP for every request?
Send no -session- in the password. Every new connection then leaves from a new IP. Clients that keep connections open (a requests.Session, an httpx client, an aiohttp session) reuse the same connection and IP: use requests.get, aiohttp with force_close=True, or httpx with max_keepalive_connections=0.
03How do I keep the same IP for a login or checkout flow?
Add -session-<any token>-time-<minutes> to the password and send the same token on every request of the flow. Always add -time-: without it a session lasts 1 minute. Up to 1000 minutes on every plan, Premium included. On the TLS ports also add -sameip (-session-<token>-time-<minutes>-sameip), or only the browser profile is held.
04Do I still need curl_cffi, tls-client or a headless browser?
Not for the TLS fingerprint. Through the Residential TLS gateway (gw.ludaxproxy.com:9999) or the Premium TLS one (gw.ludaxproxy.com:8081) the site sees a real browser handshake while your code stays plain requests, aiohttp or httpx. A headless browser is only still needed when the site builds its content with JavaScript.
05Why socks5h and not socks5?
With socks5://, requests looks the hostname up on your own machine, so the DNS query leaves from your network. With socks5h:// the gateway resolves it at the exit instead. SOCKS5 is on Residential (gw.ludaxproxy.com:7575) and Residential Premium (gw.ludaxproxy.com:1080).
06Why do I get CERTIFICATE_VERIFY_FAILED on the TLS gateways?
The TLS gateways re-sign HTTPS with the Ludax CA so they can send the browser handshake. Download the certificate once (curl -O https://ludaxproxy.com/downloads/ludax-ca.crt). In requests pass verify="ludax-ca.crt"; in httpx and aiohttp pass ssl.create_default_context(cafile="ludax-ca.crt"), as verify= and ssl= respectively.
07Is there a free trial?
No: the smallest plan is the test. 1 GB of Residential costs $0.99 and 1 GB of Residential TLS $1.49, with no subscription, and your username stays the same when you buy more.
[ 07 / KEEP GOING ]
Where to go from here
The products behind the code above, and guides for the jobs Python developers run on them.