Shopify Products Scraper avatar

Shopify Products Scraper

Pricing

$19.99/month + usage

Go to Apify Store
Shopify Products Scraper

Shopify Products Scraper

Shopify Products Scraper extracts publicly available product data from Shopify stores, including titles, prices, variants, images, descriptions, and availability. Use it for catalog analysis, research, or monitoring with fast runs and structured results.

Pricing

$19.99/month + usage

Rating

0.0

(0)

Developer

Scraper Engine

Scraper Engine

Maintained by Community

Actor stats

0

Bookmarked

4

Total users

1

Monthly active users

3 days ago

Last modified

Share

Shopify Product Scraper — Variants, Prices, SKUs and Stock

Shopify Products Scraper reads a Shopify store's public product catalogue and returns every product with its complete variant list — SKU, per-variant price, stock status and options — plus price range, currency, vendor, tags and image URLs, as structured JSON. No login or Shopify account is required: it reads the same public JSON feed the storefront itself publishes to browsers. Point it at one or more store URLs and start the run below.


What is Shopify Products Scraper?

Shopify Products Scraper is an Apify Actor that crawls a public Shopify storefront's product catalogue and returns one row per product — with the full variant array nested inside — plus one honest coverage-summary row per store explaining exactly what was and wasn't reachable. It reads the same public products.json and products/<handle>.json feeds a browser loads, so no Shopify account, API key or store login is required. It's built for e-commerce analysts, dropshippers, competitor-pricing teams and AI engineers who need a store's catalogue as clean, typed JSON rather than scraped HTML.


What Shopify product data is publicly available to scrape?

Any Shopify store that publishes its catalogue feed exposes full product and variant data — title, price, stock and options — to any visitor's browser without a login. Order data, customer data and checkout are never public; they sit behind Shopify's own admin authentication, which this Actor never touches.

Data categoryPublicly availableRestricted
Product title, price, images, URL
Full variant list (SKU, per-variant price, options, stock)
Vendor, product type, tags
Inventory quantity per variant⚠️ Only when the store chooses to publish itLeft null on stores that don't
Barcode per variant⚠️ Only when the store chooses to publish itLeft null on stores that don't
Product description / full HTML body❌ Not returned by this ActorPresent on the storefront, outside this Actor's output
Catalogue on a password-protected storeStore password
Catalogue on a headless/custom-frontend storeNo public JSON feed exposed
Order, customer and checkout dataShopify Admin authentication (store owner only)

Shopify Products Scraper only returns publicly visible data — what any visitor sees. Nothing behind a login, store password or admin credential.


What data can I extract with Shopify Products Scraper?

Each product row carries identity and descriptive fields, computed pricing and stock metrics, and a nested variant/option/image structure. A second row type — one per store — reports catalogue coverage.

FieldDescription
typeRow type: "product" for a product row
store_url / store_domainThe storefront this product came from
store_status"ok" on every product row
product_urlPublic URL of the product page
handleThe product's URL slug
product_idShopify's numeric product ID
titleProduct title
vendorVendor/brand as published by the store, or null
product_typeStore-assigned product type, or null
tagsArray of tags
created_at / updated_at / published_atStore-published timestamps
detail_enrichedtrue if the per-product detail record was also fetched
scraped_atUTC timestamp this row was collected

💰 Pricing, stock and variant metrics

FieldDescription
priceDecimal-string price of the cheapest real variant
compare_at_priceCompare-at price of that same cheapest variant, or null
price_min / price_maxLowest / highest variant price as numbers
price_variestrue when variants don't all share one price
currencyISO currency code, or null if the store doesn't publish one
discount_percentPercentage discount, only when the compare-at price is genuinely higher than price — see note below
is_on_saletrue when discount_percent is not null
availabletrue if at least one variant is in stock
variant_countNumber of variants on the product
in_stock_variant_count / out_of_stock_variant_countVariant stock rollup, or null when no variant published an available flag
availability_ratioIn-stock variants ÷ total variants with a known flag
sku_countHow many variants carry a SKU

