Shopify’s /products.json-endpoint is een van de best bewaarde geheimen in ecommerce-data. Voeg het toe aan elke Shopify-store-URL en je krijgt gestructureerde JSON terug—geen API-sleutels, geen authenticatie, geen gedoe met het scrapen van diep geneste HTML.
Ik werk aan het team van de Thunderbit Official Website, dus ik denk dagelijks na over hoe mensen data van het web halen. En Shopify-scraping komt daarbij voortdurend terug—sales teams die concurrentieprijzen volgen, ecommerce-operations die productcatalogi benchmarken, inkoopteams die nieuwe leveranciers zoeken. Met 4,82 miljoen actieve merchants op Shopify en een marktaandeel van ongeveer 30% van de Amerikaanse ecommerce-markt, is de hoeveelheid productdata die je kunt scrapen enorm.
In deze gids nemen we het hele proces door: wat dit endpoint teruggeeft, hoe je door duizenden producten pagina voor pagina loopt, hoe je rate limits omzeilt zonder geblokkeerd te worden, en hoe je Shopify’s geneste JSON netjes omzet naar een overzichtelijke CSV- of Excel-bestand met pandas. Ik behandel ook endpoints waar bijna niemand het over heeft (/collections.json, /meta.json) en laat een no-code alternatief zien voor iedereen die Python liever overslaat.
Wat is Shopify’s /products.json-endpoint (en waarom maakt het scrapen zo makkelijk)?
Elke Shopify-store heeft een openbaar endpoint op {store-url}/products.json dat gestructureerde productdata teruggeeft. Geen API-sleutels. Geen OAuth. Geen enkele vorm van authenticatie. Je voegt letterlijk /products.json toe aan de store-URL en krijgt een JSON-array terug met elk product uit de catalogus.
Probeer het zelf: open allbirds.com/products.json of zoologistperfumes.com/products.json in je browser. Je ziet keurige, gestructureerde JSON met producttitels, prijzen, varianten, afbeeldingen, tags—alles.
Vergelijk dat eens met de alternatieve aanpak: Shopify-HTML parsën. Die pagina’s zijn diep genest, verschillen per store en veranderen zodra een merchant zijn thema aanpast. Dit is waar je dan mee te maken krijgt:
De HTML-aanpak (pijnlijk):
<div class="product-card__info">
<h3 class="product-card__title">
<a href="/products/classic-blue-jeans">Classic Blue Jeans</a>
</h3>
<span class="price price--on-sale" data-product-price>$149.00</span>
</div>
De JSON-aanpak (netjes):
{
"title": "Classic Blue Jeans",
"handle": "classic-blue-jeans",
"vendor": "Hiut Denim",
"variants": [{"price": "149.00", "sku": "HD-BLU-32", "available": true}]
}
JSON wint op consistentie, betrouwbaarheid en parse-gemak. Het endpoint ondersteunt ook twee belangrijke query-parameters—?limit= (tot 250 producten per pagina, standaard 30) en ?page= voor paginering—en die gebruiken we hieronder volop in de code.
Belangrijk onderscheid: dit is een publiek storefront-endpoint, niet de Shopify Admin API. De Admin API vereist toegangstokens van de store-eigenaar en geeft orderdata, voorraadniveaus en klantinformatie. Het openbare /products.json-endpoint bevat alleen read-only productdata die iedereen kan inzien. Dat verschil leg ik later uitgebreider uit, want daarover bestaat enorm veel verwarring in fora.
Een kanttekening: niet elke Shopify-store stelt dit endpoint beschikbaar. In mijn tests gaf ongeveer 71% van de stores geldige JSON terug (allbirds.com, gymshark.com, colourpop.com, kyliecosmetics.com werken allemaal), terwijl sommige custom configuraties een 404 teruggeven (hiutdenim.co.uk, bombas.com). De snelle check is simpel: bezoek {store-url}/products.json in je browser en kijk wat er gebeurt.
Waarom Shopify scrapen met Python? Belangrijkste zakelijke use cases
Waarom de moeite nemen? ROI. 81% van de Amerikaanse retailers gebruikt inmiddels geautomatiseerd prijs scrapen voor concurrentieanalyse, tegenover slechts 34% in 2020. En onderzoek laat zien dat een 1% verbetering in prijsstrategie gemiddeld leidt tot 11,1% meer winst. Die data is dus echt geld waard.
Dit zijn de use cases die ik het vaakst zie:
| Use case | Wie heeft er baat bij | Wat je krijgt |
|---|---|---|
| Prijsmonitoring van concurrenten | Ecommerce-operations teams | Volg prijswijzigingen, kortingen en vergelijkprijzen in concurrentencatalogi |
| Productonderzoek & sourcing | Inkoop / merchandising | Vergelijk producteigenschappen, varianten, materialen en beschikbaarheid |
| Leadgeneratie | Sales teams | Haal leveranciersnamen, merkdata en contactinformatie uit store-catalogi |
| Markt- en categorieanalyse | Marketing teams | Begrijp productmix, tags, collectie-opbouw en positionering |
| Voorraad- en beschikbaarheidsmonitoring | Supply chain teams | Volg de voorraadstatus per variant (available: true/false) in de tijd |
| Detectie van nieuwe producten | Product teams | Volg created_at-timestamps om nieuwe launches van concurrenten te spotten |
Python is hier een logische keuze. 69,6% van de scraping-ontwikkelaars gebruikt Python als primaire taal, en het ecosysteem—requests voor HTTP, pandas voor datamanipulatie, httpx voor async—maakt het eenvoudig om van “ik heb een URL” naar “ik heb een spreadsheet” te gaan in minder dan 80 regels code.
Volledige products.json-veldreferentie: elk veld uitgelegd
De meeste tutorials laten je alleen title, id en handle zien en gaan daarna verder. Shopify’s JSON-response bevat meer dan 40 velden over producten, varianten, afbeeldingen en opties. Weten wat er beschikbaar is vóórdat je code schrijft, bespaart je later opnieuw scrapen.
Ik heb deze referentie samengesteld uit live /products.json-responses die ik op 16 april 2026 heb opgehaald. De structuur is consistent bij alle stores die dit endpoint beschikbaar stellen.
Velden op productniveau
| Veld | Datatype | Voorbeeldwaarde | Zakelijke toepassing |
|---|---|---|---|
id | Integer | 123456789 | Unieke product-ID voor deduplicatie |
title | String | "Classic Blue Jeans" | Productnaam voor catalogi en vergelijkingen |
handle | String | "classic-blue-jeans" | URL-slug—bouw productlinks als {store}/products/{handle} |
body_html | String (HTML) of null | Our best-selling... | Productbeschrijving voor contentanalyse en SEO-onderzoek |
vendor | String | "Hiut Denim" | Merk-/leveranciersnaam voor leadgen of sourcing |
product_type | String | "Jeans" | Categorie-indeling voor marktanalyse |
created_at | ISO-datetime | "2024-01-15T10:30:00-05:00" | Volg wanneer producten zijn toegevoegd (nieuwe launch detectie) |
updated_at | ISO-datetime | "2025-03-01T08:00:00-05:00" | Detecteer recente cataloguswijzigingen |
published_at | ISO-datetime | "2024-01-16T00:00:00-05:00" | Zie wanneer producten live gingen op de storefront |
tags | Array van strings | ["organic", "women", "straight-leg"] | Analyse van keywords/tags voor SEO, categorisatie en trendspotting |
variants | Array van objecten | (zie variantvelden hieronder) | Prijs, SKU en beschikbaarheid per variant |
images | Array van objecten | (zie afbeeldingsvelden hieronder) | Productafbeeldingen voor catalogi en visuele analyse |
options | Array van objecten | [{"name": "Size", "values": ["S","M","L"]}] | Begrijp productconfiguraties (maat, kleur, materiaal) |
Velden op variantniveau (genest onder elk product)
| Veld | Datatype | Voorbeeld | Toepassing |
|---|---|---|---|
id | Integer | 987654321 | Unieke variant-ID |
title | String | "32 / Blue" | Weergavenaam van de variant |
sku | String | "HD-BLU-32" | SKU-matching voor voorraadsystemen |
price | String | "185.00" | Prijsmonitoring (let op: dit is een string, dus cast naar float voor berekeningen) |
compare_at_price | String of null | "200.00" | Oorspronkelijke prijs—onmisbaar voor kortingsanalyse |
available | Boolean | true | Voorraadbeschikbaarheid (de enige publieke voorraadindicator) |
weight | Float | 1.2 | Analyse voor verzending/logistiek |
option1, option2, option3 | String | "32", "Blue", null | Individuele optiewaarden |
created_at, updated_at | ISO-datetime | — | Wijzigingen op variantniveau volgen |
Velden op afbeeldingsniveau
| Veld | Datatype | Voorbeeld | Toepassing |
|---|---|---|---|
id | Integer | 111222333 | Unieke afbeelding-ID |
src | String (URL) | "https://cdn.shopify.com/..." | Directe downloadlink voor afbeeldingen |
alt | String of null | "Front view of jeans" | Alt-tekst voor toegankelijkheidsanalyse |
position | Integer | 1 | Volgorde van afbeeldingen |
width, height | Integer | 2048, 2048 | Afmetingen van de afbeelding |
Wat er NIET in het publieke endpoint zit
Een belangrijke valkuil: inventory_quantity is NIET beschikbaar in openbare /products.json-responses. Dit veld is in december 2017 verwijderd uit publieke JSON-endpoints om veiligheidsredenen. De enige voorraadindicator die je krijgt is het booleaanse available-veld per variant (true of false). Voor echte voorraad-aantallen heb je de geauthenticeerde Admin API nodig met credentials van de store-eigenaar.
Bekijk deze tabel voordat je code schrijft en beslis welke velden relevant zijn voor jouw use case. Doe je prijsmonitoring, dan heb je variants[].price, variants[].compare_at_price en variants[].available nodig. Doe je leadgeneratie, focus dan op vendor, product_type en tags. Filter daarop—je CSV wordt veel overzichtelijker.
Verder dan products.json: Collections, meta en andere Shopify-endpoints
Bijna geen enkele vergelijkende tutorial noemt deze endpoints. Toch zijn ze essentieel voor serieuze competitive-intelligence-werkzaamheden.
/collections.json — alle storecategorieën
Geeft elke collectie (categorie) in de store terug, inclusief titels, handles, beschrijvingen en productaantallen. Ik heb dit geverifieerd op zoologistperfumes.com, allbirds.com en gymshark.com—allemaal gaven geldige JSON terug.
{
"collections": [
{
"id": 308387348539,
"title": "Attars",
"handle": "attars",
"published_at": "2026-03-29T12:20:32-04:00",
"products_count": 1,
"image": { "src": "https://cdn.shopify.com/..." }
}
]
}
Wil je begrijpen hoe een concurrent zijn catalogus indeelt? Dan is dit het endpoint dat je nodig hebt.
/collections/{handle}/products.json — producten per categorie
Geeft producten terug die gefilterd zijn op een specifieke collectie. Dezelfde JSON-structuur als /products.json, maar dan beperkt tot één categorie. Dit is cruciaal voor scraping op categorieniveau—bijvoorbeeld als je alleen de "Sale"- of "New Arrivals"-collectie van een concurrent wilt volgen.
/meta.json — metadata op storeniveau
Geeft storenaam, beschrijving, valuta, land en—het belangrijkste—published_products_count terug. Met dat aantal kun je vooraf exact berekenen hoeveel paginapunten je nodig hebt: ceil(published_products_count / 250). Geen eindeloos doorklikken meer totdat je een lege response krijgt.
Welk endpoint moet je gebruiken?
| Wat je wilt | Endpoint | Authenticatie nodig? |
|---|---|---|
| Alle producten (publiek) | /products.json | Nee |
| Producten in een specifieke categorie | /collections/{handle}/products.json | Nee |
| Store-metadata + productaantal | /meta.json | Nee |
| Alle collecties (categorieën) | /collections.json | Nee |
| Order-/verkoopdata (alleen eigen store) | Admin API /orders.json | Ja (API key) |
| Voorraadhoeveelheden (alleen eigen store) | Admin API /inventory_levels.json | Ja |
De terugkerende forumvraag—"Kan ik zien hoeveel units een concurrent heeft verkocht?"—heeft een kort antwoord: nee. Niet via publieke endpoints. Verkoopdata en voorraadhoeveelheden vereisen de geauthenticeerde Admin API, wat betekent dat je toegang van de store-eigenaar nodig hebt. Publieke endpoints geven alleen catalogusdata.

