amazon.com

amazon-global-prices

Installation

Adds this website's skill for your agents

 

Summary

Compare an Amazon product (query or ASIN) across multiple country storefronts (.com, .co.uk, .de, .co.jp, .fr, .it, .es, .ca, .com.au, .com.mx) and return per-country price, currency, title, and product URL in local currency. Handles the storefront-TLD-selects-catalog-but-not-currency trap by explicitly setting delivery address + language/currency preference on each storefront before extracting prices.

FIG. 01
FIG. 02
FIG. 03
FIG. 04
FIG. 05
FIG. 06
FIG. 07
FIG. 08
FIG. 09
FIG. 10
SKILL.md
268 lines

Amazon Global Price Comparison

Purpose

Given a product query (or ASIN) and a list of country codes, return the same product's price in each country's local Amazon storefront, in the local currency. For each country, the skill returns { country, storefront, currency, price, price_raw, title, asin, url }. Read-only — never adds to cart, never submits an order.

When to Use

  • Cross-border price-shopping for an electronics/book/grocery item (US vs UK vs DE vs JP vs CA, etc.).
  • Arbitrage research: where is product X cheapest after setting delivery to a local address?
  • Daily/weekly price-watch monitoring across regions for one ASIN.
  • Any flow that needs local-currency, locally-delivered prices rather than the "international shopper, prices in USD with import deposit" default that Amazon shows to US-IP visitors of foreign storefronts.

Workflow

The per-storefront flow is browser-driven — there is no public Amazon API the marketplace exposes for this. Two non-obvious things this skill must get right:

  • Storefront TLD selects the catalog (.de, .co.uk, .co.jp, …) but does NOT select the currency. Currency follows the delivery address set on that storefront's session, not the IP and not the TLD. A fresh amazon.de session opened from any non-EU IP defaults to "Deliver to United States" and prices the catalog in USD with Global Store import fees baked in, not EUR. This is the single most common failure mode and must be corrected before extracting prices.
  • Browserbase proxies.geolocation.country is not reliably honored. A session created with proxies: [{type: "browserbase", geolocation: {country: "DE"}}] still routes through AWS Oregon (US) IPs in our testing — the storefront sees a US IP regardless. So --proxies is useful for general anti-bot evasion, but do not rely on the proxy alone to get local pricing. Always set the delivery address explicitly.

1. Create a Browserbase session per country (or one session reused sequentially)

SID=$(browse cloud sessions create --keep-alive --verified --proxies \
  | node -e "let s='';process.stdin.on('data',c=>s+=c).on('end',()=>process.stdout.write(JSON.parse(s).id))")
export BROWSE_SESSION="$SID"

--verified + --proxies gives stealth + the residential-proxy pool. Parallel sessions (one per country) are preferred for throughput; sequential session-reuse works but each storefront needs its own location/language setup because preferences are cookie-scoped per TLD.

2. For each country, set delivery location and currency on its storefront

Amazon storefronts cookie-scope language + currency + ship-to address per TLD. Do the setup once per storefront per session, then search. Skipping this step yields USD prices on amazon.de/.co.uk/.co.jp/etc. and is the #1 source of bad data.

CountryTLDPostal code (working)CurrencyLanguage code
USamazon.com(default — no setup)USDen_US
UKamazon.co.ukSW1A 1AAGBPen_GB
DEamazon.de10115EURde_DE
FRamazon.fr75001EURfr_FR
ITamazon.it20121EURit_IT
ESamazon.es28001EURes_ES
JPamazon.co.jp100-0001JPYja_JP
CAamazon.caM5H 2N2CADen_CA
AUamazon.com.au2000AUDen_AU
MXamazon.com.mx01000MXNes_MX

Steps (verified flow for amazon.de, structure is identical across non-US TLDs):

browse open "https://www.amazon.de/" --remote --session "$SID"
browse wait load --remote --session "$SID"
browse wait timeout 1500 --remote --session "$SID"

# Cookie banner — only first visit. Snapshot and click the Accept button if present.
# Look for: button: Accept  (dialog "Cookies and Advertising Choices")
# Skip if no dialog.

# Open delivery-location modal — header has a button labeled "Deliver to <country>"
browse snapshot --remote --session "$SID"   # find ref of "button: Deliver to <X>"
browse click "@<ref>" --remote --session "$SID"
browse wait timeout 1500 --remote --session "$SID"

# Modal exposes "or enter a postal code in <Country>" textbox + Apply button
browse snapshot --remote --session "$SID"   # find textbox ref + Apply button ref
browse fill "@<textbox-ref>" "10115" --remote --session "$SID"
browse wait timeout 500 --remote --session "$SID"
browse click "@<apply-ref>" --remote --session "$SID"
browse wait timeout 2500 --remote --session "$SID"

# Set language + currency via preferences page (avoids USD-display-in-English)
browse open "https://www.amazon.de/customer-preferences/edit?language=de_DE" \
  --remote --session "$SID"
