Amazon Scraper API vs Proxy: Choose a Product Data Source
Compare seller APIs, licensed Amazon product data and proxy page checks by record, access scope and reuse rights.
Read guideTest DE egress separately from de-DE content, EUR pricing, VAT display, and the delivery market used by the target.

A German residential proxy helps only when the target or the acceptance rule needs a German home exit. Then check two things separately: the exit (DE in the same browser that runs the check) and the page itself (German language, euro prices, VAT display and German delivery). A Berlin IP that still returns the English store in dollars is not a German result.
Audience: Proxy buyers and developers comparing a permitted market or delivery test. The examples use Python and Playwright; they do not teach general Python syntax.
Prerequisites:
http://host:port, https://host:port, or socks5://host:port form and a test account with a request or traffic limit. Set PROXY_SERVER. Playwright documents proxy username/password settings for HTTP(S) proxies, and Chromium supports no SOCKS5 authentication methods. Use socks5:// only when the supplier permits unauthenticated access; set PROXY_USER and PROXY_PASSWORD separately only for HTTP(S) proxy authentication. Load any credentials from an approved secret manager or environment binding. Playwright documents HTTP proxy authentication; Chromium documents unauthenticated SOCKS5 support.https://httpbin.org/ip through the selected route and to access the intended target.TARGET_URL on an HTTP or HTTPS page, TARGET_EXPECTED_STATUS set to its expected integer response status, and TARGET_BODY_MARKER set to non-sensitive visible text that should appear in that page. Provide all three through the environment; do not embed credentials in the target URL.Install the pinned Python package and its matching Chromium build in the active environment:
python -m pip install playwright==1.58.0
python -m playwright install chromium
Put each supplier's exact product in the same worksheet before choosing. Prefer the offer that meets the required German result at the lower total cost of accepted records, including retries and minimum spend.
| Offer field | Decision rule |
|---|---|
| Current DE inventory and account entitlement | Confirm country access and Berlin or Munich only where the job requires city egress |
| Residential definition and sourcing | Require documented network class; compare datacenter separately when it is acceptable |
| City match and no-match response | Declare the allowed metro tolerance and reject silent fallback outside it |
| Session duration and replacement | Require continuity through the selected account, product and delivery sequence |
| Target and VAT display | Test the same account type and record gross/net labels, tax line and currency rather than comparing unlike prices |
| Account and workload terms | Confirm permitted targets, billing units, retry charges, minimum purchase and expiry |
For example, a country-level offer that holds a session can suit a German checkout controlled by delivery address. A city-specific offer with per-request rotation may be a worse fit for that journey. Conversely, a Berlin-localized campaign needs the city match even if the country offer is cheaper. These are selection rules, not vendor performance results.
Use DE as the ISO 3166 country field and EUR as the ISO 4217 currency field. BCP 47 provides a standard form for a locale such as de-DE; the IANA time-zone database supplies Europe/Berlin for the browser context. These are test inputs. They do not turn a proxy selector into proof of German egress.
German product pages may show a gross amount, a net amount, or no tax line until checkout. Record the target's label and tax line for the same account and delivery fixture; do not add a rate to a displayed price or compare unlike totals.
Deutsche Post's address data documentation uses a five-character field for the postal code. Use a real, authorized test address and keep its postcode separate from the observed IP city.
Two hypothetical jobs use the fixture differently. A Berlin consumer storefront check needs Berlin or an agreed metro only when campaign behavior depends on egress city. A Munich business-account check needs an authorized business account and the agreed catalog tier; a Munich delivery address alone does not require Munich egress. Keep consumer gross and business net totals separate.
| Requirement | Example German fixture | Pass condition |
|---|---|---|
| Country exit | requested_country=DE |
A named lookup reports DE and keeps its source, date and uncertainty |
| City rule | requested_city=Berlin or Munich |
The observed city fits the predeclared city or metro tolerance |
| Browser context | locale=de-DE, timezone=Europe/Berlin |
The automation uses the intended language and clock inputs |
| Delivery market | delivery_country=DE, authorized five-digit postcode |
The target accepts the selected German delivery context |
| Offer record | currency=EUR, amount, VAT display, final URL |
Every value comes from the target observation, with no invented total |
The sample checks the IP echo and then opens the authorized target in the same browser context. It accepts the target only when the final navigation status matches TARGET_EXPECTED_STATUS and visible body text contains TARGET_BODY_MARKER. Neither check proves country egress, residential classification, or a localized offer.
Warning: Each run makes a top-level request to httpbin and navigates to TARGET_URL. The target page may also trigger redirects and subresource requests, so total requests and traffic can exceed those two top-level checks; the supplier may bill according to its own documented units and receives the destinations. Start with a provider sandbox and an owned staging target when available. Without a sandbox, treat the run as a production test: use an authorized target, a low-limit test account, and a preset spend cap.
If an authenticated http:// proxy uses HTTP Basic, credentials travel without TLS protection; RFC 7617 recommends an external secure layer such as TLS. Use the provider's TLS-to-proxy endpoint when available. The proxy and target schemes are separate: an http:// target has no TLS, while an https:// target protects browser-to-target traffic inside the tunnel after setup. Neither upgrades an http:// browser-to-proxy hop or protects Basic credentials sent before the tunnel.
Keep credentials in environment bindings, never in either URL, source files, screenshots, or shared logs. If routing or usage differs from the quote, close the browser, stop the session or revoke its test credentials using the supplier's documented controls, and inspect usage before another request.
import asyncio
import json
import os
from urllib.parse import urlsplit
from playwright.async_api import async_playwright
# Configuration comes from the approved environment binding; never print these values.
PROXY_SERVER = os.getenv("PROXY_SERVER")
PROXY_USER = os.getenv("PROXY_USER")
PROXY_PASSWORD = os.getenv("PROXY_PASSWORD")
TARGET_URL = os.getenv("TARGET_URL")
TARGET_EXPECTED_STATUS = os.getenv("TARGET_EXPECTED_STATUS")
TARGET_BODY_MARKER = os.getenv("TARGET_BODY_MARKER")
NAVIGATION_TIMEOUT_MS = 20000
BODY_MARKER_TIMEOUT_MS = 10000
LOCALE = "de-DE"
TIMEZONE = "Europe/Berlin"
async def main():
if bool(PROXY_USER) != bool(PROXY_PASSWORD):
raise ValueError("Provide both proxy credentials or neither")
try:
proxy_parts = urlsplit(PROXY_SERVER or "")
proxy_port = proxy_parts.port
except ValueError as error:
raise ValueError("Set PROXY_SERVER to a documented host:port endpoint without credentials") from error
if (
proxy_parts.scheme not in {"http", "https", "socks5"}
or not proxy_parts.hostname
or not proxy_port
or proxy_parts.username is not None
or proxy_parts.password is not None
):
raise ValueError("Set PROXY_SERVER to a documented HTTP(S) or SOCKS5 endpoint without credentials")
if proxy_parts.scheme == "socks5" and (PROXY_USER or PROXY_PASSWORD):
raise ValueError("Use SOCKS5 without proxy credentials; this example supports credentials only for HTTP(S) proxies")
try:
target_parts = urlsplit(TARGET_URL or "")
except ValueError as error:
raise ValueError("Set TARGET_URL to a permitted HTTP(S) page without embedded credentials") from error
if (
target_parts.scheme not in {"http", "https"}
or not target_parts.hostname
or target_parts.username is not None
or target_parts.password is not None
):
raise ValueError("Set TARGET_URL to a permitted HTTP(S) page without embedded credentials")
try:
expected_status = int(TARGET_EXPECTED_STATUS or "")
except ValueError as error:
raise ValueError("Set TARGET_EXPECTED_STATUS to the expected integer status code") from error
if not 100 <= expected_status <= 599:
raise ValueError("Set TARGET_EXPECTED_STATUS to an HTTP status from 100 through 599")
if not TARGET_BODY_MARKER or not TARGET_BODY_MARKER.strip():
raise ValueError("Set TARGET_BODY_MARKER to non-sensitive visible text expected on the target page")
proxy = {"server": PROXY_SERVER}
if PROXY_USER:
proxy.update(username=PROXY_USER, password=PROXY_PASSWORD)
async with async_playwright() as playwright:
browser = await playwright.chromium.launch()
try:
context = await browser.new_context(
proxy=proxy, locale=LOCALE, timezone_id=TIMEZONE
)
try:
page = await context.new_page()
echo_response = await page.goto(
"https://httpbin.org/ip",
wait_until="domcontentloaded",
timeout=NAVIGATION_TIMEOUT_MS,
)
if echo_response is None or echo_response.status != 200:
raise RuntimeError("IP echo request failed")
echo_payload = json.loads(await page.locator("body").inner_text(timeout=BODY_MARKER_TIMEOUT_MS))
origin = echo_payload.get("origin")
if not isinstance(origin, str) or not origin:
raise RuntimeError("IP echo did not return an address")
target_response = await page.goto(
TARGET_URL,
wait_until="domcontentloaded",
timeout=NAVIGATION_TIMEOUT_MS,
)
if target_response is None or target_response.status != expected_status:
raise RuntimeError("Target response did not match TARGET_EXPECTED_STATUS")
marker = page.get_by_text(TARGET_BODY_MARKER, exact=False).first
await marker.wait_for(state="visible", timeout=BODY_MARKER_TIMEOUT_MS)
body_text = await page.locator("body").inner_text(
timeout=BODY_MARKER_TIMEOUT_MS
)
if TARGET_BODY_MARKER not in body_text:
raise RuntimeError("Target body did not contain TARGET_BODY_MARKER")
print({
"observed_exit": origin,
"target_status": target_response.status,
"body_marker_found": True,
"locale": LOCALE,
"timezone": TIMEZONE,
})
finally:
await context.close()
finally:
await browser.close()
asyncio.run(main())
Illustrative expected output (the address is redacted; the values are not a country or target measurement):
{'observed_exit': '<redacted public IP>', 'target_status': 200, 'body_marker_found': True, 'locale': 'de-DE', 'timezone': 'Europe/Berlin'}
Save the example as germany-probe.py and run it after loading the environment values:
python germany-probe.py
Set PROXY_SERVER, TARGET_URL, TARGET_EXPECTED_STATUS, and TARGET_BODY_MARKER in the approved environment; set both proxy credentials only if required. Playwright's page navigation and locator wait use bounded timeouts here: 20,000 ms per navigation and 10,000 ms for visible marker text. The script opens the target in the same configured context after the IP echo, then closes the context. A timeout or status/marker mismatch fails the check. These response checks do not establish country or city egress, a residential network, a delivery address, or a purchasable offer. Compare the returned IP with a dated lookup and verify country-specific business fields in an authorized target workflow. Redact the IP and target details before sharing logs.
Keep PROXY_SERVER free of credentials. If the supplier requires a different authentication scheme, use its documented client configuration rather than adapting a username format from another provider. Compare the returned IP with a dated lookup. MaxMind notes that city-level IP results have uncertainty, so a city label alone is not a delivery address.
A status and marker match confirms only the configured page response. For a German offer, also compare the observed DE lookup, account type, delivery destination, language, currency, and gross/net tax fields against the fixture. A redirect, global catalog, or missing tax line leaves the result incomplete.
| Symptom | Check | Next action |
|---|---|---|
| Proxy returns an authentication error | The endpoint or credential format may not match the quoted product | If the response is 407, confirm the server and separate credentials with the supplier’s official setup guide; do not copy username formats from another provider |
| The target switches to a global catalog | Account or market state differs from the fixture | Keep account, SKU, locale, and delivery postcode fixed; record the redirect instead of treating it as a German offer |
| A city lookup disagrees with the requested city | IP geolocation has a broader accuracy area than the requested metro | Apply the predeclared city tolerance or reject the route; do not infer a delivery address from the IP |
| The checkout omits VAT or delivery details | The target has not exposed a complete offer | Preserve the missing field and classify the record as incomplete; do not calculate a substitute price |
Residential, datacenter, and mobile routes answer different buyer requirements. Select residential when the target or acceptance rule requires an end-user network class and the supplier documents its sourcing. A datacenter route can fit a server-side German job when network class is not part of the requirement. Mobile is a separate product with separate inventory and terms; a German residential selector cannot satisfy a mobile requirement. Compare the route types in the residential versus datacenter guide and mobile and ISP guide.
Keep the declared retry and minimum-purchase terms with the selected offer; the cost-per-successful-request guide explains how to compare accepted records.
Scale your workflows with the tools you already use. Rotating or sticky sessions up to 72 hours.
Compare seller APIs, licensed Amazon product data and proxy page checks by record, access scope and reuse rights.
Read guideChoose the right anti-detect browser proxy guide, map the shared verification steps, and keep account access separate from the network route.
Read guideOur picks for market research: ProxyLane for small, intermittent projects, plus options for regional tracking, monthly collection and managed extraction.
Read guide