Shopify scrapen met Python: stap-voor-stap setup
- Moeilijkheidsgraad: Beginner
- Benodigde tijd: ~15 minuten (setup + eerste scrape)
- Wat je nodig hebt: Python 3.11+,
pip, een terminal en een Shopify-store-URL om te scrapen
Stap 1: Python en vereiste libraries installeren
Zorg dat je Python 3.11 of nieuwer hebt geĂŻnstalleerd (pandas 3.0.x vereist dat). Installeer daarna de twee libraries die we nodig hebben:
pip install requests pandas
Voor export naar Excel heb je ook nodig:
pip install openpyxl
Voeg bovenaan je script deze imports toe:
import requests
import pandas as pd
import time
import random
import json
Je zou geen importfouten moeten zien wanneer je het script runt. Als pandas een versie-fout geeft, upgrade Python dan naar 3.12.
Stap 2: Productdata ophalen uit /products.json
Hier is een eenvoudige functie die een store-URL neemt, het endpoint aanroept en de geparste JSON teruggeeft:
def fetch_products_page(store_url, page=1, limit=250):
"""Haal één pagina met producten op uit een Shopify-store."""
url = f"{store_url.rstrip('/')}/products.json"
params = {"limit": limit, "page": page}
headers = {
"User-Agent": "Mozilla/5.0 (compatible; ProductResearch/1.0)"
}
response = requests.get(url, params=params, headers=headers, timeout=30)
response.raise_for_status()
return response.json().get("products", [])
Belangrijke details:
limit=250is het maximum dat Shopify per pagina toestaat. De standaard is 30, dus dit expliciet instellen vermindert het aantal requests tot wel 8x.User-Agent-header: stel altijd een realistische header in. Requests zonder User-Agent maken meer kans om Shopify’s anti-bot-systemen te activeren.timeout=30: laat een request niet eindeloos hangen.
Test het met een bekende store:
products = fetch_products_page("https://allbirds.com")
print(f"Fetched {len(products)} products")
print(f"First product: {products[0]['title']}")
Je zou iets moeten zien als: Fetched 250 products en de titel van het eerste product.
Stap 3: Paginering verwerken om alle producten te scrapen
Eén request levert maximaal 250 producten op. De meeste stores hebben er meer dan dat (Allbirds heeft 1.420+). Je moet dus door de pagina’s lopen totdat je een lege response krijgt.
def scrape_all_products(store_url, delay=1.0):
"""Scrape alle producten uit een Shopify-store met paginering."""
all_products = []
page = 1
while True:
print(f"Fetching page {page}...")
products = fetch_products_page(store_url, page=page, limit=250)
if not products:
print(f"No more products. Total: {len(all_products)}")
break
all_products.extend(products)
print(f" Got {len(products)} products (total so far: {len(all_products)})")
page += 1
# Wees netjes: wacht tussen requests
time.sleep(delay + random.uniform(0, 0.5))
return all_products
Wanneer products leeg terugkomt, ben je aan het eind.
De time.sleep() met een kleine willekeurige variatie houdt je onder Shopify’s informele rate limit (~2 requests/seconde).
Pro tip: als je eerst /meta.json hebt opgehaald, weet je al hoeveel producten er zijn en kun je exact berekenen hoeveel pagina’s je nodig hebt: pages = ceil(product_count / 250). Zo voorkom je de extra lege request aan het einde.
Stap 4: De velden selecteren die je nodig hebt
Nu je alle producten als een Python-lijst met dictionaries hebt, kun je alleen de velden extraheren die je nodig hebt. Hieronder een voorbeeld dat de meest gebruikte velden voor prijsmonitoring ophaalt:
def extract_product_data(products):
"""Haal belangrijke velden uit producten en flatten de varianten."""
rows = []
for product in products:
for variant in product.get("variants", []):
rows.append({
"product_id": product["id"],
"title": product["title"],
"handle": product["handle"],
"vendor": product.get("vendor", ""),
"product_type": product.get("product_type", ""),
"tags": ", ".join(product.get("tags", [])),
"created_at": product.get("created_at", ""),
"variant_id": variant["id"],
"variant_title": variant.get("title", ""),
"sku": variant.get("sku", ""),
"price": variant.get("price", ""),
"compare_at_price": variant.get("compare_at_price", ""),
"available": variant.get("available", ""),
"image_url": product["images"][0]["src"] if product.get("images") else ""
})
return rows
Dit maakt één rij per variant—het meest bruikbare formaat voor prijsvergelijking, omdat één product zoals "Classic Blue Jeans" 12 varianten kan hebben (6 maten × 2 kleuren), elk met een eigen prijs en beschikbaarheidsstatus.
Gescrapete Shopify-data exporteren naar CSV en Excel met pandas
Elke andere Shopify-scraping tutorial dumpt ruwe JSON naar een bestand en noemt het klaar. Prima voor developers. Vrij nutteloos voor de ecommerce-analist die vrijdag een spreadsheet nodig heeft.
Het probleem: Shopify’s JSON is genest. Eén product kan een dozijn varianten bevatten, elk met een eigen prijs, SKU en beschikbaarheid. Dat omzetten naar rijen en kolommen kost wat werk in pandas.
Geneste JSON omzetten naar een nette tabel
Er zijn twee aanpakken, afhankelijk van je use case:
Optie A: één rij per variant (beste voor prijsmonitoring en voorraadtracking)
# Gebruik de extract_product_data-functie uit Stap 4
products = scrape_all_products("https://allbirds.com")
rows = extract_product_data(products)
df = pd.DataFrame(rows)
print(f"DataFrame shape: {df.shape}")
print(df.head())
Dit geeft je een platte tabel waarin elke rij een unieke combinatie van product en variant is. Een store met 500 producten en gemiddeld 4 varianten per product levert een DataFrame van ongeveer 2.000 rijen op.
Optie B: één rij per product-samenvatting (beste voor catalogusoverzichten)
def summarize_products(products):
"""Eén rij per product met min/max prijs over de varianten."""
rows = []
for product in products:
prices = [float(v["price"]) for v in product.get("variants", []) if v.get("price")]
rows.append({
"product_id": product["id"],
"title": product["title"],
"vendor": product.get("vendor", ""),
"product_type": product.get("product_type", ""),
"variant_count": len(product.get("variants", [])),
"min_price": min(prices) if prices else None,
"max_price": max(prices) if prices else None,
"any_available": any(v.get("available", False) for v in product.get("variants", [])),
"tags": ", ".join(product.get("tags", []))
})
return rows
Exporteren naar CSV, Excel en Google Sheets
# CSV-export (gebruik utf-8-sig zodat Excel speciale tekens goed leest)
df.to_csv("shopify_products.csv", index=False, encoding="utf-8-sig")
# Excel-export (openpyxl vereist)
df.to_excel("shopify_products.xlsx", index=False, engine="openpyxl")
print("Exported to shopify_products.csv and shopify_products.xlsx")
Voor Google Sheets kun je de gspread-library met een service account gebruiken, maar eerlijk gezegd—voor de meeste use cases is exporteren naar CSV en uploaden naar Google Drive sneller en eenvoudiger.
Productiesoftware voor scraping in Python: rate limits, retries en anti-blocking
Het basisscript werkt prima voor kleine stores. Maar een store met 5.000+ producten scrapen, of meerdere stores na elkaar aanroepen? Dan beginnen de problemen.
Shopify’s rate limits en blokkeringsgedrag begrijpen
Shopify’s openbare JSON-endpoints hebben geen officieel gedocumenteerde rate limits (in tegenstelling tot het leaky-bucket-model van de Admin API), maar tests in de praktijk laten het volgende zien:
- Veilige snelheid: ongeveer 2 requests per seconde per store
- Zachte bovengrens: ongeveer 40 requests per minuut voordat throttling optreedt
- HTTP 429: "Too Many Requests"—de standaard rate-limit response
- HTTP 430: een Shopify-specifieke code die op een security-block wijst (niet alleen rate limiting)
- HTTP 403 of CAPTCHA-redirect: sommige stores met extra Cloudflare-beveiliging
Requests vanaf gedeelde cloud-infrastructuur (AWS Lambda, Google Cloud Run) worden extra vaak geblokkeerd, omdat die IP-ranges vaker misbruikt worden.
Technieken om Shopify betrouwbaar te scrapen
Hier zie je de progressie van “werkt op mijn laptop” naar “geschikt voor productie”:
| Niveau | Techniek | Betrouwbaarheid |
|---|---|---|
| Basis | requests.get() + ?page= | Breekt bij grote catalogi, kan geblokkeerd worden |
| Gemiddeld | requests.Session() + ?limit=250 + time.sleep(1) + retry bij 429 | Werkt voor de meeste stores |
| Geavanceerd | Async httpx + roterende User-Agent + exponential backoff | Productiewaardig, schaalbaar tot 10K+ producten |
Gemiddeld niveau (aanbevolen voor de meeste gebruikers):
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
def create_session():
"""Maak een requests-session met automatische retry-logica."""
session = requests.Session()
retries = Retry(
total=5,
backoff_factor=1, # sleep: 0.5s, 1s, 2s, 4s, 8s
status_forcelist=[429, 430, 500, 502, 503, 504],
respect_retry_after_header=True
)
session.mount("https://", HTTPAdapter(max_retries=retries))
session.headers.update({
"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"
})
return session
De Retry-configuratie handelt 429-responses automatisch af met exponential backoff. De backoff_factor=1 betekent dat de wachttijd tussen retries oploopt van 0,5s → 1s → 2s → 4s → 8s. Session-hergebruik (requests.Session()) geeft je bovendien connection pooling, wat de overhead verlaagt bij meerdere requests naar hetzelfde domein.
User-Agent-rotatie: scrape je meerdere stores, wissel dan tussen 3–5 realistische browser-User-Agents. Dit gaat niet om misleiding—het gaat erom dat je niet uitziet als een bot die bij elke request exact dezelfde headers stuurt.
Volledig werkend Python-script om Shopify te scrapen met CSV-export
Hier is het complete, direct te kopiëren script dat alles hierboven combineert. Het is ongeveer 75 regels echte code (plus comments), en ik heb het getest op Allbirds (1.420 producten), ColourPop (2.000+ producten) en Zoologist Perfumes (kleine catalogus).
import requests
import pandas as pd
import time
import random
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
def create_session():
"""Maak een session met retry-logica voor rate limits."""
session = requests.Session()
retries = Retry(
total=5,
backoff_factor=1,
status_forcelist=[429, 430, 500, 502, 503, 504],
respect_retry_after_header=True
)
session.mount("https://", HTTPAdapter(max_retries=retries))
session.headers.update({
"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"
})
return session
def scrape_shopify(store_url, delay=1.0):
"""Scrape alle producten van een Shopify-store via /products.json."""
session = create_session()
all_products = []
page = 1
base_url = f"{store_url.rstrip('/')}/products.json"
while True:
print(f" Page {page}...", end=" ")
resp = session.get(base_url, params={"limit": 250, "page": page}, timeout=30)
resp.raise_for_status()
products = resp.json().get("products", [])
if not products:
break
all_products.extend(products)
print(f"{len(products)} products (total: {len(all_products)})")
page += 1
time.sleep(delay + random.uniform(0, 0.5))
return all_products
def flatten_to_variants(products):
"""Maak van geneste product-JSON één rij per variant."""
rows = []
for p in products:
base = {
"product_id": p["id"],
"title": p["title"],
"handle": p["handle"],
"vendor": p.get("vendor", ""),
"product_type": p.get("product_type", ""),
"tags": ", ".join(p.get("tags", [])),
"created_at": p.get("created_at", ""),
"updated_at": p.get("updated_at", ""),
"image_url": p["images"][0]["src"] if p.get("images") else "",
}
for v in p.get("variants", []):
row = {**base}
row["variant_id"] = v["id"]
row["variant_title"] = v.get("title", "")
row["sku"] = v.get("sku", "")
row["price"] = v.get("price", "")
row["compare_at_price"] = v.get("compare_at_price", "")
row["available"] = v.get("available", "")
rows.append(row)
return rows
if __name__ == "__main__":
STORE_URL = "https://allbirds.com" # Pas dit aan naar de store die je wilt scrapen
OUTPUT_CSV = "shopify_products.csv"
OUTPUT_EXCEL = "shopify_products.xlsx"
print(f"Scraping {STORE_URL}...")
products = scrape_shopify(STORE_URL)
print(f"\nTotal products scraped: {len(products)}")
print("Flattening to variant-level rows...")
rows = flatten_to_variants(products)
df = pd.DataFrame(rows)
print(f"DataFrame: {df.shape[0]} rows x {df.shape[1]} columns")
df.to_csv(OUTPUT_CSV, index=False, encoding="utf-8-sig")
df.to_excel(OUTPUT_EXCEL, index=False, engine="openpyxl")
print(f"\nExported to {OUTPUT_CSV} and {OUTPUT_EXCEL}")
Run het met python scrape_shopify.py. Voor Allbirds duurt dit ongeveer 45 seconden en krijg je een CSV met ongeveer 5.000+ rijen (één per variant). De terminaloutput ziet er ongeveer zo uit:
Scraping https://allbirds.com...
Page 1... 250 products (total: 250)
Page 2... 250 products (total: 500)
...
Page 6... 170 products (total: 1420)
Total products scraped: 1420
Flattening to variant-level rows...
DataFrame: 5680 rows x 14 columns
Exported to shopify_products.csv and shopify_products.xlsx
Sla Python over: scrape Shopify in 2 klikken met Thunderbit (no-code alternatief)
Niet iedereen wil Python installeren, importfouten debuggen of een scraping-script onderhouden. Voor de sales rep die morgenochtend concurrentieprijzen nodig heeft, is Python vaak overdreven.
Daarom hebben we Thunderbit Official Website gebouwd—een AI-webscraper die werkt als Chrome-extensie. Geen code, geen API-sleutels, geen omgevingssetup.
Probeer de Thunderbit Chrome-extensie
Hoe Thunderbit Shopify-stores scrapt
Thunderbit heeft een speciale Shopify Scraper-template die vooraf is ingesteld voor Shopify-productpagina’s. Je installeert de Thunderbit Chrome Extension Download Page, navigeert naar een Shopify-store en klikt op "Scrape." De template haalt automatisch productnamen, beschrijvingen, prijzen, variantdetails, afbeeldingen en vendorinformatie op.
Voor stores waar de template niet perfect aansluit (custom themes, afwijkende layouts), leest Thunderbit’s AI Suggest Fields-functie de pagina en genereert automatisch kolomnamen. Je kunt die aanpassen—kolommen hernoemen, velden toevoegen, instructies schrijven zoals "haal alleen producten op met een ingestelde compare_at_price."
Een paar functies die direct overeenkomen met wat het Python-script doet:
- Subpage scraping: bezoekt automatisch elke productdetailpagina en verrijkt de tabel met volledige beschrijvingen, reviews of variantdetails—precies wat ons Python-script doet door pagina’s te itereren, maar dan zonder code.
- Automatische paginering: verwerkt doorklikpaginering en infinite scroll zonder configuratie.
- Geplande scraping: zet terugkerende taken op (bijv. "elke maandag om 9:00") voor doorlopende prijsmonitoring—geen cron job of server nodig.
- Gratis export naar CSV, Excel, Google Sheets, Airtable of Notion op alle abonnementen.
Python-script vs. Thunderbit: eerlijke vergelijking
| Factor | Python-script | Thunderbit (No-code) |
|---|---|---|
| Setup-tijd | 15–60 min (omgeving + code) | ~2 min (Chrome-extensie installeren) |
| Coderen nodig | Ja (Python) | Nee |
| Aanpasbaarheid | Onbeperkt | AI-voorgestelde velden + custom prompts |
| Paginering afhandelen | Handmatig coderen | Automatisch |
| Exportformaten | Zelf coderen (CSV/Excel) | CSV, Excel, Google Sheets, Airtable, Notion (gratis) |
| Geplande runs | Cron job + hosting | Ingebouwde scheduler |
| Rate-limit afhandeling | Zelf retries/backoff coderen | Automatisch afgehandeld |
| Beste voor | Developers, grootschalige datapijplijnen | Business users, snelle extracties, terugkerende monitoring |
Gebruik Python als je volledige controle nodig hebt of als je het in een grotere datapijplijn integreert. Gebruik Thunderbit als je snel data nodig hebt en geen code wilt onderhouden. Voor een diepere kijk op web scraping voor prijsvergelijking hebben we daar een aparte gids over geschreven.

