Le point de terminaison /products.json de Shopify est l’un des secrets les moins bien gardés du e-commerce en matière de données. Ajoutez-le à n’importe quelle URL de boutique Shopify et vous récupérez un JSON structuré — sans clé API, sans authentification, sans avoir à naviguer dans du HTML imbriqué.
Je travaille au sein de l’équipe du , donc je passe beaucoup de temps à réfléchir à la façon dont les gens extraient des données du web. Et l’extraction de données Shopify revient sans cesse : équipes commerciales qui suivent les prix des concurrents, opérations e-commerce qui comparent les catalogues produits, acheteurs qui cherchent de nouveaux fournisseurs. Avec sur Shopify et une plateforme qui représente environ , le volume de données produits exploitables est énorme.
Ce guide couvre l’ensemble du processus : ce que renvoie l’endpoint, comment parcourir des milliers de produits page par page, comment gérer les limites de requêtes sans vous faire bloquer, et comment aplatir le JSON imbriqué de Shopify en un fichier CSV ou Excel propre avec pandas. Je couvrirai aussi des endpoints dont presque personne ne parle (/collections.json, /meta.json) et je présenterai une alternative sans code pour ceux qui préfèrent éviter Python.
Qu’est-ce que l’endpoint /products.json de Shopify (et pourquoi il simplifie l’extraction de données)
Chaque boutique Shopify dispose d’un endpoint public à {store-url}/products.json qui renvoie des données produits structurées. Pas de clé API. Pas d’OAuth. Pas d’authentification de quelque nature que ce soit. Il suffit littéralement d’ajouter /products.json à l’URL de la boutique pour obtenir un tableau JSON de tous les produits du catalogue.
Essayez par vous-même : ouvrez ou dans votre navigateur. Vous verrez un JSON clair et structuré avec les titres produits, les prix, les variantes, les images, les tags — tout.
Comparez cela à l’autre approche : analyser les thèmes HTML de Shopify, profondément imbriqués, incohérents d’une boutique à l’autre et modifiés dès qu’un marchand change son thème. Voilà à quoi vous seriez confronté :
Approche HTML (pénible) :
1<div class="product-card__info">
2 <h3 class="product-card__title">
3 <a href="/products/classic-blue-jeans">Classic Blue Jeans</a>
4 </h3>
5 <span class="price price--on-sale" data-product-price>$149.00</span>
6</div>
Approche JSON (propre) :
1{
2 "title": "Classic Blue Jeans",
3 "handle": "classic-blue-jeans",
4 "vendor": "Hiut Denim",
5 "variants": [{"price": "149.00", "sku": "HD-BLU-32", "available": true}]
6}
Le JSON l’emporte sur la cohérence, la fiabilité et la facilité d’analyse. L’endpoint prend aussi en charge deux paramètres clés — ?limit= (jusqu’à 250 produits par page, 30 par défaut) et ?page= pour la pagination — que nous utiliserons abondamment dans le code plus bas.
Point important : il s’agit d’un endpoint public de la boutique, pas de l’. L’API Admin exige des jetons d’accès du propriétaire de la boutique et fournit les commandes, les niveaux de stock et les informations clients. L’endpoint public /products.json donne uniquement des données produits en lecture seule, accessibles à tous. Je détaillerai cette distinction plus loin, car la confusion à ce sujet est très répandue sur les forums.
Réserve à garder en tête : toutes les boutiques Shopify n’exposent pas cet endpoint. Dans mes tests, environ 71 % des boutiques renvoient un JSON valide (allbirds.com, gymshark.com, colourpop.com, kyliecosmetics.com fonctionnent toutes), tandis que certaines configurations personnalisées renvoient une erreur 404 (hiutdenim.co.uk, bombas.com). Le test rapide est simple : rendez-vous sur {store-url}/products.json dans votre navigateur et voyez ce qui s’affiche.
Pourquoi extraire Shopify avec Python ? Principaux cas d’usage métier
Pourquoi s’y intéresser ? Pour le retour sur investissement. utilisent désormais l’extraction automatisée des prix pour la veille concurrentielle, contre seulement 34 % en 2020. Et les études montrent qu’une . Ces données valent donc vraiment de l’argent.
Voici les cas d’usage les plus courants que je rencontre :
| Cas d’usage | Qui en bénéficie | Ce que vous obtenez |
|---|---|---|
| Surveillance des prix concurrents | Équipes opérations e-commerce | Suivi des variations de prix, remises et prix barrés dans les catalogues concurrents |
| Recherche produit et sourcing | Achats / merchandising | Comparaison des caractéristiques, variantes, matières et disponibilité des produits |
| Génération de leads | Équipes commerciales | Extraction des noms de fournisseurs, données de marque et coordonnées depuis les catalogues |
| Analyse marché et catégorie | Équipes marketing | Compréhension du mix produit, des tags, de la structure des collections et du positionnement |
| Suivi des stocks et de la disponibilité | Équipes supply chain | Suivi de la disponibilité au niveau des variantes (available: true/false) dans le temps |
| Détection de nouveaux produits | Équipes produit | Suivi des horodatages created_at pour repérer les nouveaux lancements des concurrents |
Python est naturellement adapté à ce type de travail. utilisent Python comme langage principal, et son écosystème — requests pour le HTTP, pandas pour la manipulation de données, httpx pour l’asynchrone — permet de passer de « j’ai une URL » à « j’ai un tableur » en moins de 80 lignes de code.
Référence complète des champs products.json : explication de chaque champ
Tous les tutoriels concurrents vous montrent title, id et handle, puis passent à autre chose. Pourtant, la réponse JSON de Shopify contient plus de 40 champs répartis entre produits, variantes, images et options. Savoir ce qui est disponible avant d’écrire votre script vous évite de devoir réextraire les données plus tard.
J’ai établi cette référence à partir de réponses /products.json en production récupérées le 16 avril 2026. La structure est cohérente sur toutes les boutiques qui exposent l’endpoint.
Champs au niveau produit
| Champ | Type de données | Valeur d’exemple | Cas d’usage métier |
|---|---|---|---|
id | Entier | 123456789 | Identifiant unique du produit pour la déduplication |
title | Chaîne | "Classic Blue Jeans" | Nom du produit pour les catalogues et les comparaisons |
handle | Chaîne | "classic-blue-jeans" | Slug d’URL — construisez les liens produit comme {store}/products/{handle} |
body_html | Chaîne (HTML) ou null | Our best-selling... | Description produit pour l’analyse de contenu et la recherche SEO |
vendor | Chaîne | "Hiut Denim" | Nom de la marque / du fournisseur pour la génération de leads ou le sourcing |
product_type | Chaîne | "Jeans" | Classification de catégorie pour l’analyse de marché |
created_at | DateTime ISO | "2024-01-15T10:30:00-05:00" | Suivi de la date d’ajout des produits (détection des nouveaux lancements) |
updated_at | DateTime ISO | "2025-03-01T08:00:00-05:00" | Détection des changements récents du catalogue |
published_at | DateTime ISO | "2024-01-16T00:00:00-05:00" | Date de mise en ligne du produit sur la boutique |
tags | Tableau de chaînes | ["organic", "women", "straight-leg"] | Analyse de mots-clés / tags pour le SEO, la catégorisation et la détection de tendances |
variants | Tableau d’objets | (voir les champs des variantes ci-dessous) | Prix, SKU, disponibilité par variante |
images | Tableau d’objets | (voir les champs des images ci-dessous) | URL des images produit pour les catalogues et l’analyse visuelle |
options | Tableau d’objets | [{"name": "Size", "values": ["S","M","L"]}] | Comprendre la configuration du produit (taille, couleur, matière) |
Champs au niveau variante (imbriqués sous chaque produit)
| Champ | Type de données | Exemple | Cas d’usage |
|---|---|---|---|
id | Entier | 987654321 | Identifiant unique de la variante |
title | Chaîne | "32 / Blue" | Nom affiché de la variante |
sku | Chaîne | "HD-BLU-32" | Correspondance SKU pour les systèmes de stock |
price | Chaîne | "185.00" | Suivi des prix (attention : c’est une chaîne, il faut la convertir en float pour les calculs) |
compare_at_price | Chaîne ou null | "200.00" | Prix d’origine — essentiel pour suivre les remises |
available | Booléen | true | Disponibilité du stock (le seul indicateur public de stock) |
weight | Flottant | 1.2 | Analyse logistique et expédition |
option1, option2, option3 | Chaîne | "32", "Blue", null | Valeurs des options individuelles |
created_at, updated_at | DateTime ISO | — | Suivi des changements au niveau variante |
Champs au niveau image
| Champ | Type de données | Exemple | Cas d’usage |
|---|---|---|---|
id | Entier | 111222333 | Identifiant unique de l’image |
src | Chaîne (URL) | "https://cdn.shopify.com/..." | Lien direct de téléchargement de l’image |
alt | Chaîne ou null | "Front view of jeans" | Texte alternatif de l’image pour l’analyse d’accessibilité |
position | Entier | 1 | Ordre d’affichage des images |
width, height | Entier | 2048, 2048 | Dimensions de l’image |
Ce qui n’est PAS dans l’endpoint public
Point de vigilance important : inventory_quantity n’est PAS disponible dans les réponses publiques /products.json. Ce champ a été retiré des endpoints JSON publics en décembre 2017 pour des raisons de sécurité. Le seul indicateur de stock que vous obtenez est le champ booléen available sur chaque variante (true ou false). Pour accéder aux quantités réelles en stock, il faut l’API Admin authentifiée avec les identifiants du propriétaire de la boutique.
Avant d’écrire votre script, parcourez ce tableau et décidez quels champs sont utiles à votre cas d’usage. Si vous faites du suivi des prix, vous aurez besoin de variants[].price, variants[].compare_at_price et variants[].available. Si vous faites de la génération de leads, concentrez-vous sur vendor, product_type et tags. Filtrez en conséquence — votre CSV sera bien plus propre.
Au-delà de products.json : collections, meta et autres endpoints Shopify
Aucun tutoriel concurrent ne mentionne ces endpoints. Ils sont pourtant essentiels pour une vraie veille concurrentielle.
/collections.json — Toutes les catégories de la boutique
Renvoie toutes les collections (catégories) de la boutique avec les titres, handles, descriptions et nombres de produits. J’ai vérifié cela sur zoologistperfumes.com, allbirds.com et gymshark.com : les trois renvoyaient un JSON valide.
1{
2 "collections": [
3 {
4 "id": 308387348539,
5 "title": "Attars",
6 "handle": "attars",
7 "published_at": "2026-03-29T12:20:32-04:00",
8 "products_count": 1,
9 "image": { "src": "https://cdn.shopify.com/..." }
10 }
11 ]
12}
Vous voulez comprendre comment un concurrent structure son catalogue ? C’est cet endpoint qu’il faut consulter.
/collections/{handle}/products.json — Produits par catégorie
Renvoie les produits filtrés par une collection précise. Même structure JSON que /products.json, mais limitée à une seule catégorie. C’est essentiel pour l’extraction au niveau catégorie — par exemple si vous ne voulez suivre que la collection « Sale » ou « New Arrivals » d’un concurrent.
/meta.json — Métadonnées de la boutique
Renvoie le nom de la boutique, sa description, sa devise, son pays et — le plus intéressant — published_products_count. Ce compteur permet de calculer à l’avance le nombre exact de pages de pagination nécessaires : ceil(published_products_count / 250). Plus besoin d’incrémenter les pages à l’aveugle jusqu’à obtenir une réponse vide.
Quel endpoint devez-vous utiliser ?
| Ce que vous voulez | Endpoint | Authentification requise ? |
|---|---|---|
| Tous les produits (public) | /products.json | Non |
| Produits d’une catégorie précise | /collections/{handle}/products.json | Non |
| Métadonnées de la boutique + nombre de produits | /meta.json | Non |
| Toutes les collections (catégories) | /collections.json | Non |
| Données de commandes/ventes (votre propre boutique uniquement) | API Admin /orders.json | Oui (clé API) |
| Quantités de stock (votre propre boutique uniquement) | API Admin /inventory_levels.json | Oui |
La question qui revient sans cesse sur les forums — « Puis-je savoir combien d’unités un concurrent a vendues ? » — a une réponse courte : non. Pas via les endpoints publics. Les données de ventes et les quantités de stock nécessitent l’API Admin authentifiée, ce qui implique un accès propriétaire à la boutique. Les endpoints publics ne donnent que les données du catalogue produit.

