Setup
Generate an endpoint in the Geonode dashboard (product, rotating or sticky session, location, host:port:username:password format) and export the values:
export GEONODE_HOST="<host>"
export GEONODE_PORT="<port>"
export GEONODE_USER="<username>"
export GEONODE_PASS="<password>"Keep credentials out of code and out of version control. A small helper builds proxy URLs everywhere else:
import os
from urllib.parse import quote
def geonode_url(country=None, scheme="http"):
user = os.environ["GEONODE_USER"] + (f"-country-{country}" if country else "")
pw = quote(os.environ["GEONODE_PASS"], safe="")
return f"{scheme}://{user}:{pw}@{os.environ['GEONODE_HOST']}:{os.environ['GEONODE_PORT']}"The -country- suffix follows the pattern in Geonode's documentation (for example -country-jp); use your dashboard's exact format. URL-encoding the password avoids errors when it contains characters such as @ or :.
requests
import requests
proxy = geonode_url("us")
r = requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=30)
print(r.text)For several requests that should share cookies and an IP (with a sticky endpoint), use a Session:
s = requests.Session()
s.proxies = {"http": proxy, "https": proxy}
s.get("https://example.com/", timeout=30)
s.get("https://example.com/page/2", timeout=30)httpx
import httpx
with httpx.Client(proxy=geonode_url("gb"), timeout=30) as client:
print(client.get("https://api.ipify.org").text)httpx also supports HTTP/2 and async clients with the same proxy option.
aiohttp for concurrency
import asyncio
import aiohttp
async def fetch(session, url, sem):
async with sem:
async with session.get(url, proxy=geonode_url("us"), timeout=aiohttp.ClientTimeout(total=30)) as r:
return r.status, await r.text()
async def main(urls):
sem = asyncio.Semaphore(20)
async with aiohttp.ClientSession() as session:
return await asyncio.gather(*(fetch(session, u, sem) for u in urls), return_exceptions=True)Cap concurrency per target domain to stay polite and avoid blocks.
SOCKS5
Geonode lists SOCKS5 support for residential proxies. With requests, install the SOCKS extra (pip install "requests[socks]") and use the socks5h scheme so DNS is resolved through the proxy:
proxy = geonode_url("de", scheme="socks5h")
requests.get("https://api.ipify.org", proxies={"http": proxy, "https": proxy}, timeout=30)SOCKS5 may use a different port from HTTP; check the dashboard. See SOCKS5 proxies.
Proxy tip: Before scaling, run a short pilot on your real targets with Geonode and record success rate, latency and GB per result. Our our complete Geonode guide explains which Geonode product to start with.
Retries and block detection
Check for real content, not just status 200, and retry with a new IP:
import time
def get_with_retry(url, marker, attempts=3):
for n in range(attempts):
p = geonode_url("us")
try:
r = requests.get(url, proxies={"http": p, "https": p}, timeout=30)
if r.ok and marker in r.text:
return r
except requests.RequestException:
pass
time.sleep(1 + n * 2)
return NoneWith a rotating endpoint, each new connection gets a new exit. Disable connection reuse (use fresh requests rather than one session) when you want a new IP per attempt.
Common errors
| Error | Meaning | Fix |
|---|---|---|
407 Proxy Authentication Required | Credentials or username format wrong | Re-copy from dashboard; URL-encode the password |
ProxyError / connection refused | Wrong host or port, or blocked outbound port | Check endpoint; test with cURL |
SSLError through proxy | Corporate interception or wrong scheme | Use http:// for the proxy URL; don't disable verification |
ReadTimeout | Slow exit | Raise timeout moderately; retry with a new IP |
InvalidSchema for SOCKS | SOCKS support not installed | Install requests[socks] |
See common proxy errors.
Picking a Geonode product for your Python job
The Python examples above work with any Geonode product; only the endpoint changes. Choose based on the target and the shape of the job.
| Python job | Geonode product | Notes |
|---|---|---|
| Data from public portals and lenient sites | Rotating datacenter | Cheapest per GB; test first |
| Scraping protected retailers, marketplaces or search pages | Rotating residential | New connection per request for a new exit |
| Logged-in or multi-page flows | Sticky residential | One Session per flow |
| A fixed IP for an API partner's allowlist | ISP proxy | Static IP, unmetered bandwidth |
| JavaScript-heavy pages | Playwright for Python with residential, or the Scraper API | See Geonode with Playwright |
Many Python projects route by domain: a dictionary mapping domains to "datacenter" or "residential", consulted by the helper that builds proxy URLs. Start every new domain on datacenter, measure success on real content, and promote it to residential only if it fails. That habit keeps per-GB costs low.
A checklist for Python proxy code in production
- Timeouts on every request. Without them, a stalled exit can hang a worker indefinitely.
- Retries with a fresh IP and backoff, capped at two or three attempts.
- Content checks to catch block pages that return status 200.
- Per-domain concurrency limits, especially with aiohttp or httpx async clients, which make it easy to send far more requests than a site tolerates.
- Connection reuse on purpose: reuse a
Sessionfor sticky flows, avoid it when you want a new exit per request. - Secrets outside the code, loaded from environment variables or a secrets manager.
- Structured logs with domain, outcome, status, latency and bytes, so you can see success rates and bandwidth per target.
- A smoke test that requests an IP echo endpoint through each configured product at startup and fails fast if credentials are wrong.
For framework-level crawling with built-in throttling and retries, see Geonode with Scrapy. For a wider view of scraping with Geonode, see Geonode for web scraping.
Testing your setup
A quick self-test catches most configuration mistakes before they reach production:
- Request an IP echo service three times through a rotating endpoint; expect three different IPs.
- Request it three times through a sticky endpoint with a
Session; expect the same IP. - Request a geolocation service through a country-targeted endpoint; expect the right country.
- Request your real target once and check for expected content.
Wrap these in a small script that exits with an error if any check fails, and run it at deploy time and in CI with a test sub-user. When something breaks later, run the same script first: it tells you within seconds whether the problem is credentials, targeting, sessions or the target itself. For command-line checks, see Geonode with cURL.
FAQ
How do I rotate IPs with requests?
Use a rotating Geonode endpoint and new connections per request. A shared Session reuses connections and may keep the same exit.
How do I keep the same IP across requests?
Use a sticky endpoint and a Session.
Why does my password break the proxy URL?
Special characters must be URL-encoded. Use urllib.parse.quote.
Which library should I use?
requests for simple scripts, httpx for modern sync or async code with HTTP/2, aiohttp for high-concurrency async jobs.
Editorial note: Proxy providers change their pools, features and prices often, so treat any figures here as typical ranges at the time of writing and confirm current terms with the provider before you buy.