discount_percent is genuinely absent, not zero, when there's no real markdown. The source code notes a live measurement where 75% of one store's variants publish a compare-at price lower than the selling price — a percentage computed from that would be negative and meaningless, so it comes back null instead of a fake number.

🧩 Variants, options and images

FieldDescription
variantsFull array — see the Output example below for every nested key
optionsArray of { name, position, values } — the store's declared option matrix
option_namesFlat array of option names, e.g. ["Color", "Size"]
image_countNumber of image URLs on the product
featured_imageFirst image URL, or null
image_urlsEvery image URL — URLs only, no files are downloaded

🤖 Add-on: Need additional Shopify data?

Pair this with Shopify Merchant Scraper for a store's contact details, socials and tech stack, or Shopify Store Scraper for a store-level profile (theme, installed apps, catalogue size). For product data pulled straight from a store's homepage or collection pages instead of the catalogue feed, see Shopify Scraper.


How does Shopify Products Scraper differ from the official Shopify API?

Shopify's own Admin and Storefront APIs only return data for stores that have issued you an access token — you install an app on that store, or the store owner authorizes it via OAuth, before a single request works (shopify.dev, checked 2026-08-15). That makes them unusable for reading a catalogue you don't own or control, which is exactly what most competitor research, sourcing and market-monitoring use cases need.

FeatureShopify Admin/Storefront APIShopify Products Scraper
Read a store you don't own❌ needs an access token that store issues you✅ reads the public JSON feed any visitor's browser gets
Multiple unrelated stores in one run❌ separate token per store✅ one run, any number of startUrls, independent per store
Rate limit (standard plan)2 requests/second, leaky bucket, 40-request bucket (REST); cost-based points/second by plan tier — 100 (Standard), 200 (Advanced), 1000 (Plus), 2000 (Enterprise) for GraphQL (shopify.dev, checked 2026-08-15)Self-paced with jittered request gaps and automatic connection escalation on refusal — no fixed number to configure
SetupCreate/install an app, complete OAuth or generate a custom-app token, per storePaste a store URL and run
Output shapeRaw REST/GraphQL objects you normalize yourselfPre-computed rollups (price range, stock counts, SKU coverage) on every row

Use the Admin API when the store is yours and you need write access, orders or checkout data. Use Shopify Products Scraper for read-only catalogue collection across stores you don't control.


How to use Shopify Products Scraper

  1. Open Shopify Products Scraper on the Apify Store and click Try for free (or Start, if you already have it saved) to open the input form in Apify Console.
  2. Fill in startUrls with at least one Shopify storefront address — a full URL, a bare domain, or a .myshopify.com address all work.
  3. Optionally raise maxItems above the store's catalogue size if you want the whole thing, or leave the default to sample a store first.
  4. Leave proxyConfiguration on its default unless you specifically need to route through a chosen Apify Proxy selection.
  5. Click Start, then open the run's dataset and export it as JSON, CSV, Excel or the other formats Apify supports.

How to scale to bulk product extraction

startUrls is an array — add as many storefront addresses as you need in one run. Each store is crawled independently: one store returning password_protected or unreachable never stops the others from completing, and every store gets its own product rows plus its own coverage-summary row so you can tell at a glance which ones succeeded.


What can you do with Shopify product data?

  • 🏷️ Competitor price monitoring — pricing analysts use price, price_min, price_max and compare_at_price to track a rival's price bands and discount depth across a catalogue.
  • 📦 Assortment and inventory research — merchandisers use variant_count, in_stock_variant_count and availability_ratio to see how deep a competitor's size/color matrix runs and how much of it is actually in stock.
  • 🔍 Dropship and supplier sourcing — resellers use sku_count, vendor and the per-variant sku inside variants[] to shortlist suppliers with full SKU coverage before reaching out.
  • 📊 Market and category analysis — analysts aggregate product_type, tags and price across many stores in one run to map price bands and category mix in a niche.
  • 🤖 AI agent and RAG pipelines — AI engineers feed title, product_type, tags and variants[] into a vector store or agent tool so an LLM can answer product questions or compare catalogues without re-scraping. The typed JSON output is a ready tool response for any agent framework that can call the Apify API.