Comment extraire Shopify avec Python : configuration pas à pas
- Niveau de difficulté : Débutant
- Temps nécessaire : ~15 minutes (installation + première extraction)
- Ce qu’il vous faut : Python 3.11+,
pip, un terminal et une URL de boutique Shopify à extraire
Étape 1 : installer Python et les bibliothèques requises
Assurez-vous d’avoir Python 3.11 ou plus récent installé (pandas 3.0.x l’exige). Installez ensuite les deux bibliothèques nécessaires :
1pip install requests pandas
Pour l’export Excel, installez aussi :
1pip install openpyxl
En haut de votre script, ajoutez ces imports :
1import requests
2import pandas as pd
3import time
4import random
5import json
Vous ne devriez avoir aucune erreur d’import lors de l’exécution du script. Si pandas renvoie une erreur de version, mettez Python à jour vers la version 3.12.
Étape 2 : récupérer les données produits depuis /products.json
Voici une fonction de base qui prend une URL de boutique, appelle l’endpoint et renvoie le JSON analysé :
1def fetch_products_page(store_url, page=1, limit=250):
2 """Récupère une page de produits depuis une boutique Shopify."""
3 url = f"{store_url.rstrip('/')}/products.json"
4 params = {"limit": limit, "page": page}
5 headers = {
6 "User-Agent": "Mozilla/5.0 (compatible; ProductResearch/1.0)"
7 }
8 response = requests.get(url, params=params, headers=headers, timeout=30)
9 response.raise_for_status()
10 return response.json().get("products", [])
Détails importants :
limit=250correspond au maximum autorisé par Shopify par page. La valeur par défaut est 30, donc le régler explicitement réduit vos requêtes totales jusqu’à 8 fois.- En-tête
User-Agent: définissez toujours une valeur réaliste. Les requêtes sans User-Agent ont plus de risques de déclencher les systèmes anti-bot de Shopify. timeout=30: évitez qu’une requête bloque indéfiniment.
Testez avec une boutique connue :
1products = fetch_products_page("https://allbirds.com")
2print(f"Fetched {len(products)} products")
3print(f"First product: {products[0]['title']}")
Vous devriez obtenir quelque chose comme : Fetched 250 products puis le titre du premier produit.
Étape 3 : gérer la pagination pour extraire tous les produits
Une seule requête renvoie au maximum 250 produits. La plupart des boutiques en ont plus que cela (Allbirds en a plus de 1 420). Vous devez donc parcourir les pages jusqu’à obtenir une réponse vide.
1def scrape_all_products(store_url, delay=1.0):
2 """Extrait tous les produits d’une boutique Shopify en gérant la pagination."""
3 all_products = []
4 page = 1
5 while True:
6 print(f"Fetching page {page}...")
7 products = fetch_products_page(store_url, page=page, limit=250)
8 if not products:
9 print(f"No more products. Total: {len(all_products)}")
10 break
11 all_products.extend(products)
12 print(f" Got {len(products)} products (total so far: {len(all_products)})")
13 page += 1
14 # Restez courtois : attendez entre les requêtes
15 time.sleep(delay + random.uniform(0, 0.5))
16 return all_products
Quand products revient vide, vous avez atteint la fin.
Le time.sleep() avec un petit aléa permet de rester sous la limite informelle de Shopify (~2 requêtes/seconde).
Astuce : si vous avez d’abord récupéré /meta.json, vous connaissez déjà le nombre total de produits et pouvez calculer exactement le nombre de pages nécessaires : pages = ceil(product_count / 250). Cela évite la « requête vide supplémentaire » à la fin.
Étape 4 : analyser et sélectionner les champs nécessaires
Maintenant que vous avez tous les produits sous forme de liste de dictionnaires Python, extrayez uniquement les champs qui vous intéressent. Voici un exemple qui récupère les champs les plus courants pour le suivi des prix :
1def extract_product_data(products):
2 """Extrait les champs clés des produits et aplatit les variantes."""
3 rows = []
4 for product in products:
5 for variant in product.get("variants", []):
6 rows.append({
7 "product_id": product["id"],
8 "title": product["title"],
9 "handle": product["handle"],
10 "vendor": product.get("vendor", ""),
11 "product_type": product.get("product_type", ""),
12 "tags": ", ".join(product.get("tags", [])),
13 "created_at": product.get("created_at", ""),
14 "variant_id": variant["id"],
15 "variant_title": variant.get("title", ""),
16 "sku": variant.get("sku", ""),
17 "price": variant.get("price", ""),
18 "compare_at_price": variant.get("compare_at_price", ""),
19 "available": variant.get("available", ""),
20 "image_url": product["images"][0]["src"] if product.get("images") else ""
21 })
22 return rows
Cela crée une ligne par variante — le format le plus utile pour la comparaison de prix, puisqu’un produit comme « Classic Blue Jeans » peut avoir 12 variantes (6 tailles × 2 couleurs), chacune avec son propre prix et son propre état de disponibilité.
Exporter les données Shopify extraites en CSV et Excel avec pandas
Tous les autres tutoriels sur Shopify se contentent d’écrire le JSON brut dans un fichier. C’est bien pour les développeurs. Beaucoup moins utile pour l’analyste e-commerce qui a besoin d’un tableur avant vendredi.
Le problème : le JSON de Shopify est imbriqué. Un produit peut contenir une douzaine de variantes, chacune avec son prix, son SKU et sa disponibilité. Aplatir cela en lignes et colonnes demande un peu de travail avec pandas.
Aplatir un JSON imbriqué en tableau propre
Il existe deux approches, selon votre cas d’usage :
Option A : une ligne par variante (idéal pour le suivi des prix et des stocks)
1# En utilisant la fonction extract_product_data de l’étape 4
2products = scrape_all_products("https://allbirds.com")
3rows = extract_product_data(products)
4df = pd.DataFrame(rows)
5print(f"DataFrame shape: {df.shape}")
6print(df.head())
Vous obtenez ainsi un tableau plat où chaque ligne correspond à une combinaison produit-variante unique. Une boutique avec 500 produits et une moyenne de 4 variantes par produit donnera un DataFrame d’environ 2 000 lignes.
Option B : une ligne par produit résumé (idéal pour une vue d’ensemble du catalogue)
1def summarize_products(products):
2 """Une ligne par produit avec le prix min/max parmi les variantes."""
3 rows = []
4 for product in products:
5 prices = [float(v["price"]) for v in product.get("variants", []) if v.get("price")]
6 rows.append({
7 "product_id": product["id"],
8 "title": product["title"],
9 "vendor": product.get("vendor", ""),
10 "product_type": product.get("product_type", ""),
11 "variant_count": len(product.get("variants", [])),
12 "min_price": min(prices) if prices else None,
13 "max_price": max(prices) if prices else None,
14 "any_available": any(v.get("available", False) for v in product.get("variants", [])),
15 "tags": ", ".join(product.get("tags", []))
16 })
17 return rows
Exporter vers CSV, Excel et Google Sheets
1# Export CSV (utilisez utf-8-sig pour qu’Excel gère correctement les caractères spéciaux)
2df.to_csv("shopify_products.csv", index=False, encoding="utf-8-sig")
3# Export Excel (nécessite openpyxl)
4df.to_excel("shopify_products.xlsx", index=False, engine="openpyxl")
5print("Exported to shopify_products.csv and shopify_products.xlsx")
Pour Google Sheets, vous pouvez utiliser la bibliothèque gspread avec un compte de service, mais honnêtement — pour la plupart des cas d’usage, exporter en CSV puis l’importer dans Google Drive est plus rapide et plus simple.
Extraction Shopify prête pour la production : limites, retries et anti-blocage
Le script de base fonctionne bien pour les petites boutiques. Extraire une boutique de plus de 5 000 produits, ou enchaîner plusieurs boutiques ? C’est là que les problèmes commencent.
Comprendre les limites de Shopify et son comportement de blocage
Les endpoints JSON publics de Shopify n’ont pas de limites de requêtes officiellement documentées (contrairement au modèle de type « leaky bucket » de l’API Admin), mais les tests empiriques montrent :
- Rythme sûr : environ 2 requêtes par seconde et par boutique
- Plafond souple : environ 40 requêtes par minute avant le déclenchement d’un throttling
- HTTP 429 : « Too Many Requests » — la réponse standard en cas de limite dépassée
- HTTP 430 : code spécifique à Shopify indiquant un blocage de sécurité (pas seulement une limitation de débit)
- HTTP 403 ou redirection CAPTCHA : certaines boutiques protégées en plus par Cloudflare
Les requêtes issues d’infrastructures cloud partagées (AWS Lambda, Google Cloud Run) ont particulièrement tendance à être bloquées, car ces plages d’IP sont associées à de nombreux abus.
Techniques pour extraire Shopify de manière fiable
Voici l’évolution de « ça marche sur mon ordinateur » à « c’est prêt pour la production » :
| Niveau | Technique | Fiabilité |
|---|---|---|
| Basique | requests.get() + ?page= | Casse sur les gros catalogues, risque de blocage |
| Intermédiaire | requests.Session() + ?limit=250 + time.sleep(1) + retry sur 429 | Fonctionne pour la plupart des boutiques |
| Avancé | httpx asynchrone + rotation du User-Agent + backoff exponentiel | Niveau production, jusqu’à 10 000+ produits |
Niveau intermédiaire (recommandé pour la plupart des utilisateurs) :
1import requests
2from requests.adapters import HTTPAdapter
3from urllib3.util.retry import Retry
4def create_session():
5 """Crée une session requests avec logique de retry automatique."""
6 session = requests.Session()
7 retries = Retry(
8 total=5,
9 backoff_factor=1, # sommeil : 0,5 s, 1 s, 2 s, 4 s, 8 s
10 status_forcelist=[429, 430, 500, 502, 503, 504],
11 respect_retry_after_header=True
12 )
13 session.mount("https://", HTTPAdapter(max_retries=retries))
14 session.headers.update({
15 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
16 })
17 return session
La configuration Retry gère automatiquement les réponses 429 avec un backoff exponentiel. Le backoff_factor=1 signifie que la séquence de pause est 0,5 s → 1 s → 2 s → 4 s → 8 s entre les tentatives. La réutilisation de session (requests.Session()) apporte aussi du pooling de connexions, ce qui réduit les coûts quand vous envoyez plusieurs requêtes au même domaine.
Rotation du User-Agent : si vous extrayez plusieurs boutiques, faites tourner entre 3 et 5 chaînes User-Agent réalistes de navigateur. Il ne s’agit pas de tromper le site, mais d’éviter de ressembler à un bot qui envoie les mêmes en-têtes à chaque requête.
Script Python complet pour extraire Shopify avec export CSV
Voici le script complet, prêt à copier-coller, qui rassemble tout ce qui précède. Il fait environ 75 lignes de vrai code (hors commentaires), et je l’ai testé sur Allbirds (1 420 produits), ColourPop (plus de 2 000 produits) et Zoologist Perfumes (petit catalogue).
1import requests
2import pandas as pd
3import time
4import random
5from requests.adapters import HTTPAdapter
6from urllib3.util.retry import Retry
7def create_session():
8 """Crée une session avec logique de retry pour les limites de requêtes."""
9 session = requests.Session()
10 retries = Retry(
11 total=5,
12 backoff_factor=1,
13 status_forcelist=[429, 430, 500, 502, 503, 504],
14 respect_retry_after_header=True
15 )
16 session.mount("https://", HTTPAdapter(max_retries=retries))
17 session.headers.update({
18 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
19 "AppleWebKit/537.36 (KHTML, like Gecko) "
20 "Chrome/125.0.0.0 Safari/537.36"
21 })
22 return session
23def scrape_shopify(store_url, delay=1.0):
24 """Extrait tous les produits d’une boutique Shopify via /products.json."""
25 session = create_session()
26 all_products = []
27 page = 1
28 base_url = f"{store_url.rstrip('/')}/products.json"
29 while True:
30 print(f" Page {page}...", end=" ")
31 resp = session.get(base_url, params={"limit": 250, "page": page}, timeout=30)
32 resp.raise_for_status()
33 products = resp.json().get("products", [])
34 if not products:
35 break
36 all_products.extend(products)
37 print(f"{len(products)} products (total: {len(all_products)})")
38 page += 1
39 time.sleep(delay + random.uniform(0, 0.5))
40 return all_products
41def flatten_to_variants(products):
42 """Aplati le JSON produit imbriqué en une ligne par variante."""
43 rows = []
44 for p in products:
45 base = {
46 "product_id": p["id"],
47 "title": p["title"],
48 "handle": p["handle"],
49 "vendor": p.get("vendor", ""),
50 "product_type": p.get("product_type", ""),
51 "tags": ", ".join(p.get("tags", [])),
52 "created_at": p.get("created_at", ""),
53 "updated_at": p.get("updated_at", ""),
54 "image_url": p["images"][0]["src"] if p.get("images") else "",
55 }
56 for v in p.get("variants", []):
57 row = {**base}
58 row["variant_id"] = v["id"]
59 row["variant_title"] = v.get("title", "")
60 row["sku"] = v.get("sku", "")
61 row["price"] = v.get("price", "")
62 row["compare_at_price"] = v.get("compare_at_price", "")
63 row["available"] = v.get("available", "")
64 rows.append(row)
65 return rows
66if __name__ == "__main__":
67 STORE_URL = "https://allbirds.com" # Changez cela pour la boutique cible
68 OUTPUT_CSV = "shopify_products.csv"
69 OUTPUT_EXCEL = "shopify_products.xlsx"
70 print(f"Scraping {STORE_URL}...")
71 products = scrape_shopify(STORE_URL)
72 print(f"\nTotal products scraped: {len(products)}")
73 print("Flattening to variant-level rows...")
74 rows = flatten_to_variants(products)
75 df = pd.DataFrame(rows)
76 print(f"DataFrame: {df.shape[0]} rows x {df.shape[1]} columns")
77 df.to_csv(OUTPUT_CSV, index=False, encoding="utf-8-sig")
78 df.to_excel(OUTPUT_EXCEL, index=False, engine="openpyxl")
79 print(f"\nExported to {OUTPUT_CSV} and {OUTPUT_EXCEL}")
Lancez-le avec python scrape_shopify.py. Pour Allbirds, cela prend environ 45 secondes et produit un CSV avec plus de 5 000 lignes environ (une par variante). La sortie terminal ressemble à ceci :
1Scraping https://allbirds.com...
2 Page 1... 250 products (total: 250)
3 Page 2... 250 products (total: 500)
4 ...
5 Page 6... 170 products (total: 1420)
6Total products scraped: 1420
7Flattening to variant-level rows...
8DataFrame: 5680 rows x 14 columns
9Exported to shopify_products.csv and shopify_products.xlsx
Passez du Python : extraire Shopify en 2 clics avec Thunderbit (alternative sans code)
Tout le monde n’a pas envie d’installer Python, de déboguer des erreurs d’import ou d’entretenir un script d’extraction. Pour le commercial qui a besoin des prix concurrents pour demain matin, Python est excessif.
C’est pour cela que nous avons créé — un extracteur web IA qui fonctionne comme extension Chrome. Pas de code, pas de clé API, pas de configuration d’environnement.
Comment Thunderbit extrait les boutiques Shopify
Thunderbit propose un modèle d’extraction Shopify dédié, préconfiguré pour les pages produits Shopify. Vous installez la , vous ouvrez une boutique Shopify, puis vous cliquez sur « Scrape ». Le modèle extrait automatiquement les noms de produits, descriptions, prix, détails des variantes, images et informations de vendeur.
Pour les boutiques où le modèle ne correspond pas parfaitement (thèmes personnalisés, mises en page inhabituelles), la fonctionnalité AI Suggest Fields de Thunderbit lit la page et génère automatiquement les noms de colonnes. Vous pouvez les personnaliser : renommer les colonnes, ajouter des champs, ou écrire des instructions comme « n’extraire que les produits ayant un compare_at_price renseigné ».
Quelques fonctionnalités qui correspondent directement à ce que fait le script Python :
- Extraction des sous-pages : visite automatiquement chaque page produit et enrichit le tableau avec les descriptions complètes, avis ou détails de variantes — exactement ce que fait notre script Python en parcourant les pages, mais sans code.
- Pagination automatique : gère automatiquement la pagination par clic et le défilement infini sans configuration.
- Extraction planifiée : programmez des tâches récurrentes (par exemple « tous les lundis à 9 h ») pour surveiller les prix dans le temps — sans cron ni serveur.
- Export gratuit vers CSV, Excel, Google Sheets, Airtable ou Notion sur tous les plans.
Script Python vs Thunderbit : comparaison honnête
| Critère | Script Python | Thunderbit (sans code) |
|---|---|---|
| Temps d’installation | 15–60 min (environnement + code) | ~2 min (installation de l’extension Chrome) |
| Codage requis | Oui (Python) | Non |
| Personnalisation | Illimitée | Champs suggérés par l’IA + prompts personnalisés |
| Gestion de la pagination | À coder manuellement | Automatique |
| Formats d’export | À développer soi-même (CSV/Excel) | CSV, Excel, Google Sheets, Airtable, Notion (gratuit) |
| Exécutions planifiées | Cron + hébergement | Planificateur intégré |
| Gestion des limites de requêtes | Retries/backoff à coder | Gérée automatiquement |
| Idéal pour | Développeurs, pipelines de données à grande échelle | Utilisateurs métier, extractions rapides, suivi récurrent |
Utilisez Python si vous avez besoin d’un contrôle total ou si vous intégrez ces données dans une chaîne de traitement plus large. Utilisez Thunderbit si vous avez besoin de données rapidement et que vous ne voulez pas maintenir du code. Pour aller plus loin sur , nous avons rédigé un guide dédié sur ce sujet.