Tips en best practices voor het scrapen van Shopify-stores
Deze gelden ongeacht je toolkeuze:
- Gebruik altijd
?limit=250om het totale aantal requests te minimaliseren. De standaard van 30 per pagina betekent 8x meer requests voor dezelfde data. - Respecteer de store: voeg 1–2 seconden vertraging toe tussen requests. Een server bestoken met razendsnelle requests is slechte praktijk en vergroot de kans op blokkering.
- Controleer eerst
robots.txt: Shopify’s standaardrobots.txtblokkeert/products.jsonniet. Maar sommige stores voegen eigen regels toe, dus controleer dit voordat je op schaal gaat scrapen. - Sla eerst ruwe JSON lokaal op, en verwerk daarna pas verder. Als je parsing-logica later verandert, hoef je niet opnieuw te scrapen. Een simpele
json.dump(all_products, open("raw_data.json", "w"))vóór het flattenen bespaart veel gedoe. - Dedupliceer op
product.id: bij randgevallen in paginering kunnen dubbele producten aan paginagrenzen terugkomen. Een snelledf.drop_duplicates(subset=["product_id", "variant_id"])lost dat op. - Zet
priceom naar float voordat je gaat rekenen. Shopify geeft prijzen als strings terug ("185.00"), niet als getallen. - Houd endpointwijzigingen in de gaten: hoewel
/products.jsonal jaren stabiel is, zou Shopify dit in theorie kunnen beperken. Krijg je ineens 404’s, controleer dan eerst handmatig de store.
Voor meer over het bouwen van robuuste scrapers, bekijk onze gids over best practices voor web scraping tools.
Juridische en ethische aandachtspunten bij het scrapen van Shopify
Kort, maar belangrijk.
Het /products.json-endpoint levert publiek beschikbare productdata—dezelfde informatie die elke bezoeker ziet wanneer hij de store bekijkt. Shopify’s Servicevoorwaarden bevatten taal over het niet gebruiken van "automated means" om toegang te krijgen tot "the Services", maar die tekst verwijst naar het platform zelf (admin-dashboard, checkout), niet naar publieke storefront-data. Tot april 2026 zijn er geen Shopify-specifieke scrapingzaken aangespannen.
Belangrijke juridische precedenten ondersteunen scraping van publieke data: de hiQ v. LinkedIn-zaak stelde vast dat het scrapen van publiek toegankelijke data de CFAA niet schendt, en Meta v. Bright Data (2024) oordeelde dat TOS-beperkingen alleen gelden wanneer een gebruiker is ingelogd.
Best practices:
- Scrape alleen publiek beschikbare productdata
- Scrape geen persoonlijke of klantgegevens
- Respecteer
robots.txten rate limits - Voldoe aan GDPR/AVG en CCPA als je persoonlijke data verwerkt (productcatalogusdata is niet-persoonlijk)
- Identificeer jezelf met een duidelijke User-Agent-string
- Je eigen Shopify-store scrapen via de Admin API is altijd prima
Voor een diepere duik, zie onze post over de juridische implicaties van web scraping.
Conclusie en belangrijkste inzichten
Shopify’s openbare /products.json-endpoint maakt ecommerce-data-extractie bijna zo eenvoudig als het maar kan. De workflow is: voeg /products.json toe → haal op met Python → pagineer met ?limit=250&page= → flatten met pandas → exporteer naar CSV of Excel.
Wat deze gids biedt dat andere gidsen niet doen:
- Volledige veldreferentie: weet precies welke data beschikbaar is (40+ velden over producten, varianten en afbeeldingen) voordat je ook maar één regel code schrijft
- Extra endpoints:
/collections.jsonen/meta.jsongeven je categorie-inzicht en storemetadata die geen enkele concurrerende tutorial behandelt - Productiewaardige technieken: session-hergebruik, exponential backoff, User-Agent-headers en
?limit=250om echte rate limits aan te kunnen - Correcte CSV/Excel-export: afgevlakte variantdata met pandas, niet alleen ruwe JSON-dumps
- No-code alternatief: Thunderbit voor gebruikers die snelheid boven codeflexibiliteit verkiezen
Voor eenmalige of terugkerende Shopify-data-extracties zonder code, probeer de Thunderbit Chrome Extension Download Page—de Shopify Scraper-template regelt alles van paginering tot export. Voor custom datapijplijnen of scraping op schaal over veel stores biedt het Python-script in deze gids volledige controle.
Bekijk ons Thunderbit YouTube-kanaal voor video-uitleg, of lees onze gidsen over Amazon-producten scrapen en data van websites naar Excel halen voor gerelateerde technieken.
Probeer Thunderbit voor Shopify-scraping Get Started Free
FAQ’s
Kun je elke Shopify-store scrapen met products.json?
De meeste Shopify-stores stellen dit endpoint standaard beschikbaar—in tests gaf ongeveer 71% geldige JSON terug. Sommige stores met custom configuraties of extra beveiligingslagen (Cloudflare, headless setups) geven een 404 terug of blokkeren de request. De snelle check: bezoek {store-url}/products.json in je browser. Zie je JSON, dan zit je goed.
Is het legaal om Shopify-stores te scrapen?
Publieke productdata (prijzen, titels, afbeeldingen, beschrijvingen) is over het algemeen toegankelijk, en juridische precedenten zoals hiQ v. LinkedIn ondersteunen het scrapen van publiek beschikbare informatie. Controleer wel altijd de specifieke voorwaarden van de store en de lokale wetgeving. Scrape geen persoonlijke of klantgegevens en respecteer rate limits.
Hoeveel producten kun je scrapen van een Shopify-store?
Er is geen harde limiet op het totaal. Paginering met ?limit=250&page= laat je de volledige catalogus ophalen. Voor zeer grote stores (25.000+ producten) gebruik je session-hergebruik en vertragingen om rate limits te vermijden. Het /meta.json-endpoint kan je vooraf het exacte productaantal geven, zodat je weet hoeveel pagina’s je kunt verwachten.
Wat is het verschil tussen products.json en de Shopify Admin API?
/products.json is een publiek endpoint—geen authenticatie, alleen read-only productdata, toegankelijk voor iedereen. De Admin API vereist toegangstokens van de store-eigenaar en biedt orders, voorraadhoeveelheden, klantdata en schrijfrechten. Als je verkoopdata of echte voorraadniveaus nodig hebt, heb je Admin API-toegang nodig (dus je moet de store-eigenaar zijn of toestemming hebben).
Kan ik Shopify scrapen zonder Python?
Absoluut. Tools zoals Thunderbit Official Website laten je Shopify-stores scrapen vanuit een Chrome-extensie zonder code. Paginering wordt automatisch afgehandeld en export gaat direct naar CSV, Excel, Google Sheets, Airtable of Notion. Voor developers die liever andere talen gebruiken: hetzelfde /products.json-endpoint werkt ook met JavaScript, Ruby, Go—elke taal die HTTP-requests kan doen en JSON kan parsen.
Meer leren