How does Shopify Products Scraper handle rate limits and blocking?

Requests start on a direct connection with a jittered pacing gap between calls. A request that gets a soft-refusal status (403, 406, 407, 409, 429, 451, 500, 502, 503, 504) or no response at all is retried up to 4 attempts total, with capped exponential backoff (min(2^attempt + jitter, 8s)), and the connection steps up to Apify Proxy — first a datacenter tier, then residential — the first time a store pushes back. Once it steps up it stays up for the rest of the run; escalation is monotonic and shared across all concurrent requests to that run. A 404 or 401 is treated as deterministic (dead store / password-locked) and is never retried. If you set your own proxyConfiguration, that selection is used for every request instead of the automatic ladder.

If a store's catalogue can't be completed, whatever was already collected is still returned and the store's summary row reports partial_interrupted coverage rather than silently truncating with no explanation.


⬇️ Input

ParameterRequiredTypeDescriptionExample value
startUrlsYesarrayOne or more Shopify storefront addresses, e.g. https://tentree.com or https://nuts.com. A bare domain or a .myshopify.com address works too. Each store is scraped independently and gets its own coverage summary row.["https://tentree.com"]
maxItemsNointegerUpper limit on how many products to collect from each store. Minimum 1, maximum 100000, default 10. Set it above the store's catalogue size to collect everything.500
proxyConfigurationNoobjectOptional. Leave the default unless you need the run to go out through a specific Apify Proxy selection.{"useApifyProxy": false}

⚠️ Shopify's own catalogue-listing endpoint silently clamps any page-size request above 250 items back down to 250 — this Actor walks it page by page rather than requesting more at once, so it is never affected, but it's why maxItems values above a store's true size return everything the store has rather than erroring.

Example input

{
"startUrls": [
"https://tentree.com",
"https://nuts.com"
],
"maxItems": 500,
"proxyConfiguration": {
"useApifyProxy": false
}
}

⬆️ Output

Results land in the Actor's dataset as typed JSON, exportable as JSON, CSV, Excel, XML, RSS or HTML directly from Apify Console or via the API. Two row types share the same dataset, told apart by type. Only type: "product" rows are billed, under the row_result event — filter type == "store_summary" to see the free coverage rows, or type == "product" to see only what you were charged for.

Prices are always major-unit decimal strings ("45.00", not cents) — the Actor reads only the storefront surfaces that publish prices that way.

Example output

Product row (type: "product"):

