Comparer les prix Amazon en Europe : écarts mesurés sur 5 pays

80 produits relevés sur amazon.de, .fr, .it, .es et .nl le 19 octobre 2026 : écart médian de 19 %, aucune boutique toujours moins chère. Méthode, tableaux et script Python de veille tarifaire.

Le même produit Amazon coûte en médiane 18,6 % de plus dans la boutique européenne la plus chère que dans la moins chère. Nous l’avons mesuré le 19 octobre 2026 : 35 produits neufs vendus par Amazon lui-même, chacun relevé sur amazon.de, .fr, .it, .es et .nl, TVA comprise. 71 % d’entre eux différaient de plus de 10 %, et aucune boutique ne gagnait de façon constante : l’Espagne, la France et l’Allemagne se sont relayées en bas du classement, les Pays-Bas étaient le plus souvent les plus chers. Le script Python qui a produit les chiffres se trouve à la fin.

De combien les prix Amazon diffèrent-ils entre les boutiques européennes ?

Par « écart », nous entendons ici le prix le plus élevé divisé par le prix le plus bas, moins 1, pour un même produit sur les boutiques où un prix était disponible. Nous l’avons calculé sur trois ensembles imbriqués parmi nos 80 produits de test :

Ensemble Produits Écart médian Au-dessus de 10 % Au-dessus de 25 %
Toutes les offres avec un prix valide en euros, 2 boutiques ou plus 80 18,6 % 58 (72 %) 29
Neuf, vendu par Amazon, 3 boutiques ou plus 35 18,6 % (moitié centrale de 5,4 % à 29,1 %) 25 (71 %) 10
Neuf, vendu par Amazon, prix relevé dans les 5 boutiques 19 19,4 % 11 (58 %) 6

Seuls 5 des 35 produits vendus par Amazon avaient le même prix partout. Le cas le plus extrême était un coffret Bosch de 52 outils à main : 69,99 € en Allemagne, en France et en Espagne, 96,95 € aux Pays-Bas, 105,98 € en Italie (51 %).

Une étude publiée sur DEV Community le 18 octobre 2026 par Atlas DataWorks rapporte une médiane de 29,3 % sur 86 produits tirés des meilleures ventes d’amazon.de, avec 73 produits sur 86 au-dessus de 10 % et l’Allemagne la moins chère 50 fois. Le sens est le même que chez nous, l’ampleur est plus faible, et l’Allemagne ne domine pas. Leurs produits viennent de la liste allemande des meilleures ventes, les nôtres de marques présentes dans les résultats de recherche d’au moins quatre boutiques : un écart différent n’a rien de surprenant. Considérez les deux comme des échantillons.

Quelle boutique Amazon est la moins chère ?

Aucune, de façon fiable. En ne comptant que les produits ayant une seule boutique la moins chère (égalités exclues), sur les 35 produits vendus par Amazon :

Boutique Moins chère pour Prix médian par rapport au plus bas du produit Produits avec un prix
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

L’Espagne n’a eu un prix que pour 23 des 35 produits (voir la couverture plus bas). Ce qui se confirme, ce sont les Pays-Bas, environ 15 % au-dessus du prix le plus bas en médiane. Exemple : le casque Sony WH-1000XM5 coûte 227,19 € en Allemagne, 269,99 € en France, 199,00 € en Italie et 239,00 € aux Pays-Bas.

Par catégorie, les appareils et consoles (Kindle, Nintendo, Garmin, Samsung, 11 produits) avaient un écart médian de 1,2 %. L’audio (JBL, casques Sony, 13 produits) 23,9 %, la maison et le bricolage (5) 23,7 %, les jouets (6) 17,9 %.

La TVA explique-t-elle la différence ?

À peine. Les taux normaux de TVA en 2026 sont de 19 % en Allemagne, 20 % en France, 21 % en Espagne et aux Pays-Bas, et 22 % en Italie (Tax Foundation, janvier 2026). La TVA seule peut expliquer au plus 2,5 % (Allemagne contre Italie). En divisant chaque prix par le taux de son pays, l’écart médian des 35 produits n’est passé que de 18,6 % à 18,4 %. Le reste vient de la tarification propre d’Amazon sur chaque marketplace.

Comment l’avons-nous mesuré ?

  1. Produits de départ. 16 requêtes de marques (Logitech, Anker, Lego, Kindle, Nintendo, Philips, Samsung, Bosch, Tefal, Oral-B, JBL, casques Sony, Playmobil, Braun, Garmin, livres de poche en anglais) lancées sur chacune des cinq boutiques : 80 recherches, 80 crédits. Nous avons gardé les ASIN présents dans les résultats d’au moins quatre boutiques et en avons tiré 80 au hasard, avec un plafond par requête (52 vus dans les cinq boutiques, 28 dans quatre).
  2. Prix. Une consultation produit par ASIN et par boutique : 400 consultations à 1 crédit chacune, avec le pays et le code postal définis pour chaque boutique.
  3. Nouvelles tentatives. 87 consultations n’avaient pas de prix au premier passage. Un second passage en a récupéré 50 (voir plus bas).
  4. Validation. Nous n’avons gardé un prix que s’il était en euros et que la chaîne affichée concordait au centime près avec extracted_price. Sur 400 consultations, aucune ne divergeait. Nous avons aussi lu les titres des huit plus gros écarts de l’ensemble vendu par Amazon : même modèle dans chaque langue.

