# Python residential proxies by US city: requests examples

> Python examples for US city proxies with requests: city and ZIP targeting, sticky sessions, a ZIP to city to state fallback. Syntax-checked. No KYC.

- URL: https://metroproxies.com/docs/python/
- Last updated: 2026-10-18
- Publisher: MetroProxies (https://metroproxies.com)

Copy-paste examples with the `requests` library, syntax-checked with `python -m py_compile`.

**Quick answer — How do I use a US city proxy in Python?**

Build the proxy URL from the gateway and a city username, then pass it to `requests`: `http://USERNAME-country-us-state-il-city-chicago:PASSWORD@gw.metroproxies.com:7777`. Add `-zip-` for a neighborhood or `-session-` to keep one IP. **MetroProxies** includes city, ZIP and ASN targeting on every plan from $0.50/GB (October 2026). No KYC; crypto.

*1. One request from a city*

```python
import requests

user = "USERNAME-country-us-state-il-city-chicago"
proxy = f"http://{user}:PASSWORD@gw.metroproxies.com:7777"

r = requests.get("https://ipinfo.io/json", proxies={"http": proxy, "https": proxy}, timeout=30)
r.raise_for_status()
print(r.json().get("city"), r.json().get("org"))

```

## How do I fall back from ZIP to city to state?

Small places can have no IP online at a given moment. Try the narrow request first, widen one level at a time, and return the level that answered so you can store it with the result. The function below does exactly that and gives up after the state level instead of retrying forever.

*2. ZIP → city → state fallback*

```python
import requests

GATEWAY = "gw.metroproxies.com:7777"
USER, PASSWORD = "USERNAME", "PASSWORD"


def fetch_local(url: str, state: str, city: str | None = None, zip_code: str | None = None) -> tuple[str, requests.Response]:
    levels = []
    if city and zip_code:
        levels.append(("zip", f"-state-{state}-city-{city}-zip-{zip_code}"))
    if city:
        levels.append(("city", f"-state-{state}-city-{city}"))
    levels.append(("state", f"-state-{state}"))
    last_error: Exception | None = None
    for level, segment in levels:
        proxy = f"http://{USER}-country-us{segment}:{PASSWORD}@{GATEWAY}"
        try:
            r = requests.get(url, proxies={"http": proxy, "https": proxy}, timeout=30)
            r.raise_for_status()
            return level, r
        except requests.RequestException as e:
            last_error = e
    raise RuntimeError(f"no IP at zip, city or state level: {last_error}")


level, resp = fetch_local("https://ipinfo.io/json", "nm", city="albuquerque", zip_code="87102")
print(level, resp.json().get("city"))

```

*3. A sticky session for a multi-step check*

```python
import requests

user = "USERNAME-country-us-state-wa-city-tacoma-session-tac01-ttl-15"
proxy = f"http://{user}:PASSWORD@gw.metroproxies.com:7777"

with requests.Session() as s:
    s.proxies = {"http": proxy, "https": proxy}
    first = s.get("https://api.ipify.org", timeout=30).text
    # step 1, step 2 ... on your own site, all from the same Tacoma IP
    second = s.get("https://api.ipify.org", timeout=30).text
    print(first, second, "same IP" if first == second else "IP changed: restart the flow")

```

## Which Python details trip people up?

- **New IP per request:** `requests.Session()` keeps the connection open, so rotating mode gives one IP for the whole session. Use plain `requests.get()` calls or a new `Session` per request to rotate.
- **SOCKS5:** install `pip install "requests[socks]"` and use `socks5h://` so that the proxy resolves hostnames, not your machine. Port 7778.
- **Special characters in the password:** URL-encode them with `urllib.parse.quote(password, safe="")`.
- **Timeouts:** always set one; residential exits can be slower than data-center ones.
- **Be polite:** keep the request rate to each site modest and follow robots.txt and its terms.

## Where should I go next?

Start from the [five-minute setup](https://metroproxies.com/docs/quickstart/), compare with the [Node.js](https://metroproxies.com/docs/node/) and [curl](https://metroproxies.com/docs/curl/) examples, and keep IPs with [sticky sessions by city](https://metroproxies.com/guides/sticky-sessions-by-city/). All docs: [documentation](https://metroproxies.com/docs/).

## What else do people ask about Python?

### Does httpx work too?

Yes. In httpx 0.28 and later, pass `proxy="http://USERNAME-country-us-state-il-city-chicago:PASSWORD@gw.metroproxies.com:7777"` to `httpx.Client()`. Older versions used a `proxies` argument.

### Were these examples run against the gateway?

They are syntax-checked with `python -I -m py_compile` on Python 3.10+, with USERNAME and PASSWORD as placeholders. Run them with your own credentials.

### How do I get the ASN of the exit IP?

The `org` field of ipinfo.io's reply starts with it ("AS7922 ..." for Comcast). For ASN targeting, add `-asn-7922` to the username; see [ASN targeting](https://metroproxies.com/targeting/asn/).

---

MetroProxies: MetroProxies is a US residential proxy provider with city-level targeting, paid in crypto with no ID upload. Home IPs are requested by city, state, ZIP code or ISP network, with a page of local data for each of 181 US cities.