{
"type": "product",
"is_child": false,
"store_url": "https://tentree.com",
"store_domain": "tentree.com",
"store_status": "ok",
"product_url": "https://tentree.com/products/treeblend-baker-t-shirt-cottage-red-heather",
"handle": "treeblend-baker-t-shirt-cottage-red-heather",
"product_id": 8462674067642,
"title": "TreeBlend Baker T-Shirt",
"vendor": "tentree",
"product_type": "Mens",
"tags": ["basics", "mens", "organic-cotton", "t-shirts-tanks"],
"price": "45.00",
"compare_at_price": null,
"price_min": 45.0,
"price_max": 45.0,
"price_varies": false,
"currency": "USD",
"discount_percent": null,
"is_on_sale": false,
"available": true,
"variant_count": 5,
"in_stock_variant_count": 5,
"out_of_stock_variant_count": 0,
"availability_ratio": 1.0,
"sku_count": 5,
"variants": [
{
"variantId": 46195127550138,
"title": "COTTAGE RED HEATHER / S",
"sku": "TCM1869-6298-S",
"barcode": "661814898315",
"price": "45.00",
"priceValue": 45.0,
"compareAtPrice": null,
"currency": "USD",
"available": true,
"inventoryQuantity": null,
"inventoryPolicy": null,
"option1": "COTTAGE RED HEATHER",
"option2": "S",
"option3": null,
"position": 1,
"grams": 400,
"weight": 400.0,
"weightUnit": "g",
"requiresShipping": true,
"taxable": true,
"createdAt": "2026-07-24T16:29:11-07:00",
"updatedAt": "2026-08-08T02:58:27-07:00"
}
],
"options": [
{ "name": "Color", "position": 1, "values": ["COTTAGE RED HEATHER"] },
{ "name": "Size", "position": 2, "values": ["S", "M", "L", "XL", "XXL"] }
],
"option_names": ["Color", "Size"],
"image_count": 3,
"featured_image": "https://cdn.shopify.com/s/files/1/2341/3995/files/tree_blend_baker_2.jpg",
"image_urls": [
"https://cdn.shopify.com/s/files/1/2341/3995/files/tree_blend_baker_2.jpg"
],
"created_at": "2026-07-24T16:29:11-07:00",
"updated_at": "2026-08-08T02:58:27-07:00",
"published_at": "2026-08-04T07:00:03-07:00",
"detail_enriched": true,
"scraped_at": "2026-08-08T14:21:09Z"
}

Store coverage summary row (type: "store_summary") — always exactly one per store, including stores that returned nothing:

{
"type": "store_summary",
"is_child": false,
"store_url": "https://tentree.com",
"store_domain": "tentree.com",
"store_status": "ok",
"status_detail": "Catalogue read successfully.",
"catalogue_coverage": "complete",
"catalogue_total": 412,
"products_returned": 412,
"variant_total": 1863,
"detail_enriched_count": 412,
"currency": "USD",
"sku_coverage_percent": 97.31,
"inventory_coverage_percent": 41.06,
"scraped_at": "2026-08-08T14:22:47Z"
}

store_status on the summary row is one of ok, password_protected, no_published_products, catalogue_unavailable, not_shopify, store_not_found or unreachable. catalogue_coverage is one of complete, limited_by_max_items, partial_interrupted or none. catalogue_total is populated only when catalogue_coverage is complete — if maxItems cut the run short, the store's true size is unknown and is reported as null rather than guessed.


How does it work?

Shopify Products Scraper calls the same JSON endpoints a browser loads when it visits a storefront — the catalogue listing (/products.json, paginated 250 products at a time, up to 400 pages) and, for every product found, the individual product record (/products/<handle>.json) that fills in barcode, inventory quantity and currency. No browser is launched and no JavaScript is rendered — these are direct HTTP calls against Shopify's own public data surfaces. Requests start on a direct connection and only route through Apify Proxy if the store pushes back; only publicly visible data is ever returned, nothing behind a password or admin login. Because every store publishes this feed in the same shape, the output schema stays the same regardless of which storefront theme a store is running.


Integrations

Shopify Products Scraper works with the tools you already use for automation and analysis — no plugin required, since it's just an Apify Actor reachable over the standard Apify API.

Calling Shopify Products Scraper programmatically

