# How to use proxies with Python requests, httpx and aiohttp

Three lines of configuration per library, then the same username syntax everywhere: country, city and session live in the proxy URL, so one gateway serves every job.


## The proxy URL

Every Python HTTP library takes a proxy as a URL. With ProxShift the URL carries your credentials and the [targeting parameters](https://proxshift.com/docs/username-parameters) in the username; the hostname is the gateway and the port picks the protocol.

```text
# Rotating: a new United States household on every new connection
http://USER-cc-us:PASS@res.proxshift.com:9000

# Sticky: one Berlin household held for 30 minutes under the id "job42"
http://USER-cc-de-city-berlin-sid-job42-ttl-30m:PASS@res.proxshift.com:9000

# SOCKS5 with remote DNS (socks5h), same parameters
socks5h://USER-cc-us:PASS@res.proxshift.com:9001
```


## requests

Pass the same URL for `http` and `https`; requests uses CONNECT for HTTPS destinations automatically. A `Session` reuses connections, which keeps you on the same exit until the connection closes; use one `Session` per sticky job and plain `requests.get` calls when you want a fresh exit per request.

```python
import requests

PROXY = "http://USER-cc-us:PASS@res.proxshift.com:9000"
proxies = {"http": PROXY, "https": PROXY}

# One request, one exit
r = requests.get("https://api.ipify.org", proxies=proxies, timeout=30)
print(r.text)

# A sticky flow: same exit for every request of this session
sticky = "http://USER-cc-de-city-berlin-sid-cart42-ttl-15m:PASS@res.proxshift.com:9000"
s = requests.Session()
s.proxies = {"http": sticky, "https": sticky}
s.get("https://example.com/product/1", timeout=30)
s.post("https://example.com/cart", json={"id": 1}, timeout=30)
```

> Tip: For SOCKS5 install the extra: `pip install \"requests[socks]\"`, then use `socks5h://` so DNS is resolved at the exit.


## httpx

httpx takes a single `proxy=` argument (older versions: `proxies=`). It supports HTTP/2 to the destination through the CONNECT tunnel and works the same way in async code.

```python
import httpx

PROXY = "http://USER-cc-us:PASS@res.proxshift.com:9000"

with httpx.Client(proxy=PROXY, timeout=30) as client:
    print(client.get("https://api.ipify.org").text)

# async, one sticky exit per task
import asyncio

async def fetch(sid: str, url: str) -> str:
    proxy = f"http://USER-cc-us-sid-{sid}-ttl-10m:PASS@res.proxshift.com:9000"
    async with httpx.AsyncClient(proxy=proxy, timeout=30) as client:
        return (await client.get(url)).text

asyncio.run(fetch("task1", "https://api.ipify.org"))
```


## aiohttp

aiohttp takes the proxy per request or per session and speaks HTTP proxies natively; SOCKS5 needs the `aiohttp-socks` connector.

```python
import aiohttp, asyncio

PROXY = "http://USER-cc-us:PASS@res.proxshift.com:9000"

async def main():
    async with aiohttp.ClientSession() as session:
        async with session.get("https://api.ipify.org", proxy=PROXY, timeout=aiohttp.ClientTimeout(total=30)) as r:
            print(await r.text())

asyncio.run(main())
```


## Rotation, keep-alive and retries

- A new TCP connection means a new exit. `requests.get` without a `Session` opens one per call; a `Session` or an httpx `Client` keeps connections alive and therefore keeps the exit until the pool recycles it.
- Force a fresh exit inside a session by changing the `-sid-` value; force one per request by sending `Connection: close`.
- Retry once on 403, 429 and connection errors: on a rotating gateway the retry is a different visitor. Never retry across exits in the middle of a sticky flow.
- Set timeouts to the exit type: 15 s connect and 45 s read for residential, more for mobile.


## Saving gigabytes

Residential traffic is billed per GB in both directions. Ask for compressed responses (`Accept-Encoding: gzip, br` is on by default in these libraries), prefer JSON endpoints to HTML, and never download images, fonts or media unless they are the data. A 350 KB page is cheap; a 4 MB page with assets is not.


## Questions

**Why do I keep getting the same IP with requests?**

A Session reuses the TCP connection, and the exit is chosen per connection. Use plain requests.get calls, send Connection: close, or change the -sid- value to get a new exit.

**Do I need a different proxy for HTTPS sites?**

No. The same http:// proxy URL handles HTTPS destinations through a CONNECT tunnel; TLS runs end to end between your code and the site.

**Can I use the same code for mobile proxies?**

Yes: replace res.proxshift.com with mob.proxshift.com. Ports, credentials and parameters are identical.

Source: https://proxshift.com/guides/python-requests-httpx