browse wait load --remote --session "$SID"
browse snapshot --remote --session "$SID"   # find "radio: Deutsch - DE", "radio: € - EUR …", "button: Save changes"
browse click "@<deutsch-radio>" --remote --session "$SID"
browse click "@<eur-radio>" --remote --session "$SID"
browse click "@<save-changes>" --remote --session "$SID"
browse wait timeout 2500 --remote --session "$SID"

After this, the session is configured for German prices in EUR. Verify by reading glow-ingress-line2 from the page HTML — it should show a city in the target country, not "United States".

3. Search and extract

browse open "https://www.amazon.de/s?k=$(printf %s "$QUERY" | jq -sRr @uri)" \
  --remote --session "$SID"
browse wait load --remote --session "$SID"
browse wait timeout 2500 --remote --session "$SID"
browse get html body --remote --session "$SID" > /tmp/page.json

OR open the product detail page if you already have the ASIN: https://www.amazon.{tld}/dp/{ASIN}.

Parse the search-results HTML. Each card is wrapped in <div data-asin="B0XXXXXXXX" data-component-type="s-search-result" ...>. Within each block, harvest:

FieldSource
asindata-asin attribute
title<h2><span>{title}</span></h2> or aria-label="…" on the <h2> (look for class="a-size-medium ... a-text-normal")
price (display)<span class="a-offscreen">…</span> — full formatted string, e.g. "226,07 €", "$159.99", "£199.99", "¥34,980"
currency symbol<span class="a-price-symbol">…</span> / £ / $ / . NOTE: when currency is mis-set to USD on a foreign storefront, this span contains the literal string "USD" instead of $ — this is the canary for "you forgot to set delivery+currency."
price (numeric)<span class="a-price-whole">{whole}</span><span class="a-price-fraction">{frac}</span>
url<a class="a-link-normal …" href="/-/en/Amazon/dp/B0…/ref=sr_1_…">… — strip ?… query, prepend storefront origin

Stagehand extract with Zod schema (alternative to manual HTML parsing — recommended for production):

import { Stagehand } from "@browserbasehq/stagehand";
import { z } from "zod";

const result = await stagehand.page.extract({
  instruction:
    "Extract the first non-sponsored, non-Amazon-Device search result " +
    "that matches the product query. Return ASIN, title, currency symbol, " +
    "numeric price (combine whole + fraction), and product detail page URL.",
  schema: z.object({
    asin: z.string().regex(/^B0[A-Z0-9]{8}$/),
    title: z.string(),
    currency: z.enum(["USD","EUR","GBP","JPY","CAD","AUD","MXN"]),
    price: z.number().positive(),
    price_raw: z.string(),
    url: z.string().url(),
  }),
});

Stagehand's extract reads the rendered DOM (not just the raw HTML), so it transparently handles the lazy-loaded a-price blocks that sometimes are absent from the initial browse get html body snapshot. Pair with the location+currency setup above.

4. Normalize and aggregate

For each country, normalize the a-price-symbol + numeric whole/fraction into ISO-4217 currency codes (€ → EUR, £ → GBP, ¥ → JPY, $ → USD on amazon.com/amazon.ca/amazon.com.au — disambiguate by TLD), and floating-point price. Concatenate into a single result envelope.

5. Release sessions

browse cloud sessions update "$SID" --status REQUEST_RELEASE