from apify_client import ApifyClient
client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("scraper-engine/shopify-products-scraper").call(run_input={
"startUrls": ["https://tentree.com"],
"maxItems": 500,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
print(item["title"], item.get("price"))

Works in Go, Ruby, Node.js, cURL — any language that can make an HTTP request against the Apify API.

No-code tools (n8n, Make, LangChain)

In n8n, use the HTTP Request node pointed at the Actor's run-sync-get-dataset-items endpoint with your API token, or the dedicated Apify node if you have it installed. In Make, the Apify app's "Run an Actor" module accepts the same startUrls / maxItems input and returns the dataset items to the next module. In LangChain, the ApifyWrapper / Apify Actor tool can call this Actor and load its dataset directly as Document objects for a retrieval pipeline.


Scraping publicly available product data is generally lawful — this Actor returns only what any visitor's browser can already load from a storefront, without bypassing a login, password or paywall. Product catalogues, prices and SKUs are business/product data, not personal data, so GDPR and CCPA do not attach to this Actor's output; the relevant frameworks instead are a store's terms of service and database-rights protections that may apply to a compiled catalogue in some jurisdictions. Consult legal counsel if your use case involves bulk storage or redistribution of a store's catalogue data.


Frequently asked questions

What Shopify product fields does Shopify Products Scraper return?

The top fields are title, price (with price_min/price_max), variants (SKU, per-variant price and stock), tags and available. See What data can I extract above for the full field tables.

Does Shopify Products Scraper require a Shopify account or login?

No. It reads the storefront's public catalogue feed exactly as a browser would — no Shopify account, API key or store login is needed. A store locked behind a store password cannot be read; that's reported as password_protected rather than silently returning nothing.

How many products can I extract in one run?

Up to maxItems per store (max 100000). Each store is crawled to completion, maxItems, or the point where the catalogue feed stops answering — whichever comes first — and the coverage summary row tells you which one happened.

What happens if a product's detail record can't be fetched?

The product still comes back from the catalogue listing with detail_enriched: false. Fields only available on the detail record — barcode, inventoryQuantity, weight, and the currency sourced from that record — are null for that product, while everything from the catalogue surface (price, stock, options, images) is still populated.

Can I scrape multiple Shopify stores at once?

Yes. startUrls accepts an array of storefront addresses; each store is scraped independently in the same run and gets its own summary row, so one problem store never blocks the rest.

Does Shopify Products Scraper work with Claude, ChatGPT and other AI agent tools?

Yes, as an HTTP endpoint any agent framework can call through the Apify API — the JSON output is typed and consistent, so it drops straight into a tool call or RAG pipeline without extra parsing.

What makes Shopify Products Scraper different from a basic Shopify catalogue scraper?

It returns the full variant array on every product — not just one headline price — with SKU, price and stock per variant, and it reports an honest store status (password_protected, catalogue_unavailable, not_shopify, etc.) instead of returning an empty result when a store can't be read.

Does Shopify Products Scraper return data in a format LLMs can use directly?

Yes. Typed, normalized JSON with consistent field names across runs — no HTML parsing, no selectors. Pass it directly to an LLM, index it into a vector store, or feed it to an agent tool.

What happens when Shopify changes a store's layout or theme?

The catalogue feed this Actor reads is Shopify's own stable JSON data surface, not the rendered storefront page, so a theme or layout change on the store doesn't change the output schema. No specific update turnaround is published for anti-bot changes on Shopify's side.

Can I use Shopify Products Scraper without managing proxies or browser infrastructure?

Yes. There's no browser to configure — requests are direct HTTP calls — and connection escalation through Apify Proxy happens automatically if a store pushes back, with no proxy setup required unless you want to pick a specific configuration yourself.

Which fields work best for AI training data and RAG indexing?

For RAG, index title, product_type, tags and vendor as descriptive text alongside variants[] for structured lookups. For training data, price, variant_count, sku_count and availability_ratio are the most consistently structured numeric fields across every row. All fields return as typed primitives — strings, numbers, booleans or arrays — never mixed types.


ScraperWhat it extracts
Shopify Merchant ScraperB2B lead sheet per store — merchant identity, emails, phones, social profiles, product/collection counts and tech stack
Shopify Store ScraperStore-level profile — identity, theme, installed apps, catalogue size, collection count and price range
Shopify ScraperProduct data pulled from a store's homepage, collection pages or single product pages
Amazon Product Details ScraperProduct details from Amazon listing pages
eBay Product Listing ScraperProduct data from eBay search and listing pages
Amazon Price TrackerAmazon prices, ratings, reviews, sellers and stock

Your feedback

Found a bug, or missing a field you need from a Shopify store's catalogue? Open an issue on this Actor's Issues tab in Apify Console — that's the fastest way to reach the maintainer directly.