Amazon Preisvergleich Länder: 80 Produkte in 5 EU-Shops gemessen
Wir haben 80 Produkte auf amazon.de, .fr, .it, .es und .nl verglichen (19. Oktober 2026): Median-Abstand 18,6 %, kein Shop dauerhaft am günstigsten. Methode, Tabellen, Python für Preismonitoring.

Dasselbe Amazon-Produkt kostet im teuersten EU-Shop im Median 18,6 % mehr als im günstigsten. Wir haben das am 19. Oktober 2026 gemessen: 35 neue Produkte, die Amazon selbst verkauft, jeweils auf amazon.de, .fr, .it, .es und .nl bepreist, inklusive MwSt. Bei 71 % lag der Unterschied über 10 %, und kein Shop gewann durchgehend: Spanien, Frankreich und Deutschland wechselten sich am unteren Ende ab, die Niederlande waren meist am teuersten. Das Python-Skript, das die Zahlen erzeugt hat, steht am Ende.
Wie stark unterscheiden sich Amazon-Preise zwischen EU-Shops?
„Abstand” heißt hier: höchster Preis geteilt durch niedrigsten Preis, minus 1, für ein Produkt über alle Shops, in denen ein Preis vorlag. Wir haben ihn auf drei verschachtelten Mengen unserer 80 Testprodukte berechnet:
| Menge | Produkte | Median-Abstand | Über 10 % | Über 25 % |
|---|---|---|---|---|
| Jedes Angebot mit gültigem Europreis, 2+ Shops | 80 | 18,6 % | 58 (72 %) | 29 |
| Neu, von Amazon verkauft, 3+ Shops | 35 | 18,6 % (mittlere Hälfte 5,4 % bis 29,1 %) | 25 (71 %) | 10 |
| Neu, von Amazon verkauft, in allen 5 Shops bepreist | 19 | 19,4 % | 11 (58 %) | 6 |
Nur 5 der 35 von Amazon verkauften Produkte hatten überall denselben Preis. Der größte Ausreißer war ein 52-teiliges Handwerkzeug-Set von Bosch: 69,99 € in Deutschland, Frankreich und Spanien, 96,95 € in den Niederlanden, 105,98 € in Italien (51 %).
Eine Studie auf DEV Community vom 18. Oktober 2026 von Atlas DataWorks nennt einen Median von 29,3 % über 86 Produkte aus den Bestsellern von amazon.de, davon 73 von 86 über 10 % und Deutschland 50-mal am günstigsten. Die Richtung passt zu unserer, das Ausmaß ist bei uns kleiner, und Deutschland dominiert nicht. Deren Produkte stammen aus der deutschen Bestsellerliste, unsere aus Marken, die in den Suchergebnissen von mindestens vier Shops auftauchten, ein anderer Abstand überrascht also nicht. Behandle beide als Stichproben.
Welcher Amazon-Shop ist am günstigsten?
Keiner, zumindest nicht verlässlich. Gezählt werden nur Produkte mit genau einem günstigsten Shop (Gleichstände entfernt), bei den 35 von Amazon verkauften Produkten:
| Shop | Am günstigsten bei | Medianpreis im Vergleich zum Tiefstpreis des Produkts | Bepreiste Produkte |
|---|---|---|---|
| amazon.fr | 8 | +0,7 % | 35 |
| amazon.es | 7 | +0,0 % | 23 |
| amazon.de | 6 | +0,9 % | 34 |
| amazon.it | 4 | +1,0 % | 28 |
| amazon.nl | 2 | +14,6 % | 35 |
Spanien war nur für 23 der 35 bepreist (Abdeckung siehe unten). Das einzige stabile Muster sind die Niederlande, im Median etwa 15 % über dem Tiefstpreis. Ein Beispiel: Die Kopfhörer Sony WH-1000XM5 kosten 227,19 € in Deutschland, 269,99 € in Frankreich, 199,00 € in Italien und 239,00 € in den Niederlanden.
Nach Kategorie hatten Geräte und Konsolen (Kindle, Nintendo, Garmin, Samsung, 11 Produkte) einen Median-Abstand von 1,2 %. Audio (JBL, Sony-Kopfhörer, 13 Produkte) lag bei 23,9 %, Haus und Werkzeug (5) bei 23,7 %, Spielzeug (6) bei 17,9 %.
Erklärt die MwSt den Unterschied?
Kaum. Die Regelsätze der MwSt liegen 2026 bei 19 % in Deutschland, 20 % in Frankreich, 21 % in Spanien und den Niederlanden und 22 % in Italien (Tax Foundation, Januar 2026). Die MwSt allein kann höchstens 2,5 % erklären (Deutschland gegen Italien). Teilt man jeden Preis durch den Satz seines Landes, sank der Median-Abstand der 35 Produkte nur von 18,6 % auf 18,4 %. Der Rest ist Amazons eigene Preisgestaltung pro Marktplatz.
Wie haben wir gemessen?
- Ausgangsmenge. 16 Marken-Suchanfragen (Logitech, Anker, Lego, Kindle, Nintendo, Philips, Samsung, Bosch, Tefal, Oral-B, JBL, Sony-Kopfhörer, Playmobil, Braun, Garmin, englische Taschenbücher), auf jedem der fünf Shops gesucht: 80 Suchen, 80 Credits. Wir haben ASINs behalten, die in den Ergebnissen von mindestens vier Shops vorkamen, und 80 davon zufällig gezogen, pro Suchanfrage begrenzt (52 in allen fünf Shops gesehen, 28 in vier).
- Preise. Eine Produktabfrage pro ASIN und Shop: 400 Abfragen zu je 1 Credit, mit
countryundpostal_codepro Shop gesetzt. - Wiederholungen. Bei 87 Abfragen fehlte im ersten Durchgang der Preis. Ein zweiter Durchgang holte 50 davon zurück (siehe unten).
- Validierung. Einen Preis behielten wir nur, wenn er in Euro war und der angezeigte String auf den Cent mit
extracted_priceübereinstimmte. Von 400 Abfragen wich keine ab. Außerdem haben wir die Titel der acht größten Abstände in der Menge der von Amazon verkauften Produkte gelesen: in jeder Sprache dasselbe Modell.
Brauchbare Preise pro Shop, von 80 Produkten nach der Wiederholung: Deutschland 78, Frankreich 79, Niederlande 77, Italien 67, Spanien 62. „Fehlt” heißt, der Aufruf ist gescheitert (422 target_unavailable, wird nicht berechnet) oder die Seite hatte keinen Buy-Box-Preis. Der gesamte Lauf brauchte am 19. Oktober 2026 rund 510 Credits; erfolgreiche Produktabfragen dauerten im Median 9,2 Sekunden, p90 bei 30 Sekunden.
Was geht beim Vergleich von Marktplätzen schief?
- Locale-Parameter zählen. Für eine ASIN lieferten amazon.fr, .it, .es und .co.uk ohne
countryundpostal_codeeine Seite ohne Preis (Standort „United States”). Mit den Parametern kamen Preise. amazon.nl ist die Ausnahme: Dort antwortete jedepostal_codemit400, schick also nurcountry=nl. Die Lieferstadt kann von der angefragten Postleitzahl abweichen (Mailand 20121 kam als „Figino 20153” zurück), lies Preise also als „eine typische Adresse in diesem Land”. - Preis-Strings haben vier Formen:
€69.99 with 36 percent savings,9,99 €,€ 10,99und135,24 € con 32 un risparmio percentuale. Nimm die erste Zahl, bestimme das Dezimalzeichen am letzten Trennzeichen und lehne alles ohne Eurozeichen ab. Eine deutsche Seite lieferte einmalextracted_average_rating47 für „4,7”, prüf geparste Zahlen also gegen. - amazon.co.uk ist in GBP. Es funktioniert (
countrygbplus Postleitzahl lieferte einen Pfundpreis), wir haben es aber weggelassen, um Wechselkurs-Diskussionen zu vermeiden. - „Verkauft von” ändert das Ergebnis. Warehouse- und Drittanbieter-Angebote („Amazon Seconde main”, Händler in einem einzelnen Shop) erzeugten unsere größten Ausreißer, deshalb enthalten die Hauptmengen nur neue Angebote, die Amazon selbst verkauft.
- Fehler sind vorübergehend. 31 von 80 italienischen und 32 von 80 spanischen Abfragen im ersten Durchgang scheiterten mit 422; eine Wiederholung holte 20 und 17 zurück. Wiederhole, und behandle den Rest als „nicht angeboten”.
Wie führe ich diesen Vergleich in Python aus?
Das Skript nimmt ASINs, ruft jede auf fünf Shops ab, behält nur validierte Europreise von Amazon-Angeboten, wiederholt 422/429/5xx und stoppt an einer Credit-Obergrenze. Es nutzt den Amazon-Endpoint (resource=product, 1 Credit).
import os, re, statistics, sys, threading, time
from concurrent.futures import ThreadPoolExecutor
import requests
API = "https://api.fastaf.co/v1/amazon"
HEADERS = {"Authorization": f"Bearer {os.environ['FASTAF_API_KEY']}"}
CREDIT_CAP = int(os.environ.get("CREDIT_CAP", 200))
WORKERS = int(os.environ.get("WORKERS", 5))
STORES = { # amazon.nl rejects postal_code, so there only the country is sent
"de": {"domain": "de", "country": "de", "postal_code": "10115"},
"fr": {"domain": "fr", "country": "fr", "postal_code": "75001"},
"it": {"domain": "it", "country": "it", "postal_code": "20121"},
"es": {"domain": "es", "country": "es", "postal_code": "28013"},
"nl": {"domain": "nl", "country": "nl"},
}
spent, lock = 0, threading.Lock()
def fetch(asin, store):
global spent
params = {"resource": "product", "asin": asin, **STORES[store]}
for attempt in range(4):
with lock:
if spent >= CREDIT_CAP:
return None # stop before the cap, not after
r = requests.get(API, params=params, headers=HEADERS, timeout=120)
with lock:
spent += int(r.headers.get("X-FastAF-Credits-Used", 0))
if r.status_code == 200:
return r.json()
if r.status_code in (422, 429, 500, 502, 503, 504): # failed calls are free
time.sleep(3 * (attempt + 1))
continue
return None
return None
def parse_eur(text):
"""'€69.99 with 36 percent savings', '9,99 €', '€ 1.299,00' -> float."""
if not text or "€" not in text:
return None # refuse anything that is not euros
m = re.search(r"\d[\d.,\s ]*\d|\d", text)
s = re.sub(r"[\s ]", "", m.group())
cut = max(s.rfind(","), s.rfind("."))
if cut != -1 and len(s) - cut - 1 in (1, 2): # last separator = decimal mark
return float(re.sub(r"[.,]", "", s[:cut]) + "." + s[cut + 1:])
return float(re.sub(r"[.,]", "", s))
def price(page):
if not page or not page.get("price"):
return None
shown, extracted = parse_eur(page["price"]), page.get("extracted_price")
if shown is None or extracted is None or abs(shown - extracted) > 0.011:
return None # the two parses disagree: drop it rather than guess
sold_by = page.get("sold_by") or ""
return shown if sold_by.lower().startswith("amazon") else None # Amazon-sold only
asins = sys.argv[1:]
jobs = [(a, s) for a in asins for s in STORES]
with ThreadPoolExecutor(WORKERS) as pool:
prices = dict(zip(jobs, pool.map(lambda j: price(fetch(*j)), jobs)))
spreads, wins = [], dict.fromkeys(STORES, 0)
print("asin " + "".join(f"{s:>9}" for s in STORES) + " spread")
for a in asins:
row = {s: prices[(a, s)] for s in STORES if prices[(a, s)]}
spread = max(row.values()) / min(row.values()) - 1 if len(row) > 1 else None
if spread is not None:
spreads.append(spread)
low = [s for s, p in row.items() if p == min(row.values())]
if len(low) == 1:
wins[low[0]] += 1
cells = "".join(f"{row[s]:9.2f}" if s in row else f"{'-':>9}" for s in STORES)
print(f"{a} {cells} " + (f"{spread:6.1%}" if spread is not None else " n/a"))
if spreads:
print(f"\nmedian spread {statistics.median(spreads):.1%} over {len(spreads)} products")
print("cheapest store:", wins)
print(f"credits used: {spent} (cap {CREDIT_CAP})")
Am 19. Oktober 2026 gegen Production gelaufen mit python price_compare.py B0DXKNBQS6 B0C3CRCMKJ (ein JBL-Lautsprecher und das Bosch-Werkzeugset):
asin de fr it es nl spread
B0DXKNBQS6 127.99 140.82 135.24 - 150.00 17.2%
B0C3CRCMKJ 69.99 69.99 105.98 69.99 96.95 51.4%
median spread 34.3% over 2 products
cheapest store: {'de': 1, 'fr': 0, 'it': 0, 'es': 0, 'nl': 0}
credits used: 9 (cap 12)
Der Strich ist echt: Die Abfrage des JBL auf amazon.es lieferte in diesem Lauf keinen brauchbaren Preis. Zwei Produkte auf fünf Shops kosten 9 Credits, eine Watchlist mit 30 Produkten also etwa 150 Credits pro Prüfung, rund 8 US-Cent mit einem Starter-Paket. Für einen wiederkehrenden Job mit Alarmen siehe den Preis-Tracking-Bot für Preismonitoring; zu den Produktfeldern Amazon-Produktdaten auslesen; wenn du von der eingestellten PA-API kommst, diesen Migrationsguide.
Wo liegen die Grenzen dieser Daten?
- Ein Tag. Alles wurde am 19. Oktober 2026 abgerufen. Preise und Aktionen ändern sich täglich; eine andere Woche würde eine andere Tabelle liefern.
- Buy-Box-Preis, ohne Versand. Lieferkosten, Coupons und Prime-Angebote können den echten Preis verändern. Preise mit „with 36 percent savings” enthalten die aktuelle Aktion.
- Die Stichprobe bevorzugt weit verbreitete Marken. Sie sagt nichts über Nischenprodukte oder rein lokale Produkte, und eine ASIN ist nicht überall dasselbe Produkt, weshalb wir die Titel geprüft haben.
- Kleine Stichprobe. 35 Produkte in der Hauptmenge; die mittlere Hälfte reicht von 5 % bis 29 %, lies den Median also als „rund 19 %“.
Kurz gesagt
Dieselbe ASIN, fünf EU-Amazon-Shops, ein Tag: ein Median-Abstand von 18,6 % zwischen günstigstem und teuerstem Shop, bei 71 % der von Amazon verkauften Produkte über 10 %, fast nichts davon MwSt. Die Niederlande waren im Median am teuersten; der günstigste Shop wechselte von Produkt zu Produkt. Schick country und postal_code pro Shop (nicht bei amazon.nl), validiere jeden geparsten Preis, wiederhole die 422er und begrenze deine Credits. Hol dir 500 kostenlose Credits und führ das Skript aus, oder lies zuerst die Docs.