Site-Specific Gotchas

  • Storefront TLD selects catalog, NOT currency. amazon.de from a US IP defaults to "Deliver to United States" and displays USD (with Global Store import fees) regardless of TLD. Always set the delivery address per storefront before reading prices. The a-price-symbol span literally contains the string "USD" (not $) on a mis-configured foreign storefront — use that as a self-check before emitting results.
  • Browserbase proxy geolocation.country is not reliably honored: proxies: [{type: "browserbase", geolocation: {country: "DE"}}] still routed through AWS Oregon IPs in our 2026-05-20 testing — ipinfo.io/json returned country: US, city: Boardman from the proxied session. Setting the storefront's delivery address explicitly is the only reliable path to local-currency prices. Don't trust the proxy country flag.
  • Preferences are cookie-scoped per TLD, NOT shared across storefronts. A session that has been set up for amazon.de (Berlin + EUR) still defaults to "United States / USD" when opening amazon.co.uk — you must run the setup flow once per storefront. Parallel sessions (one per country) avoid this serialization.
  • First search result is often an Amazon Device (Kindle, Echo, Fire TV) with no price displayed — the data-cy="price-recipe" block is empty and the card shows a "Learn More" CTA instead of a price. Skip and use the next result that matches the query. This is consistent across .com / .de / .co.uk / .co.jp.
  • Sponsored results are interleaved. Amazon mixes third-party sponsored listings (e.g. JBL/HyperX in a Sony search) ahead of the literal match. Filter by matching query tokens against the title before emitting. Sponsored cards have the same data-asin structure — there's no cheap "is-sponsored" attribute on the outer div; the <span>Sponsored</span> label appears nested inside.
  • Markdown body extraction (browse get markdown body) often drops the <span class="a-offscreen"> price text — the markdown converter strips visually-hidden spans. Use browse get html body and regex on data-asin blocks, or use Stagehand extract against the live DOM.
  • a-offscreen may contain the title instead of the price when the price block hasn't rendered yet — Amazon uses a-offscreen for multiple screen-reader fallbacks. Always cross-check a-price-symbol + a-price-whole + a-price-fraction against a-offscreen — if a-offscreen doesn't start with a currency symbol/code, ignore it.
  • Cookie consent banner blocks DOM interaction on first visit for EU storefronts (DE/UK/FR/IT/ES). Snapshot for dialog: Cookies and Advertising Choices and click button: Accept (or Decline — both unblock the page). The banner does NOT auto-dismiss on navigation; it must be clicked.
  • /customer-preferences/edit?language=<lc> is the canonical language+currency setter. The query-string-only trick (https://www.amazon.de/?language=de_DE&currency=EUR) does NOT persist preferences — it sets one-shot URL params that don't survive navigation. The preferences page is the only reliable persistent setter we found.
  • Postal codes — accept format varies. DE/FR/IT/ES/JP/AU accept numeric ZIPs. UK requires alphanumeric postcode with space (SW1A 1AA). CA requires alphanumeric with space (M5H 2N2). MX accepts numeric. JP accepts numeric with optional dash (100-0001 or 1000001).
  • amazon.com defaults to USD without setup. Don't run the location/currency flow on amazon.com unless you actually need a non-US delivery zip — it works out of the box.
  • Amazon shows "Deliver to" location in the header via <span id="glow-ingress-line2">…</span> — read this to verify the location was applied correctly. If it still says "United States" after you tried to set DE, the modal click didn't take and the session will yield USD prices.
  • Product detail page (/dp/{ASIN}) is more reliable for single-ASIN price lookup than search — it skips the sponsored-result filtering and the "first result is a device with no price" problem. Use /dp/ when you already have an ASIN.
  • JPY prices have no decimal fractiona-price-fraction is absent on amazon.co.jp. Treat a-price-whole as the full integer price.
  • EU price formatting uses comma as decimal separator: 226,07 € (not 226.07 €). Normalize before parsing to float.
  • Each storefront-setup adds ~6–10 seconds of wall time (load home → accept cookies → open modal → fill ZIP → apply → load prefs → click 3 radios → save → reload). Budget ~15 seconds per country including the actual search. For 5 countries, sequential = ~75s, parallel = ~15s.
  • Don't trust the inferred currency from TLD alone for amazon.com vs amazon.ca vs amazon.com.au — all three use $ as a-price-symbol. Map currency by TLD, never by symbol: .com → USD, .ca → CAD, .com.au → AUD, .com.mx → MXN. Same for : .co.jp → JPY (not CNY).

Expected Output

{
  "success": true,
  "query": "Sony WH-1000XM5",
  "results": [
    {
      "country": "US",
      "storefront": "amazon.com",
      "currency": "USD",
      "price": 328.00,
      "price_raw": "$328.00",
      "title": "Sony WH-1000XM5 Wireless Industry Leading Noise Canceling Headphones",
      "asin": "B09Y2MYL5C",
      "url": "https://www.amazon.com/dp/B09Y2MYL5C"
    },
    {
      "country": "DE",
      "storefront": "amazon.de",
      "currency": "EUR",
      "price": 226.07,
      "price_raw": "226,07 €",
      "title": "Sony WH-1000XM5 Kabelloser Premium-Kopfhörer mit Noise Cancelling",
      "asin": "B0BXM22X99",
      "url": "https://www.amazon.de/dp/B0BXM22X99"
    },
    {
      "country": "UK",
      "storefront": "amazon.co.uk",
      "currency": "GBP",
      "price": 199.99,
      "price_raw": "£199.99",
      "title": "Sony WH-1000XM5 Wireless Noise Cancelling Headphones",
      "asin": "B09Y2MYL5C",
      "url": "https://www.amazon.co.uk/dp/B09Y2MYL5C"
    },
    {
      "country": "JP",
      "storefront": "amazon.co.jp",
      "currency": "JPY",
      "price": 34980,
      "price_raw": "¥34,980",
      "title": "ソニー ワイヤレスノイズキャンセリングヘッドホン WH-1000XM5",
      "asin": "B0B2GHTL3X",
      "url": "https://www.amazon.co.jp/dp/B0B2GHTL3X"
    }
  ],
  "error_reasoning": null
}

Per-country failure mode (continues other countries):

{
  "country": "DE",
  "error": "currency_misconfigured",
  "detail": "After delivery-location setup, a-price-symbol still returned 'USD' — verify postal code applied (glow-ingress-line2 was still 'United States'). No price emitted for this country."
}

Other documented per-country error reasons:

  • "captcha" — Amazon CAPTCHA wall (rare with --verified --proxies; document if hit)
  • "no_results" — search returned zero matches in the storefront (e.g. product not sold there)
  • "only_amazon_device_results" — all top-N matches were Amazon Devices with no price; need a more specific query
  • "sponsored_only" — top-N were all sponsored 3rd-party items not matching the query
  • "location_modal_not_found" — couldn't find the button: Deliver to <X> ref (Amazon A/B test variant)

Full-flow failure:

{ "success": false, "query": "…", "results": [], "error_reasoning": "Session creation failed: …" }