← Blog · · 5 min read

How to Scrape Search Results from Another Country with Residential Proxies

Two tabletop models of the same city block, one under cool overcast light and one with warm windows

A search results page is local. Rankings, ads, language, currency, and which listings even appear can change with the viewer’s country.

A residential proxy gets you a household ISP exit in that country. It does not, by itself, make a generic search URL return that country’s page. If you skip the local hostname, send English headers, or reuse cookies from another market, you can collect headquarters results and file them as “DE.”

This is the job: one public query, one country, one labeled results page. The country targeting guide covers the modifier. This post covers the search workflow that sits on top of it.

Name the job before the first request

Write the unit of work down. If you cannot fill this in, you are not ready to collect:

query     = one public search term
country   = ISO two-letter code you actually need
page      = the public results HTML the parser reads
success   = exit country matches AND the results page parsed

Keep one country per job. A worker that “just tries another country” when the first request fails will mix markets in the same table.

Use public pages. Do not collect personal results, signed-in rankings, or anything behind an account. Respect the destination’s terms, robots guidance where it applies, and the law.

Request the country on the proxy, not only in the URL

PacketStream country targeting is an auth-key suffix. The host and recommended HTTPS port stay the same: proxy.packetstream.io:31111.

AUTH_KEY_country-DE

Use uppercase ISO two-letter codes. Build the password from an allowlist in your job config, not from a free-text string a caller can inject.

set -o pipefail
COUNTRY=DE
COUNTRY_PASSWORD="${PACKETSTREAM_AUTH_KEY}_country-${COUNTRY}"

curl --silent --show-error --fail-with-body \
  --proxy 'https://proxy.packetstream.io:31111' \
  --proxy-user "${PACKETSTREAM_USER}:${COUNTRY_PASSWORD}" \
  'https://ipinfo.io' \
  | jq -e --arg want "$COUNTRY" 'select(.country == $want) | {ip, country, org}'

That command exits non-zero if cURL fails or the observed country is not DE. Do not start the search until it succeeds. City, region, and coordinates from an IP database are diagnostic, not extra targeting. Country is the supported boundary. Details: country targeting.

If the requested country has no available exit, the request fails. PacketStream does not silently send you through somewhere else. Record that as unavailable work. Do not strip _country-DE inside a generic retry so the job “succeeds” from the wrong market.

Use the local results URL and language

The exit is one input. The destination still chooses a page from:

  • the hostname or regional path you requested;
  • query parameters for country or language, when the site uses them;
  • Accept-Language;
  • cookies and prior session state.

Decide which of those your job actually requires. A German exit with an English Accept-Language and a generic /search URL is a mixed experiment, not a German results job.

curl --silent --show-error --fail-with-body \
  --location --max-redirs 1 \
  --proxy 'https://proxy.packetstream.io:31111' \
  --proxy-user "${PACKETSTREAM_USER}:${COUNTRY_PASSWORD}" \
  -H 'Accept-Language: de-DE,de;q=0.9' \
  --output /tmp/packetstream-search-de.html \
  --write-out '{"http_code":%{http_code},"url":"%{url_effective}","redirects":%{num_redirects}}\n' \
  'https://example.de/search?q=public-term'

Prefer the regional hostname or path the site publishes for that country. Follow one redirect, then record the final URL. If the job lands on a global homepage, that is a collection miss, not a parser problem.

Do not copy cookies, local storage, or a logged-in session from another country into this request. Start the results fetch with a clean client profile for that job.

Rotate for independent queries, stick for one results workflow

Independent public queries in the same country can use the country suffix alone. Each new proxy connection selects an available exit in that country. Reused connections keep the same exit. That is connection-based rotation, not a new IP per application request. See rotation and sticky sessions and connection pooling.

Pagination, “related searches,” or a click-through that must look like one visitor should share one exit:

AUTH_KEY_country-DE_session-search42

Use a non-sensitive label. If that session’s Packeter disconnects, the session fails. Stop the workflow, pick a new label, and restart from a known page. Do not continue page 2 as a different person.

Treat a 200 as unproven until the page parses

A status code does not mean you got that country’s results. After a 200:

  1. Confirm the observed exit country still matches the job.
  2. Confirm the final URL is the regional results page you asked for.
  3. Confirm the HTML contains the result list your parser expects, in the language you required.
  4. Reject challenge pages, empty shells, and homepages that only look like search.

Store three facts separately:

{
  "query": "public-term",
  "requested_country": "DE",
  "observed_country": "DE",
  "final_url": "https://example.de/search?q=public-term",
  "collected_at": "2026-08-31T15:00:00Z"
}

Do not infer the country later from the URL or from an IP database. If observed country and requested country disagree, quarantine the row. Quality checks belong with validation and change detection.

Keep failures in their own buckets

What happenedWhat to do
Auth failedStop. Fix credentials. Do not retry.
Requested country unavailableRecord unavailable. Bounded backoff. Keep the country suffix.
Destination error or timeoutRetry the destination policy. Same country.
200 that failed the parserDo not count as a result. Do not silently switch country.
Sticky session droppedNew session label. Restart the results workflow.

A controlled preflight is in the cURL checklist. Failure classes are in troubleshooting.

What this job is not

It is not a way to log into someone else’s account, harvest personal results, or defeat access controls. A residential exit changes the network path. It does not change what you are allowed to collect.

Keep the country on the job, verify the exit, request the local page, and label anything that is not that page. That is how you scrape search results from another country without filing the wrong web as data.