# aiohttp Proxy Setup: Auth, Sessions and SOCKS5

> aiohttp proxy setup tested on aiohttp 3.14.5: proxy= and proxy_auth, the new Proxy-Authorization way, session-wide proxies, SOCKS5 and one sticky IP per task.

[Home](https://quanticdata.io/) / [Blog](https://quanticdata.io/blog/) / aiohttp Proxy Setup: Auth, Sessions and SOCKS5

# How to use a proxy with aiohttp: proxy=, authentication, SOCKS5 and one sticky session per task

Proxies · Oct 24, 2026 · 13 min read · By [Aldo Morese](https://quanticdata.io/about/), founder of QuanticData

![Using a proxy with aiohttp: the QuanticData proxy URL on port 8080 goes into ClientSession(proxy=...), one session per asyncio task with its own sticky session ID, and the card shows a real run from Chile where task 1, task 2 and task 3 each kept one IP for both requests, all with status 200.](https://quanticdata.io/blog/aiohttp-proxy-setup/hero.webp?v=20261024h)

On this page

- [What you need before you start](https://quanticdata.io/blog/aiohttp-proxy-setup/#what-you-need-before-you-start)
- [The proxy format aiohttp expects](https://quanticdata.io/blog/aiohttp-proxy-setup/#the-proxy-format-aiohttp-expects)
- [Step by step: proxy= and proxy_auth= on a request](https://quanticdata.io/blog/aiohttp-proxy-setup/#step-by-step-proxy-and-proxy-auth-on-a-request)
- [Session-level settings: one proxy for every request](https://quanticdata.io/blog/aiohttp-proxy-setup/#session-level-settings-one-proxy-for-every-request)
- [Concurrency: one sticky session per task](https://quanticdata.io/blog/aiohttp-proxy-setup/#concurrency-one-sticky-session-per-task)
- [SOCKS5 with aiohttp-socks](https://quanticdata.io/blog/aiohttp-proxy-setup/#socks5-with-aiohttp-socks)
- [Which proxy type for which aiohttp job](https://quanticdata.io/blog/aiohttp-proxy-setup/#which-proxy-type-for-which-aiohttp-job)
- [ISP proxies in aiohttp](https://quanticdata.io/blog/aiohttp-proxy-setup/#isp-proxies-in-aiohttp)
- [Mobile proxies in aiohttp](https://quanticdata.io/blog/aiohttp-proxy-setup/#mobile-proxies-in-aiohttp)
- [aiohttp proxy not working: errors and fixes](https://quanticdata.io/blog/aiohttp-proxy-setup/#aiohttp-proxy-not-working-errors-and-fixes)
- [HTTP or SOCKS5 in aiohttp](https://quanticdata.io/blog/aiohttp-proxy-setup/#http-or-socks5-in-aiohttp)
- [Before you scale up](https://quanticdata.io/blog/aiohttp-proxy-setup/#before-you-scale-up)

To use a proxy with aiohttp, pass its URL as proxy= on a request or on the ClientSession, with the login inside the URL or in a Proxy-Authorization header. proxy_auth=aiohttp.BasicAuth still works but is deprecated since aiohttp 3.14. SOCKS5 needs aiohttp-socks. Give every asyncio task its own sticky session. Real code and output below.

aiohttp is the asyncio HTTP client for Python: many requests in flight at once from one process, which is exactly where a proxy plan earns its keep and where small mistakes multiply. The Residential Premium scripts and every error on this page were run on 24 October 2026 with Python 3.13.6, aiohttp 3.14.5 and aiohttp_socks 0.12.0, through a QuanticData plan with exits in Chile; ISP and mobile lines use the same code with the values from their own panels. The outputs are copied from the terminal; only the credentials are replaced by USER and PASS and the exit IPs are masked. If your code is synchronous, the same proxy works with [a proxy with Python requests](https://quanticdata.io/blog/how-to-use-a-proxy-with-python-requests/).

## What you need before you start

- **Python 3.10 or newer and aiohttp.** aiohttp 3.14.5 requires Python 3.10 or later: `pip install aiohttp`. For SOCKS5 add `pip install aiohttp-socks`.
- **A proxy plan.** Residential Premium, ISP or mobile: all three work with aiohttp. The table further down says which one fits which job.
- **The proxy URL.** In the QuanticData dashboard open My proxies, then your plan. In the Endpoint generator set Output format to http://user:pass@host:port: the Preview is then the exact string aiohttp takes as proxy=.

**Try it on your own targets.** Every QuanticData account gets $2 of free API usage per month.

[Start free — $2/month included](https://quanticdata.io/signup/?utm_source=blog&utm_medium=website&utm_campaign=blog-inline&utm_content=aiohttp-proxy-setup) · [Explore Residential Proxies from $0.80/GB](https://quanticdata.io/residential-proxies/)

## The proxy format aiohttp expects

aiohttp reads a proxy as a URL: scheme, login and password, host and port. The same QuanticData proxy in the two shapes you will use:

```
# credentials inside the URL: works on every aiohttp version, no warning
http://USER-country-cl-sid-aiohttp01-ttl-60m:PASS@residentialpremium.quantumproxies.io:8080

# the gateway alone, with the credentials passed separately
http://residentialpremium.quantumproxies.io:8080
```

Four details decide whether it connects:

- **The scheme is http://, even for https:// sites.** aiohttp asks the gateway for a CONNECT tunnel and runs TLS to the site inside it. A proxy URL that starts with https:// makes aiohttp speak TLS to the gateway itself, and the request fails with an SSL WRONG_VERSION_NUMBER error.
- **Port 8080 is HTTP, port 1080 is SOCKS5.** aiohttp's own proxy= speaks HTTP only; SOCKS5 goes through aiohttp-socks, further down.
- **The username is the whole string.** `-country-cl` picks the exit country, `-sid-aiohttp01` names the session and `-ttl-60m` keeps it for 60 minutes. A login cut at the first dash still authenticates, but every request then leaves from a random country on a new IP.
- **Reserved characters need escaping.** The credentials the generator shows are letters and digits and go into the URL as they are. A password of your own with @, : or / has to be percent-encoded, for example with urllib.parse.quote, before it goes into a URL.

![The QuanticData Endpoint generator for a Residential Premium plan: Chile selected, Session set to Sticky, HTTP protocol, Output format http://user:pass@host:port and the Preview with the proxy URL on residentialpremium.quantumproxies.io:8080, username and password blurred](https://quanticdata.io/blog/aiohttp-proxy-setup/quanticdata-generator-chile-proxy-url.webp)

*The generator with Output format http://user:pass@host:port: the Preview is the proxy= string for aiohttp.*

## Step by step: proxy= and proxy_auth= on a request

1. **Generate the line.** In the Endpoint generator choose the Country, set Session to Sticky, set Session TTL (minutes) to at least the length of the job, keep Protocol on HTTP and pick the output format you want. Connection details shows host, port, username and password one by one, which is what proxy_auth= needs.
2. **Write the request.** proxy= gets the gateway URL, proxy_auth= gets an aiohttp.BasicAuth with the username and the password.
3. **Run it and read the exit.** https://ipinfo.io/json answers with the IP, city, region and time zone the site sees. The country has to match the `-country-` in the username.
4. **On aiohttp 3.14 or later, move the credentials.** Put them in a Proxy-Authorization header or in the URL, and the deprecation warnings go away.

![Connection details of the QuanticData Endpoint generator: host residentialpremium.quantumproxies.io, port 8080, the username with -country-cl and the session, and the password, each with a copy button, credentials blurred](https://quanticdata.io/blog/aiohttp-proxy-setup/quanticdata-generator-connection-details.webp)

*The same proxy as four values: the username and password go into proxy_auth= or the Proxy-Authorization header.*

The script sends the same request twice, first with proxy_auth=, then with the header that aiohttp 3.14 recommends:

```python
import asyncio
import aiohttp

PROXY = "http://residentialpremium.quantumproxies.io:8080"
LOGIN = "USER-country-cl-sid-aiohttp01-ttl-60m"
PASSWORD = "PASS"
URL = "https://ipinfo.io/json"

def where(info):
    return f'{info["ip"]}  {info["city"]}, {info["region"]}  {info["timezone"]}'

async def main():
    async with aiohttp.ClientSession() as session:
        auth = aiohttp.BasicAuth(LOGIN, PASSWORD)
        async with session.get(URL, proxy=PROXY, proxy_auth=auth) as r:
            print("proxy_auth   ", r.status, where(await r.json()))

        token = aiohttp.encode_basic_auth(LOGIN, PASSWORD)
        headers = {"Proxy-Authorization": token}
        async with session.get(URL, proxy=PROXY, proxy_headers=headers) as r:
            print("proxy_headers", r.status, where(await r.json()))

asyncio.run(main())
```

What it printed:

```
/Users/me/aiohttp-demo/proxy_auth.py:16: DeprecationWarning: BasicAuth is deprecated and will be removed in aiohttp 4.0; use aiohttp.encode_basic_auth() with headers={'Authorization': ...} instead
  auth = aiohttp.BasicAuth(LOGIN, PASSWORD)
/Users/me/aiohttp-demo/proxy_auth.py:17: DeprecationWarning: The 'proxy_auth' parameter is deprecated and will be removed in v4; pass proxy_headers={'Proxy-Authorization': aiohttp.encode_basic_auth(login, password)} instead
  async with session.get(URL, proxy=PROXY, proxy_auth=auth) as r:
proxy_auth    200 148.222.•••.•••  Santiago, Santiago Metropolitan  America/Santiago
proxy_headers 200 148.222.•••.•••  Santiago, Santiago Metropolitan  America/Santiago
```

![Visual Studio Code with proxy_auth.py and six numbered steps: the gateway URL on port 8080, the username with country cl and session aiohttp01, proxy= with proxy_auth=aiohttp.BasicAuth, the same request with a Proxy-Authorization header from encode_basic_auth, the two DeprecationWarnings in the terminal and two 200 responses from the same IP in Santiago, America/Santiago](https://quanticdata.io/blog/aiohttp-proxy-setup/aiohttp-proxy-auth-deprecation.webp)

*proxy_auth.py as it ran on 24 October 2026 with aiohttp 3.14.5. Redrawn editor, real code and output, IP masked.*

Both requests went out through the same Chilean IP because they carry the same session ID, aiohttp01. The two warnings are aiohttp 3.14 telling you that the BasicAuth class and the proxy_auth parameter will be removed in aiohttp 4.0. Nothing breaks today, but code that should outlive the next major release needs one of the other two ways:

| How the credentials travel | Code | aiohttp versions |
| --- | --- | --- |
| Inside the proxy URL | `proxy="http://USER-...:PASS@host:8080"` | Every version, no warning |
| proxy_auth= | `proxy_auth=aiohttp.BasicAuth(login, password)` | Works; DeprecationWarning from 3.14, removal planned for 4.0 |
| Proxy-Authorization header | `proxy_headers={"Proxy-Authorization": aiohttp.encode_basic_auth(login, password)}` | 3.14 and later: encode_basic_auth() was added in 3.14.0 |

One detail from the aiohttp changelog: encode_basic_auth() encodes in UTF-8, BasicAuth defaulted to latin-1. With the letters-and-digits credentials of the generator the bytes are identical.

## Session-level settings: one proxy for every request

Since aiohttp 3.11.0 the ClientSession itself accepts proxy= and proxy_auth=, so every request of the session goes through the proxy without repeating it. A proxy= on a single request still overrides the session's.

```
proxy = "http://USER-country-cl-sid-aiohttp01-ttl-60m:PASS@residentialpremium.quantumproxies.io:8080"
timeout = aiohttp.ClientTimeout(total=30)

async with aiohttp.ClientSession(proxy=proxy, timeout=timeout) as session:
    async with session.get("https://ipinfo.io/json") as r:
        print(r.status, await r.json())
```

- **Put the credentials in the URL at session level.** ClientSession has no proxy_headers parameter in aiohttp 3.14.5: `ClientSession(proxy=..., proxy_headers=...)` fails with `TypeError: ClientSession.__init__() got an unexpected keyword argument 'proxy_headers'`, even though an example in the documentation passes it. The header works on each request; the URL works everywhere.
- **Set a timeout.** aiohttp's default is 300 seconds in total and 30 seconds to connect. Through a proxy a stalled request then holds its slot for five minutes; 30 seconds in total is a sensible start for page fetches.
- **Environment variables are off by default.** Unlike requests, aiohttp ignores HTTP_PROXY and HTTPS_PROXY unless the session is created with `trust_env=True`. Then it reads them with urllib's getproxies(), credentials in the URL included, and skips the hosts listed in NO_PROXY. In our run, HTTPS_PROXY set to the Chilean line plus trust_env=True returned 200 from Chile.

## Concurrency: one sticky session per task

The reason to use aiohttp is concurrency, and that is where the proxy needs a rule: one sticky session per task. A task that logs in, follows a cart or walks through pages should keep one IP from its first request to its last; two tasks should never share one. The session ID in the username does exactly that, so the code only has to build one proxy URL per task:

```python
import asyncio
import aiohttp

GATEWAY = "residentialpremium.quantumproxies.io:8080"
USER, PASSWORD = "USER", "PASS"
URL = "https://ipinfo.io/json"

def proxy_url(sid, country="cl", ttl=60):
    login = f"{USER}-country-{country}-sid-{sid}-ttl-{ttl}m"
    return f"http://{login}:{PASSWORD}@{GATEWAY}"

async def task(n):
    proxy = proxy_url(f"aiohttp{n:02d}")
    timeout = aiohttp.ClientTimeout(total=30)
    async with aiohttp.ClientSession(proxy=proxy, timeout=timeout) as s:
        for step in (1, 2):
            async with s.get(URL) as r:
                info = await r.json()
                print(f"task {n} request {step}", info["ip"], info["city"])

async def main():
    await asyncio.gather(*(task(n) for n in (1, 2, 3)))

asyncio.run(main())
```

```
task 3 request 1 190.114.•••.••• Santiago
task 1 request 1 148.222.•••.••• Santiago
task 2 request 1 190.5.•••.••• Chanco
task 3 request 2 190.114.•••.••• Santiago
task 1 request 2 148.222.•••.••• Santiago
task 2 request 2 190.5.•••.••• Chanco
```

![Visual Studio Code with sticky_tasks.py and five numbered steps: proxy_url builds one proxy URL per session ID, each task gets aiohttp01, aiohttp02 or aiohttp03, ClientSession(proxy=...) with a 30-second timeout, asyncio.gather runs the three tasks, and the terminal shows each task keeping one IP for both requests: Santiago, Chanco and Santiago](https://quanticdata.io/blog/aiohttp-proxy-setup/aiohttp-sticky-session-per-task.webp)

*Three tasks, three sessions, three IPs, each kept for both requests. Real run on 24 October 2026, IPs masked.*

Task 1 also came back on 148.222.•••.•••, the IP of the first script: same session ID, same IP, as long as the 60 minutes have not run out. Why a ClientSession per task and not one shared session with a different proxy= per request? Both keep the IPs apart: aiohttp's connection pool keys every connection by its proxy, so two session IDs never share a socket. But a ClientSession also holds the cookies, and a task that behaves like one visitor should not see the cookies of another.

For many tasks, cap how many run at once. A semaphore keeps, here, ten sessions open at a time over fifty tasks; each ClientSession also has its own connector with the default limit of 100 connections:

```
async def task(n, sem):
    async with sem, aiohttp.ClientSession(proxy=proxy_url(f"aiohttp{n:02d}")) as s:
        async with s.get(URL) as r:
            return r.status

async def main():
    sem = asyncio.Semaphore(10)
    statuses = await asyncio.gather(*(task(n, sem) for n in range(1, 51)))
```

For a new IP on every request instead, leave `-sid-` out of the username (Session: Rotating in the generator). Pools of separate proxies and their rotation are covered in [rotating proxies in Python](https://quanticdata.io/blog/how-to-rotate-proxies-python/).

## SOCKS5 with aiohttp-socks

aiohttp has no SOCKS support of its own: a `socks5://` URL in proxy= is spoken to as if it were HTTP and fails. The aiohttp-socks package adds a connector that does the SOCKS5 handshake; install it with `pip install aiohttp-socks` and give the connector to the session:

```python
import asyncio
import aiohttp
from aiohttp_socks import ProxyConnector

PROXY = ("socks5://USER-country-cl-sid-aiohttp04-ttl-60m:PASS"
         "@residentialpremium.quantumproxies.io:1080")

async def main():
    connector = ProxyConnector.from_url(PROXY)
    async with aiohttp.ClientSession(connector=connector) as session:
        async with session.get("https://ipinfo.io/json") as r:
            info = await r.json()
            print(r.status, info["ip"], info["city"], info["region"],
                  info["timezone"])

asyncio.run(main())
```

```
200 191.113.•••.••• Santiago Santiago Metropolitan America/Santiago
```

![Visual Studio Code with socks5.py and four numbered steps: from aiohttp_socks import ProxyConnector, a socks5:// URL on residentialpremium.quantumproxies.io port 1080, the connector passed to ClientSession(connector=...), and a 200 response from Santiago, Santiago Metropolitan, America/Santiago in the terminal](https://quanticdata.io/blog/aiohttp-proxy-setup/aiohttp-socks5-proxyconnector.webp)

*SOCKS5 through aiohttp-socks 0.12.0, real run on 24 October 2026, IP masked.*

- **One connector, one proxy, one session.** The connector belongs to the ClientSession, so the one-session-per-task rule above comes for free: build a connector per task with its own session ID.
- **DNS through the proxy.** For socks5 URLs aiohttp-socks lets the proxy resolve the host name by default (rdns), so the site's name is not looked up on your network.
- **Same login, other port.** The username and password are the same as on HTTP; only the scheme and port 1080 change. More on when SOCKS5 is worth it on the page for [SOCKS5 proxies](https://quanticdata.io/socks5-proxies/).

## Which proxy type for which aiohttp job

| Proxy type | In aiohttp | Good for |
| --- | --- | --- |
| Residential Premium | One URL per task with a sticky -sid-; country, region, city or ISP in the username; HTTP 8080, SOCKS5 1080; sessions up to 1440 minutes | Most scraping and multi-step jobs: home IPs in the country you choose |
| ISP | Fixed IPs from Assigned IPs, Output format Proxy URL, pasted as proxy=; HTTP 50100, SOCKS5 50101 | Accounts and jobs that must keep the same address for months |
| Mobile | Same pattern as Premium with -type-mobile in the username; mobile.quantumproxies.io, HTTP 8080, SOCKS5 1080; IP whitelist available | Mobile-first sites and apps that expect carrier IPs |

## ISP proxies in aiohttp

An ISP plan gives fixed IPs instead of a gateway. In the dashboard, Proxy endpoints, Assigned IPs lists them; set Output format to Proxy URL and every line is already a proxy= string: `http://USER:PASS@IP:50100`. Protocol HTTP / HTTPS uses port 50100; switching it to SOCKS5 changes the port in the list to 50101, for use with aiohttp-socks. There is no session ID and no lifetime: the IP is the line, so give each account or job its own line and its own ClientSession.

![The Assigned IPs panel of a QuanticData ISP plan: Protocol HTTP / HTTPS, Output format Proxy URL, five IPs masked on port 50100 with username USER, and the formatted output http://USER:PASS@IP:50100 ready to copy](https://quanticdata.io/blog/aiohttp-proxy-setup/quanticdata-isp-assigned-ips-proxy-url.webp)

*ISP plan, Output format Proxy URL: each line is a proxy= value. Sample IPs masked.*

![Visual Studio Code with isp_accounts.py and four numbered steps: three QuanticData ISP lines in Proxy URL format on port 50100 with the IPs masked, one ClientSession(proxy=...) per IP, and a comment that the IP is the same on every run because ISP lines have no session ID or TTL](https://quanticdata.io/blog/aiohttp-proxy-setup/aiohttp-isp-proxy-urls.webp)

*One fixed ISP IP per account, run together with asyncio.gather. Redrawn editor, sample IPs masked.*

## Mobile proxies in aiohttp

Mobile lines work like Residential Premium with `-type-mobile` in the username. In the plan's Endpoint generator choose the country, the Proxy host (gateway) closest to your server, Global, USA, EU or Asia, then Sticky and the protocol: HTTP on 8080 or SOCKS5 on 1080. The Preview shows the host to use.

```
MOBILE = ("http://USER-country-cl-type-mobile-sid-aiohttp07-ttl-60m:PASS"
          "@mobile.quantumproxies.io:8080")

async with aiohttp.ClientSession(proxy=MOBILE) as session:
    async with session.get("https://ipinfo.io/json") as r:
        print(r.status, await r.json())
```

Mobile plans also accept IP whitelist authentication: add your server's IP in the generator, then use a line from Proxy list for a whitelisted IP as `proxy="http://HOST:PORT"`, with no login at all. For a new mobile IP, change the session ID, for example aiohttp08 instead of aiohttp07. The plans are on the page for [mobile proxies](https://quanticdata.io/mobile-proxies/).

![The Mobile Endpoint generator of QuanticData: Chile selected, Proxy host (gateway) Global, USA, EU or Asia, Session Sticky, Protocol HTTP 8080 or SOCKS5 1080, and the Preview with -country-cl-type-mobile in the username, credentials blurred](https://quanticdata.io/blog/aiohttp-proxy-setup/quanticdata-generator-mobile-chile.webp)

*Mobile: gateway, protocol and the -type-mobile username, ready for proxy=.*

## aiohttp proxy not working: errors and fixes

Each mistake below was reproduced on 24 October 2026 with aiohttp 3.14.5; the first column is what aiohttp actually raised.

| What aiohttp raises | Cause | Fix |
| --- | --- | --- |
| `ClientHttpProxyError: 407, message='Proxy Authentication Required'` | Wrong password, or the username cut or copied with a space | Copy both again from Connection details; check the plan is active with traffic left |
| `ClientResponseError: 400, message="Bad status line"` with `b'\x05\xff'` | An http:// or socks5:// proxy= pointed at the SOCKS5 port 1080: aiohttp spoke HTTP to a SOCKS5 server | HTTP on 8080, or SOCKS5 on 1080 through aiohttp-socks |
| `IncompleteReadError: 0 bytes read on a total of 2 expected bytes`, after about 15 seconds | aiohttp-socks pointed at the HTTP port 8080 | socks5:// with port 1080 |
| `ClientConnectorSSLError` with `WRONG_VERSION_NUMBER` | The proxy URL starts with https:// | http:// for the proxy, even for https:// sites |
| `TypeError: ClientSession.__init__() got an unexpected keyword argument 'proxy_headers'` | proxy_headers passed to the session | Credentials in the session's proxy URL, or proxy_headers on each request |
| `DeprecationWarning: BasicAuth is deprecated` | aiohttp 3.14 or later with proxy_auth= | Proxy-Authorization header or credentials in the URL |
| Requests leave from your own IP | HTTPS_PROXY set but the session ignores it | trust_env=True, or proxy= in the code |
| The IP changes in the middle of a task | The session lifetime ended, or two tasks share one session ID | A longer -ttl- and a different -sid- in every task |

![The Visual Studio Code terminal with a Python traceback ending in aiohttp.client_exceptions.ClientHttpProxyError: 407, message Proxy Authentication Required, and the proxy URL with the password inside the message; beside it, what to check in order: the password copied whole, the full username, the plan active with traffic left](https://quanticdata.io/blog/aiohttp-proxy-setup/aiohttp-407-proxy-authentication-required.webp)

*The 407 as aiohttp 3.14.5 raised it. Note the password inside the message. Redrawn terminal, real output.*

Look at the 407 again: the exception message repeats the whole proxy URL, password included. A logger that writes `str(error)` writes your proxy password into the logs. Log the status and the host instead, or strip the credentials first. The status itself is explained in [407 Proxy Authentication Required](https://quanticdata.io/blog/how-to-fix-407-proxy-authentication-required/).

When aiohttp fails and you cannot tell whether the proxy or the code is at fault, test the same values outside Python. If this returns an address in the right country, the proxy works and the problem is in the script:

```bash
curl -x http://residentialpremium.quantumproxies.io:8080 \
  -U "USER-country-cl-sid-test-ttl-10m:PASS" https://ipinfo.io/json
```

Certificate errors are a different family, covered in [SSL certificate errors behind a proxy](https://quanticdata.io/blog/ssl-certificate-verify-failed-proxy/).

## HTTP or SOCKS5 in aiohttp

For web scraping, HTTP on port 8080 is the simpler choice: it needs nothing beyond aiohttp, works with proxy= on requests and sessions, and every QuanticData network offers it. SOCKS5 on port 1080 needs aiohttp-socks and one connector per session, and is worth it when the host name should be resolved by the proxy or when the same proxy also serves tools that do not speak HTTP. If you also use the other async client, [the httpx proxy guide](https://quanticdata.io/blog/httpx-proxy/) covers its proxy= and mounts. The plans themselves are on the pages for [QuanticData residential proxies](https://quanticdata.io/residential-proxies/) and [ISP proxies](https://quanticdata.io/isp-proxies/).

## Before you scale up

A proxy changes where requests come from, not what a site allows. Keep to each site's terms and to the law where you work, keep the concurrency reasonable for the site you fetch from, and give every account its own session and its own IP.

### Sources & further reading

- [aiohttp documentation: Advanced Client Usage, Proxy support](https://docs.aiohttp.org/en/stable/client_advanced.html#proxy-support)
- [aiohttp documentation: Client Reference (ClientSession, BasicAuth, encode_basic_auth, TCPConnector)](https://docs.aiohttp.org/en/stable/client_reference.html)
- [aiohttp changelog: 3.11.0 session proxy parameters, 3.14.0 BasicAuth deprecation](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [aiohttp-socks on PyPI: ProxyConnector for SOCKS proxies](https://pypi.org/project/aiohttp-socks/)
- [Python documentation: urllib.request.getproxies](https://docs.python.org/3/library/urllib.request.html#urllib.request.getproxies)
- [RFC 1928: SOCKS Protocol Version 5](https://www.rfc-editor.org/rfc/rfc1928)

## FAQ

Quick answers on aiohttp proxy.

[Something else? Ask us](mailto:hello@quanticdata.io)

### How do I use a proxy with aiohttp?

Pass the proxy URL as proxy= on a request, for example session.get(url, proxy="http://USER:PASS@host:8080"), or on the session with aiohttp.ClientSession(proxy=...), available since aiohttp 3.11. The scheme is http:// even for https:// sites: aiohttp opens a CONNECT tunnel through the proxy.

### How do I pass proxy authentication in aiohttp?

Three ways: the username and password inside the proxy URL, proxy_auth=aiohttp.BasicAuth(login, password), or proxy_headers={"Proxy-Authorization": aiohttp.encode_basic_auth(login, password)}. Since aiohttp 3.14, BasicAuth and proxy_auth raise a DeprecationWarning and are planned for removal in 4.0; the URL and the header do not.

### Does aiohttp support SOCKS5 proxies?

Not by itself: proxy= speaks HTTP only, and a socks5:// URL there fails. Install aiohttp-socks and pass ProxyConnector.from_url("socks5://USER:PASS@host:1080") to aiohttp.ClientSession(connector=...). The connector belongs to the session, so it is one SOCKS5 proxy per session.

### How do I set a proxy for a whole aiohttp ClientSession?

Create the session with aiohttp.ClientSession(proxy="http://USER:PASS@host:8080"). Every request of the session uses it unless a request passes its own proxy=. In aiohttp 3.14.5 the session does not accept proxy_headers, so keep the credentials in the URL at session level.

### Does aiohttp read HTTP_PROXY and HTTPS_PROXY?

Only when the session is created with trust_env=True. aiohttp then reads the variables with urllib's getproxies(), including credentials in the URL, and honours NO_PROXY. Without trust_env it ignores them, unlike requests.

### How do I get a new IP for each request in aiohttp?

With a QuanticData Residential Premium or mobile line, leave -sid- out of the username and every request gets a new IP. For one IP per task, give each task its own -sid- and its own ClientSession; for a new IP later, change the session ID.

## One sticky IP for every aiohttp task

Residential Premium, ISP and mobile proxies with country targeting and sticky sessions up to 1440 minutes, HTTP and SOCKS5, copied from the endpoint generator straight into proxy=.

[Start free — $2/month included](https://quanticdata.io/signup/?utm_source=blog&utm_medium=website&utm_campaign=blog-end&utm_content=aiohttp-proxy-setup) · [Explore Residential Proxies from $0.80/GB](https://quanticdata.io/residential-proxies/)

## Related reading

- [MBBrowser Proxy Setup: Add, Test and Fix](https://quanticdata.io/blog/mbbrowser-proxy-setup/): Proxies · Open Create New Session, choose HTTP or SOCKS5 under Proxy Server to match the port, fill in address, port, Account and Password, click Test until it says Success and create the session. Below: every field, why Test sets the time zone, Residential Premium, ISP and mobile lines, bulk import with the Proxy Server Manager and a fix for each error.
- [Crawl4AI Proxy: Config, Rotation and Fixes](https://quanticdata.io/blog/crawl4ai-proxy-setup/): Proxies · Pass proxy_config with server, username and password, in BrowserConfig for the whole browser or in CrawlerRunConfig for one run. Below: the formats Crawl4AI 0.9 accepts, a real check, rotation over sticky sessions, Residential Premium, ISP and mobile lines, the Docker server and a fix for each error it prints.
- [Helium Scraper Proxy: List, Rotation and Fixes](https://quanticdata.io/blog/helium-scraper-proxy-setup/): Proxies · Open File, Proxy List and add a row with the address, port, user name and password; then open Project, Settings and set Enable Proxies to True. Below: the values for Residential Premium, ISP and mobile, what each of the four Proxies settings does, rotation with sticky sessions or RotateProxy, a check in Helium Scraper's browser and a fix for each mistake.

---

Source: https://quanticdata.io/blog/aiohttp-proxy-setup/ · Site index for AI: https://quanticdata.io/llms.txt