Prix exploitables par boutique, sur 80 produits après la nouvelle tentative : Allemagne 78, France 79, Pays-Bas 77, Italie 67, Espagne 62. « Manquant » signifie que l’appel a échoué (422 target_unavailable, non facturé) ou que la page n’avait pas de prix de Buy Box. L’ensemble de l’exécution a utilisé environ 510 crédits le 19 octobre 2026 ; les consultations produit réussies ont pris une médiane de 9,2 secondes, p90 à 30 secondes.

Quels pièges quand on compare des marketplaces ?

  • Les paramètres de localisation comptent. Pour un même ASIN, amazon.fr, .it, .es et .co.uk appelés sans country ni postal_code ont renvoyé une page sans prix (localisation « United States »). Avec eux, nous avons obtenu des prix. amazon.nl fait exception : il répondait 400 à tout postal_code, donc n’envoyez que country=nl. La ville de livraison peut différer du code postal demandé (Milan 20121 est revenu comme « Figino 20153 »), alors lisez les prix comme « une adresse typique de ce pays ».
  • Les chaînes de prix ont quatre formes : €69.99 with 36 percent savings, 9,99 €, € 10,99 et 135,24 € con 32 un risparmio percentuale. Prenez le premier nombre, déterminez le séparateur décimal d’après le dernier séparateur, et refusez tout ce qui n’a pas le signe euro. Une page allemande a un jour renvoyé extracted_average_rating 47 pour « 4,7 », donc recoupez les nombres parsés.
  • amazon.co.uk est en livres sterling. Ça fonctionne (country gb plus un code postal a renvoyé un prix en livres), mais nous l’avons laissé de côté pour éviter les débats sur les taux de change.
  • « Vendu par » change la réponse. Les offres d’entrepôt et de vendeurs tiers (« Amazon Seconde main », revendeurs sur une seule boutique) ont produit nos plus gros écarts atypiques, donc les ensembles principaux ne gardent que les offres neuves vendues par Amazon.
  • Les échecs sont transitoires. 31 consultations italiennes sur 80 et 32 espagnoles sur 80 ont échoué avec un 422 au premier passage ; une nouvelle tentative en a récupéré 20 et 17. Réessayez, puis traitez le reste comme « non proposé ».

Comment lancer cette comparaison en Python ?

Le script prend des ASIN, interroge chacun sur cinq boutiques, ne garde que les prix en euros validés des offres vendues par Amazon, relance sur 422/429/5xx, et s’arrête à un plafond de crédits. Il utilise l’endpoint Amazon (resource=product, 1 crédit).

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 rejette postal_code : on n’y envoie que le pays
    "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  # s’arrêter avant le plafond, pas après
        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):  # les appels échoués sont gratuits
            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  # refuser tout ce qui n’est pas en 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):  # le dernier séparateur est la virgule décimale
        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  # les deux lectures divergent : on l’écarte plutôt que de deviner
    sold_by = page.get("sold_by") or ""
    return shown if sold_by.lower().startswith("amazon") else None  # uniquement vendu par Amazon


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})")

Exécuté en production le 19 octobre 2026 avec python price_compare.py B0DXKNBQS6 B0C3CRCMKJ (une enceinte JBL et le coffret d’outils Bosch) :

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)

Le tiret est réel : la consultation amazon.es de la JBL n’a renvoyé aucun prix exploitable lors de cette exécution. Deux produits sur cinq boutiques coûtent 9 crédits, donc une liste de suivi de 30 produits revient à environ 150 crédits par passage, soit à peu près 0,08 $ avec un pack Starter. Pour une tâche récurrente avec alertes, voir le bot de suivi de prix ; pour les champs produit, extraire les données produit d’Amazon ; si vous venez de la PA-API retirée, ce guide de migration.

Quelles sont les limites de ces données ?

  • Un seul jour. Tout a été récupéré le 19 octobre 2026. Les prix et les promotions bougent chaque jour ; une autre semaine donnerait un autre tableau.
  • Prix de la Buy Box, frais de livraison exclus. Les frais de port, les coupons et les offres réservées à Prime peuvent changer le prix réel. Les prix « avec 36 % de réduction » incluent la promotion en cours.
  • L’échantillon favorise les marques très diffusées. Il ne dit rien des produits de niche ou vendus localement, et un ASIN n’est pas toujours le même produit partout, d’où la vérification des titres.
  • Petit échantillon. 35 produits dans l’ensemble principal ; la moitié centrale va de 5 % à 29 %, donc lisez la médiane comme « autour de 19 % ».

En bref

Même ASIN, cinq boutiques Amazon européennes, un jour : un écart médian de 18,6 % entre la moins chère et la plus chère, supérieur à 10 % pour 71 % des produits vendus par Amazon, presque rien à voir avec la TVA. Les Pays-Bas étaient les plus chers en médiane ; la boutique la moins chère changeait d’un produit à l’autre. Envoyez country et postal_code pour chaque boutique (pas pour amazon.nl), validez chaque prix parsé, relancez les 422 et plafonnez vos crédits. Obtenez 500 crédits gratuits et lancez le script, ou lisez d’abord la documentation.