Conseils et bonnes pratiques pour extraire des boutiques Shopify
Ces recommandations restent valables quel que soit votre outil :
- Utilisez toujours
?limit=250pour réduire le nombre total de requêtes. La valeur par défaut de 30 par page implique 8 fois plus de requêtes pour les mêmes données. - Respectez la boutique : ajoutez 1 à 2 secondes de délai entre les requêtes. Envoyer des requêtes en rafale à un serveur n’est pas une bonne pratique et augmente vos risques de blocage.
- Vérifiez d’abord
robots.txt: lerobots.txtstandard de Shopify ne bloque pas/products.json. Mais certaines boutiques ajoutent des règles personnalisées, donc vérifiez avant d’extraire à grande échelle. - Stockez d’abord le JSON brut en local, puis traitez-le. Si votre logique d’analyse change plus tard, vous n’aurez pas à réextraire les données. Un simple
json.dump(all_products, open("raw_data.json", "w"))avant l’aplatissement vous évitera bien des soucis. - Dédupliquez via
product.id: dans certains cas, la pagination peut renvoyer des doublons aux frontières des pages. Un rapidedf.drop_duplicates(subset=["product_id", "variant_id"])règle le problème. - Convertissez
priceen float avant tout calcul. Shopify renvoie les prix sous forme de chaînes ("185.00"), pas de nombres. - Surveillez les changements d’endpoint : même si
/products.jsonest stable depuis des années, Shopify pourrait théoriquement en restreindre l’accès. Si votre scraper renvoie soudainement des 404, vérifiez d’abord la boutique manuellement.
Pour en savoir plus sur la création de scrapers robustes, consultez notre guide sur les .
Considérations juridiques et éthiques lors de l’extraction de Shopify
Section courte, mais importante.
L’endpoint /products.json fournit des données produits publiquement accessibles — les mêmes informations qu’un visiteur voit en parcourant la boutique. Les Conditions d’utilisation de Shopify mentionnent le fait de ne pas utiliser de « moyens automatisés » pour accéder aux « Services », mais cette formulation vise la plateforme elle-même (tableau de bord admin, paiement), pas les données publiques de la boutique. À ce jour, en avril 2026, aucune action en justice spécifique à l’extraction Shopify n’a été déposée.
Les précédents juridiques soutiennent l’extraction de données publiques : l’affaire hiQ v. LinkedIn a établi que l’extraction de données accessibles publiquement ne viole pas le CFAA, et Meta v. Bright Data (2024) a jugé que les restrictions des CGU ne s’appliquent que lorsqu’un utilisateur est connecté.
Bonnes pratiques :
- N’extrayez que des données produits accessibles publiquement
- N’extrayez pas de données personnelles ou clients
- Respectez
robots.txtet les limites de requêtes - Respectez le RGPD/CCPA si vous traitez des données personnelles (les données du catalogue produit ne sont pas personnelles)
- Identifiez-vous avec une chaîne User-Agent claire
- Extraire votre propre boutique Shopify via l’API Admin est toujours autorisé
Pour aller plus loin, consultez notre article sur les .
Conclusion et points clés à retenir
L’endpoint public /products.json de Shopify rend l’extraction de données e-commerce incroyablement simple. Le workflow est le suivant : ajoutez /products.json → récupérez avec Python → parcourez les pages avec ?limit=250&page= → aplatissez avec pandas → exportez en CSV ou Excel.
Ce que ce guide couvre et que les autres ne couvrent pas :
- Référence complète des champs : sachez exactement quelles données sont disponibles (plus de 40 champs entre produits, variantes et images) avant d’écrire la moindre ligne de code
- Endpoints supplémentaires :
/collections.jsonet/meta.jsonvous donnent une vision au niveau catégorie et des métadonnées boutique absentes des autres tutoriels - Techniques prêtes pour la production : réutilisation des sessions, backoff exponentiel, en-têtes User-Agent et
?limit=250pour gérer les limites réelles - Export CSV/Excel correct : données aplaties au niveau variante avec pandas, pas seulement des dumps JSON bruts
- Alternative sans code : pour ceux qui préfèrent la rapidité à la flexibilité du code
Pour des extractions Shopify ponctuelles ou récurrentes sans code, essayez la — le modèle Shopify Scraper gère tout, de la pagination à l’export. Pour des pipelines de données personnalisés ou des extractions à grande échelle sur de nombreuses boutiques, le script Python de ce guide vous donne un contrôle total.
Consultez notre pour des démonstrations vidéo, ou explorez nos guides sur et pour des techniques liées.
FAQ
Peut-on extraire n’importe quelle boutique Shopify avec products.json ?
La plupart des boutiques Shopify exposent cet endpoint par défaut — dans mes tests, environ 71 % renvoyaient un JSON valide. Certaines boutiques avec des configurations personnalisées ou des couches de sécurité supplémentaires (Cloudflare, architectures headless) peuvent renvoyer une 404 ou bloquer la requête. Le test rapide : rendez-vous sur {store-url}/products.json dans votre navigateur. Si vous voyez du JSON, c’est bon.
Est-il légal d’extraire des boutiques Shopify ?
Les données publiques produits (prix, titres, images, descriptions) sont généralement accessibles, et des précédents juridiques comme hiQ v. LinkedIn soutiennent l’extraction d’informations publiques. Cela dit, vérifiez toujours les Conditions d’utilisation de la boutique concernée et la législation locale. N’extrayez pas de données personnelles ou clients, et respectez les limites de requêtes.
Combien de produits peut-on extraire d’une boutique Shopify ?
Il n’existe pas de limite totale stricte. La pagination avec ?limit=250&page= permet de récupérer tout le catalogue. Pour les très grosses boutiques (25 000+ produits), utilisez la réutilisation de session et des délais pour éviter les limites de requêtes. L’endpoint /meta.json peut vous indiquer à l’avance le nombre exact de produits afin de savoir combien de pages prévoir.
Quelle est la différence entre products.json et l’API Shopify Admin ?
/products.json est un endpoint public — pas d’authentification, données produits en lecture seule, accessible à tous. L’API Admin exige des jetons d’accès du propriétaire de la boutique et fournit les commandes, les quantités de stock, les données clients et un accès en écriture. Si vous avez besoin de données de ventes ou de stocks réels, il faut l’API Admin (ce qui signifie que vous devez être propriétaire de la boutique ou avoir son autorisation).
Peut-on extraire Shopify sans Python ?
Absolument. Des outils comme permettent d’extraire des boutiques Shopify via une extension Chrome, sans écrire de code. La pagination est gérée automatiquement et l’export se fait directement vers CSV, Excel, Google Sheets, Airtable ou Notion. Pour les développeurs qui préfèrent d’autres langages, le même endpoint /products.json fonctionne avec JavaScript, Ruby, Go — n’importe quel langage capable de faire des requêtes HTTP et de parser du JSON.
En savoir plus
