# Proxy Geo-Targeting by City, ZIP Code, and ASN: Up to 5 Locations per Request

Residential proxy geo-targeting lets you choose where a request exits: a country, a region, a city, a ZIP code, or a network (ASN). On Massive's residential network, multi-location targeting goes one step further and lets one proxy username name up to five locations. Write `country-US,GB,DE` and the request goes out through a device in any of those three countries, with traffic spread across them. The same works for subdivisions, cities, ZIP codes, and ASNs, and device type accepts a list too. This spotlight covers single city and ZIP code targeting, the syntax for lists, the four rules that keep lists unambiguous, and how to check which location actually served each request.

> **Key Takeaways**
>
> - Target one city with `country-US-subdivision-NY-city-New%20York`, or one ZIP code with `country-US-zipcode-10001`. A ZIP code overrides `city`.
> - `country`, `subdivision`, `city`, and `zipcode` each accept a comma-separated list of up to **5** values. A request is served by any node that matches one of them, and traffic is spread across them ([Massive Docs](https://docs.joinmassive.com/residential/geotargeting)).
> - `asn` also accepts up to 5 values, and `type` accepts several device types, such as `mobile,tv`.
> - Only one parameter per request may hold a list. A list of countries can't be narrowed by region, city, or ZIP code.
> - A second list or more than five values returns HTTP 400. Read the `X-Exit-Country` and `X-Exit-ASN` headers to see which value served each request.

## How do you target a residential proxy by city or ZIP code?

Add geo keys to the proxy username. `country` comes first and is required whenever you set any other geo key ([Massive Docs](https://docs.joinmassive.com/residential/geotargeting)). By city:

<div data-block="html"><div style="background:#011627;border:1px solid rgba(250,244,236,0.08);border-radius:10px;margin:1.5rem 0;"><div style="padding:10px 18px 0;font-family:'JetBrains Mono',monospace;font-size:11px;letter-spacing:0.08em;color:rgba(214,222,235,0.6);">BASH</div><pre style="margin:0;padding:10px 18px 16px;background:transparent;color:#d6deeb;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.65;white-space:pre-wrap;overflow-wrap:anywhere;overflow-x:visible;"><code>curl -x https://network.joinmassive.com:65535 \
     -U '{PROXY_USERNAME}-country-US-subdivision-NY-city-New%20York:{API_KEY}' \
     https://cloudflare.com/cdn-cgi/trace</code></pre></div></div>

Adding `subdivision` matters when a city name exists in more than one region of a country; without it, "the request can be served from any of them." By ZIP code:

<div data-block="html"><div style="background:#011627;border:1px solid rgba(250,244,236,0.08);border-radius:10px;margin:1.5rem 0;"><div style="padding:10px 18px 0;font-family:'JetBrains Mono',monospace;font-size:11px;letter-spacing:0.08em;color:rgba(214,222,235,0.6);">BASH</div><pre style="margin:0;padding:10px 18px 16px;background:transparent;color:#d6deeb;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.65;white-space:pre-wrap;overflow-wrap:anywhere;overflow-x:visible;"><code>curl -x https://network.joinmassive.com:65535 \
     -U '{PROXY_USERNAME}-country-US-zipcode-10001:{API_KEY}' \
     https://cloudflare.com/cdn-cgi/trace</code></pre></div></div>

When you set a ZIP code, the `city` key is ignored. Some countries accept partial postal codes, such as 5 characters in the United States and 3 in Canada. The docs add a caveat worth keeping in mind: "Geotargeting by country and city is always more robust than by ZIP code" ([Massive Docs](https://docs.joinmassive.com/residential/geotargeting)).

## What problem does multi-location targeting solve?

Single-location targeting forces a choice. Either you pin a request to one place and accept that a narrow target may have fewer available devices, or you drop targeting and accept requests from anywhere. Many real jobs sit in between. A price check for the EU market might accept Germany, France, or the Netherlands. An ad check for a U.S. campaign might accept any of its five target metros. A test of how a site treats mobile carriers might accept any of three carrier networks.

Without lists, covering those cases means rotating usernames in your own code. With a list, one username describes the whole acceptable set, and the network picks a matching device. Our [test of whether ChatGPT answers differ by country](https://www.joinmassive.com/blog/does-chatgpt-give-different-answers-by-country) covers when an AI agent needs a location at all. This is the next step: describing the set of locations that count as correct.

## How do you target several locations in one request?

Put a comma-separated list in the parameter. Per the [geotargeting docs](https://docs.joinmassive.com/residential/geotargeting), the request "is then served by any node that matches one of the listed values, and traffic is spread across them." Several countries look like this:

<div data-block="html"><div style="background:#011627;border:1px solid rgba(250,244,236,0.08);border-radius:10px;margin:1.5rem 0;"><div style="padding:10px 18px 0;font-family:'JetBrains Mono',monospace;font-size:11px;letter-spacing:0.08em;color:rgba(214,222,235,0.6);">BASH</div><pre style="margin:0;padding:10px 18px 16px;background:transparent;color:#d6deeb;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.65;white-space:pre-wrap;overflow-wrap:anywhere;overflow-x:visible;"><code>curl -x https://network.joinmassive.com:65535 \
     -U '{PROXY_USERNAME}-country-US,GB,DE:{API_KEY}' \
     https://cloudflare.com/cdn-cgi/trace</code></pre></div></div>

One country, several cities. City names are currently case-sensitive and must be URL-encoded, so New York becomes `New%20York`:

<div data-block="html"><div style="background:#011627;border:1px solid rgba(250,244,236,0.08);border-radius:10px;margin:1.5rem 0;"><div style="padding:10px 18px 0;font-family:'JetBrains Mono',monospace;font-size:11px;letter-spacing:0.08em;color:rgba(214,222,235,0.6);">BASH</div><pre style="margin:0;padding:10px 18px 16px;background:transparent;color:#d6deeb;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.65;white-space:pre-wrap;overflow-wrap:anywhere;overflow-x:visible;"><code>curl -x https://network.joinmassive.com:65535 \
     -U '{PROXY_USERNAME}-country-US-city-New%20York,Chicago:{API_KEY}' \
     https://cloudflare.com/cdn-cgi/trace</code></pre></div></div>

![Multi-location targeting syntax. A proxy username such as PROXY_USERNAME-country-US-city-New%20York,Chicago names one country and a list of up to five cities. The network serves each request from a device in any listed city and spreads traffic across them. Lists work for country, subdivision, city, zipcode, and asn, and type accepts several device types.](assets/multi-value-syntax.png "One username, up to five acceptable locations.")

## How do you target a proxy by ASN or device type?

Add `asn` to the username. **[ASN](https://www.joinmassive.com/glossary/what-is-an-asn)** (the number that identifies a network, such as a mobile carrier or ISP) accepts up to five values. This request is served by a U.S. node on either of two networks ([Massive Docs](https://docs.joinmassive.com/residential/asn-type-targeting)):

<div data-block="html"><div style="background:#011627;border:1px solid rgba(250,244,236,0.08);border-radius:10px;margin:1.5rem 0;"><div style="padding:10px 18px 0;font-family:'JetBrains Mono',monospace;font-size:11px;letter-spacing:0.08em;color:rgba(214,222,235,0.6);">BASH</div><pre style="margin:0;padding:10px 18px 16px;background:transparent;color:#d6deeb;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.65;white-space:pre-wrap;overflow-wrap:anywhere;overflow-x:visible;"><code>curl -x https://network.joinmassive.com:65535 \
     -U '{PROXY_USERNAME}-country-US-asn-7018,7922:{API_KEY}' \
     https://cloudflare.com/cdn-cgi/trace</code></pre></div></div>

**Device type** accepts a list that matches any of the named types. The values are `mobile`, `common` (any non-mobile device), and `tv`, and an unrecognized value returns HTTP 400. This request goes to a mobile or TV device in the U.S. ([Massive Docs](https://docs.joinmassive.com/residential/device-type-targeting)):

<div data-block="html"><div style="background:#011627;border:1px solid rgba(250,244,236,0.08);border-radius:10px;margin:1.5rem 0;"><div style="padding:10px 18px 0;font-family:'JetBrains Mono',monospace;font-size:11px;letter-spacing:0.08em;color:rgba(214,222,235,0.6);">BASH</div><pre style="margin:0;padding:10px 18px 16px;background:transparent;color:#d6deeb;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.65;white-space:pre-wrap;overflow-wrap:anywhere;overflow-x:visible;"><code>curl -x https://network.joinmassive.com:65535 \
     -U '{PROXY_USERNAME}-type-mobile,tv-country-US:{API_KEY}' \
     https://cloudflare.com/cdn-cgi/trace</code></pre></div></div>

## What are the rules for lists?

Four rules keep a list from turning into an ambiguous request. All four come from the [geotargeting docs](https://docs.joinmassive.com/residential/geotargeting):

| Rule | Example that works | Example that fails |
|------|--------------------|--------------------|
| One list per request | `country-US-city-Boston,Chicago` | `country-US,CA-city-Boston,Toronto` |
| A list of countries can't be narrowed | `country-US,GB,DE` | `country-US,GB-city-London` |
| `country` is still required | `country-US-zipcode-10001,60601` | `zipcode-10001,60601` |
| Up to 5 values | `country-US,GB,DE,FR,ES` | Six or more countries |

The second rule exists because "the same region or city name can exist in more than one country." There is one exception to it: a single `asn` can still be combined with several countries. A list of ASNs, on the other hand, needs every other parameter to be single-valued, because only one parameter may hold a list.

Two smaller details: duplicate and empty values are ignored, so `US,US` counts as one value. And a second list, more than five values, a missing `country`, or an unrecognized `type` returns HTTP 400, so you find out at the first request, not after a silent fallback to some other location.

## A 407 can hide a targeting mistake

We checked how the network reports a bad username without spending any traffic. On October 10, 2026, we sent six usernames to the residential endpoint with a deliberately invalid API key. Four broke a documented rule: six countries, two lists in one request, a city with no country, and an unknown device type.

<div data-block="html"><div style="background:#011627;border:1px solid rgba(250,244,236,0.08);border-radius:10px;margin:1.5rem 0;"><div style="padding:10px 18px 0;font-family:'JetBrains Mono',monospace;font-size:11px;letter-spacing:0.08em;color:rgba(214,222,235,0.6);">TEXT</div><pre style="margin:0;padding:10px 18px 16px;background:transparent;color:#d6deeb;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.65;white-space:pre-wrap;overflow-wrap:anywhere;overflow-x:visible;"><code>probe-country-US,GB,DE
probe-country-US,GB,DE,FR,ES,IT
probe-country-US,CA-city-Boston,Toronto
probe-city-Boston
probe-type-mobile,tv-country-US
probe-type-watch-country-US</code></pre></div></div>

Every one of the six came back `407 Proxy Authentication Required`, not `400`. You can repeat the test with any placeholder username and key.

So the network checks credentials before it checks targeting. That ordering matters when you debug. A `407` tells you nothing about whether your targeting is valid, so fix the credentials first. Once authentication passes, a `400` points at the targeting itself.

## Validate a multi-location username before you send it

You can catch these mistakes before a request leaves your code. This small builder enforces the documented rules and URL-encodes city names:

<div data-block="html"><div style="background:#011627;border:1px solid rgba(250,244,236,0.08);border-radius:10px;margin:1.5rem 0;"><div style="padding:10px 18px 0;font-family:'JetBrains Mono',monospace;font-size:11px;letter-spacing:0.08em;color:rgba(214,222,235,0.6);">PYTHON</div><pre style="margin:0;padding:10px 18px 16px;background:transparent;color:#d6deeb;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.65;white-space:pre-wrap;overflow-wrap:anywhere;overflow-x:visible;"><code>from urllib.parse import quote
GEO = ("country", "subdivision", "city", "zipcode")
LISTABLE = GEO + ("asn",)
ORDER = ("type",) + LISTABLE
DEVICE_TYPES = {"mobile", "common", "tv"}
def massive_username(base, **params):
    """Build a residential proxy username and enforce the documented list rules."""
    unknown = set(params) - set(ORDER)
    if unknown:
        raise ValueError(f"unsupported keys: {sorted(unknown)}")
    vals = {}
    for key in ORDER:
        value = params.get(key)
        if value is None or value == "" or (
            isinstance(value, (list, tuple)) and not value
        ):
            continue
        items = value if isinstance(value, (list, tuple)) else [value]
        # The network ignores duplicate and empty values; drop them here too.
        items = list(dict.fromkeys(str(v).strip() for v in items if str(v).strip()))
        if key in LISTABLE and len(items) &gt; 5:
            raise ValueError(f"{key}: up to 5 values")
        if key == "type" and not set(items) &lt;= DEVICE_TYPES:
            raise ValueError(f"type must be one of {sorted(DEVICE_TYPES)}")
        vals[key] = items
    if any(k in vals for k in GEO) and "country" not in vals:
        raise ValueError("country is required with any geo key")
    lists = [k for k in LISTABLE if len(vals.get(k, [])) &gt; 1]
    if len(lists) &gt; 1:
        raise ValueError(f"only one list per request, got {lists}")
    if len(vals.get("country", [])) &gt; 1 and any(k in vals for k in GEO[1:]):
        raise ValueError("a list of countries can't be narrowed")
    return "-".join([base] + [f"{k}-{','.join(quote(v) for v in vals[k])}" for k in vals])
print(massive_username("{PROXY_USERNAME}", country="US", city=["New York", "Chicago"]))
# {PROXY_USERNAME}-country-US-city-New%20York,Chicago</code></pre></div></div>

We ran it against 13 cases on October 10, 2026. The valid inputs built the expected usernames, and six countries, two lists, a narrowed country list, a city without a country, and an unknown device type each raised an error. It covers the rules the docs state. The docs don't say whether a device-type list counts toward the one-list limit, so the builder doesn't enforce that.

## Lists versus strict targeting

Lists widen targeting. Stacking several single-value parameters narrows it. The docs warn that "the more strict geotargeting narrows the range of appropriate nodes," and the knowledge base advises starting broad and narrowing as needed ([Massive Docs](https://docs.joinmassive.com/kb/technical/what-are-the-rules-for-combining-parameters)).

Lists give you a middle setting. If a single small city returns `471 No Route Match`, which means no available node matched your parameters ([Massive Docs](https://docs.joinmassive.com/residential/error-types)), a list of nearby cities in the same country is often a better fix than dropping to country level. You keep the results local while giving the network more devices to choose from.

## How do you know which location served the request?

Read the exit node headers, the network's own record of [where the exit IP sits](https://www.joinmassive.com/glossary/what-is-ip-geolocation). For HTTPS traffic, the response to the proxy's [CONNECT request](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect) includes `X-Exit-IP` and, when the data is available, `X-Exit-Country`, `X-Exit-Timezone`, and `X-Exit-ASN` ([Massive Docs](https://docs.joinmassive.com/residential/exit-node-headers)). Run curl with `-v` to see them:

<div data-block="html"><div style="background:#011627;border:1px solid rgba(250,244,236,0.08);border-radius:10px;margin:1.5rem 0;"><div style="padding:10px 18px 0;font-family:'JetBrains Mono',monospace;font-size:11px;letter-spacing:0.08em;color:rgba(214,222,235,0.6);">TEXT</div><pre style="margin:0;padding:10px 18px 16px;background:transparent;color:#d6deeb;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.65;white-space:pre-wrap;overflow-wrap:anywhere;overflow-x:visible;"><code>&lt; HTTP/1.1 200 OK
&lt; X-Exit-IP: 203.0.113.42
&lt; X-Exit-Country: US
&lt; X-Exit-Timezone: America/New_York
&lt; X-Exit-ASN: 7922</code></pre></div></div>

When a request can be served from any of five places, log which one served it. Store the exit country and ASN next to each result. If one market's numbers look off later, you can split your data by the location that served it instead of guessing. The same location parameters work on the [AI chat endpoint](https://www.joinmassive.com/blog/ai-chat-endpoint-geotargeted-llm-completions) when the thing you're checking is an LLM answer rather than a page.

## Four jobs where multi-location targeting helps

- **Regional price and stock checks.** Name the countries or cities that make up a market, and let the network spread requests across them. For an EU price check, `country-DE,FR,NL` covers three markets with one username and no rotation code.
- **Ad verification.** List a campaign's target ZIP codes, such as `country-US-zipcode-10001,60601,94103`.
- **Carrier and device testing.** List the carrier networks or device types you care about, such as `type-mobile,tv`, without writing rotation logic.
- **Resilient localized fetching.** Swap a narrow target that sometimes returns `471` for a short list of equivalent ones.

## Frequently Asked Questions

### Can I get a residential proxy by city or ZIP code?

Yes. Add `country` plus `city` (and `subdivision` if the city name repeats within the country), or `country` plus `zipcode`, to the proxy username. Each key also accepts a list of up to 5 values.

### How many locations can one Massive proxy request target?

Up to five values in one parameter, such as five countries or five cities in one country. More than five returns HTTP 400.

### Can I list several countries and several cities at once?

No. Only one parameter per request may hold a list, and a list of countries can't be combined with `subdivision`, `city`, or `zipcode`.

### Can I combine an ASN with several countries?

Yes. A single `asn` can be combined with a list of countries. A list of ASNs needs `country` and every other parameter to be single-valued.

### How do I see which country served my request?

Read the `X-Exit-Country` header in the CONNECT response for HTTPS traffic. `X-Exit-ASN` shows the network.

## The bottom line

- With proxy geo-targeting lists, one proxy username can describe up to five acceptable countries, subdivisions, cities, ZIP codes, or ASNs, plus several device types.
- Keep to one list per request, keep `country` in every geo request, and don't narrow a list of countries.
- Log the exit country and ASN.

## Sources

- Massive Docs, ["Geotargeting"](https://docs.joinmassive.com/residential/geotargeting)
- Massive Docs, ["ASN identifier targeting"](https://docs.joinmassive.com/residential/asn-type-targeting)
- Massive Docs, ["Device-type targeting"](https://docs.joinmassive.com/residential/device-type-targeting)
- Massive Docs, ["Exit Node Headers"](https://docs.joinmassive.com/residential/exit-node-headers)
- Massive Docs, ["Error Types"](https://docs.joinmassive.com/residential/error-types)
- IETF, ["RFC 9110: HTTP Semantics, CONNECT"](https://www.rfc-editor.org/rfc/rfc9110.html#name-connect)
- Massive Docs, ["What are the rules for combining parameters?"](https://docs.joinmassive.com/kb/technical/what-are-the-rules-for-combining-parameters)
