Short answers
How do I use a proxy with Python Requests?
Pass a proxies dictionary with http and https keys to the request. Each value is a complete proxy URL. The key describes the destination URL; the value describes how Python connects to the gateway.
Why is the HTTPS proxy value an http:// URL?
An HTTPS destination can travel through an HTTP proxy using CONNECT. Keep http:// for the HTTP gateway on 7000; Requests still verifies the destination’s HTTPS certificate.
How do I put a proxy password into a URL?
Read the username and password from your runtime configuration, then encode each once with urllib.parse.quote(value, safe=""). Do not encode a full URL or encode credentials that are already URL-encoded.
Does a Requests Session keep the proxy IP?
No. A Python Session manages cookies and connections. Gateway rotation is configured separately in the proxy username. A sticky gateway session keeps the same device while available; its IP can still change.
Working without Requests? The Python urllib guide uses the standard library, with an explicit opener and a prompted proxy password. Its handler settings are separate from the Requests session below.
Using an async client? Follow the separate HTTPX proxy setup guide for AsyncClient or the aiohttp proxy guide for ClientSession; their proxy arguments differ from Requests.
For a Scrapy project, configure the crawler itself using the Scrapy proxy guide. Settings on a separate Requests session do not configure Scrapy’s downloader.
Prepare the interpreter and connection
Start in the Python environment your application actually uses. Install Requests with that interpreter, then run the check there: a package installed on your laptop does not configure a container or a notebook kernel.
python -m pip install requests
python -c "import requests; print(requests.__version__)"- Open the connection builder, choose a pool and a country from the current availability, and select HTTP.
- Provide
PROXY_USERas the complete generated username, including its pool, country and rotation settings. An account username alone is not a finished connection. - Provide
PROXY_PASSWORDas the proxy password. Your website password and API key are different credentials. - Inject these values through your local runtime or deployment secret configuration. Keep them out of source control, command output and shared notebooks.
The setup reference explains the connection fields. If you already have a passing shell check, keep those same fields for this first Python request; changing the country and the client together makes a failure harder to isolate.
Make one authenticated HTTP proxy request
Save this as proxy_check.py. It requires the two credential variables and accepts an optional PROXY_SERVER containing only the scheme, host and port. The echo endpoint reports the address it observed; it does not prove that every destination will accept your traffic.
import os
from urllib.parse import quote
import requests
server = os.environ.get("PROXY_SERVER", "http://gw.portproof.org:7000")
if not server.startswith("http://") or "@" in server:
raise SystemExit("Use an HTTP server address without credentials")
user = quote(os.environ["PROXY_USER"], safe="")
password = quote(os.environ["PROXY_PASSWORD"], safe="")
proxy = f"http://{user}:{password}@{server.removeprefix('http://')}"
proxies = {"http": proxy, "https": proxy}
try:
with requests.Session() as session:
session.trust_env = False
session.verify = os.environ.get("REQUESTS_CA_BUNDLE") or True
response = session.get(
"https://api.portproof.org/v1/echo-ip",
proxies=proxies,
timeout=(10, 30),
)
response.raise_for_status()
payload = response.json()
if not isinstance(payload.get("ip"), str):
raise ValueError("The endpoint did not return an IP address")
print("HTTP", response.status_code, "exit", payload["ip"])
except requests.RequestException as error:
raise SystemExit(f"Request failed: {type(error).__name__}") from NoneRun python proxy_check.py. A successful result gives the HTTP status and your own observed exit address. The script deliberately avoids printing the proxy URL or raw exception text, either of which can end up in a shared job log.
The proxy dictionary follows the Requests proxy interface. Encoding only the credential components follows Python’s URL quoting reference; a slash in a password must be encoded too, which is why safe is empty.
Make the running process predictable
This check uses explicit per-request settings and turns trust_env off. It therefore does not inherit proxy choices or default authentication from the machine. It also opts back into a configured certificate bundle with session.verify; otherwise the normal trusted certificates remain enabled. See the Session interface.
If your organisation manages outbound networking centrally, keep that policy instead of copying the override blindly. Choose one configuration source, document it, and test from the deployed process. Check only whether required variables are present; do not dump the environment into a log. The curl works but the app does not guide covers process and container differences.
Check which proxy Requests actually used
Setting Session.proxies does not always make that proxy the route. We checked two local authenticated proxies and a local destination with Python 3.12.14, Requests 2.34.2 and urllib3 2.8.0 on 30 September 2026. These were real requests with synthetic credentials, not calls to a live proxy pool. Redirects were disabled for each check.
| Configuration | Route recorded by the fixture |
|---|---|
| Environment proxy plus a different Session.proxies value | Environment proxy |
| Environment proxy plus proxies passed to get() | Per-request proxy |
| trust_env=False with Session.proxies configured | Session proxy |
| Environment proxy and matching NO_PROXY, without explicit settings | Direct to the local destination |
| Matching NO_PROXY with a session or per-request proxy | Explicit proxy still used |
NO_PROXY did not remove the explicit proxy settings in these checks. If your job needs selected destinations to connect directly, implement that choice in the application and verify both routes. Do not assume an environment exclusion cancels every proxy setting. The Requests proxy configuration guide documents environment precedence. For differences between a shell and a worker, use the curl and app routing checklist.
The HTTPS checks also confirmed the certificate-bundle line in the example above: with trust_env=False, setting REQUESTS_CA_BUNDLE alone produced SSLError; assigning that bundle to session.verify succeeded with TLS verification enabled. The Session interface explains the environment setting.
Use separate connection and reading limits
The tuple (10, 30) sets connection and read timeouts in seconds. These are example limits, not a promise about network speed. A read timeout limits how long the client waits without receiving data; it is not a thirty-second deadline for an entire download. Requests documents this distinction in its timeout guide.
Give a scheduled job a separate overall deadline and cap its work queue. A worker that keeps receiving small chunks can otherwise remain busy much longer than the read timeout suggests. Start with one small request before adding parallelism, retries or large response bodies.
Use SOCKS5 when your application needs it
python -m pip install "requests[socks]"For SOCKS5, keep the encoded user and password variables from the HTTP example and replace the proxy construction and dictionary with the following lines. Remove the HTTP-only server validation too. Both dictionary entries still follow the destination scheme.
proxy = f"socks5h://{user}:{password}@gw.portproof.org:7001"
proxies = {"http": proxy, "https": proxy}Requests uses socks5h for hostname resolution at the proxy; plain socks5 resolves the destination on the client. Pick the DNS location deliberately, then repeat the same echo check. The protocol comparison helps when an application supports both.
Separate Python sessions from gateway sessions
Reuse a Python Session for a related sequence of requests and close it when that unit of work ends. Keep its cookies separate from unrelated jobs. For a multi-step workflow, select a named sticky session in the connection builder and reuse that exact generated username throughout the workflow.
A new Python request is not necessarily a new network connection: connection reuse can keep an existing tunnel alive. Do not test connection-based rotation by demanding a different address after every session.get. Likewise, a repeated address alone cannot prove that routing is wrong. Read rotation and sticky sessions before turning either assumption into a test assertion.
Identify the failed stage before retrying
| Symptom | First check |
|---|---|
| ProxyError or a tunnel authentication failure | Through the HTTP gateway, a refused port, an unresolved gateway hostname, a connection timeout and a rejected CONNECT all raise ProxyError. Compare the full username, current proxy password, scheme and port with a fresh builder result. Use the 407 guide if authentication is refused. |
| ConnectionError with socks5h | A refused SOCKS5 port or rejected SOCKS5 credentials. Check the port 7001, the complete username and the password. |
| InvalidSchema or missing SOCKS support | Install requests[socks] in the same environment that runs the script. |
| ConnectTimeout | With socks5h, the gateway connection or SOCKS5 greeting did not finish in time; the HTTP gateway reports that stage as ProxyError. Check reachability of the gateway host and port from the actual worker. |
| ReadTimeout | No data arrived within a limit. Through the HTTP gateway this also happened when the gateway accepted the connection and never answered CONNECT. Test the small echo endpoint before the application destination; limit subsequent retries. |
| SSLError | Check hostname, system time and the certificate bundle. Preserve verification. |
| A response with status 403 or 429 | Establish whether the response came from the gateway or destination. Respect destination access rules and rate limits. |
| A JSON decoding error | The request returned a body that was not the expected JSON. Check the status and content type without logging credentials. |
We recorded the ProxyError, ConnectionError, ConnectTimeout, ReadTimeout and SSLError cases above with Requests 2.34.2, urllib3 2.8.0 and PySocks 1.7.1 against local proxies on 1 October 2026. If the gateway is not reached at all, follow connection refused and timeouts.
Correct rejected credentials before retrying. Start with 407 authentication troubleshooting or CONNECT tunnel failures. For permitted reads that fail transiently, bound the number of retries and include a delay. Do not automatically replay purchases, submissions or other operations with side effects.
Once the echo check passes, replace it with one authorised application request and check the response your job actually needs. Measure a representative run before choosing how many GB to buy. See how traffic is counted and current per-GB prices.
What is not allowed
Use these examples for authorised QA, price monitoring, ad verification and research that respects the destination’s terms and access rules. A working proxy does not grant permission to collect data or send requests. See the acceptable-use policy.
Read next
Fix 407 Proxy Authentication Required
Read the gateway code, check credentials and balance, then separate a rejected HTTPS tunnel from an HTTP response.
Read the guide
Node.js fetch proxy setup with Undici
An explicit HTTP proxy dispatcher with safe credential handling, bounded requests and response cleanup.
Read the guide