Shopify Products Scraper With Variant & SKU Rows
Pricing
from $2.99 / 1,000 results
Shopify Products Scraper With Variant & SKU Rows
Shopify Products Scraper With Variant & SKU Rows extracts Shopify product data with each variant and SKU as separate rows, including titles, prices, inventory, options, images, product URLs, and merchant details. Ideal for product research, price monitoring, and catalog analysis.
Pricing
from $2.99 / 1,000 results
Rating
0.0
(0)
Developer
SimpleAPI
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
0
Monthly active users
2 days ago
Last modified
Categories
Share
Shopify Product Scraper β Variant Rows, SKUs, Price and Stock
Pull a public Shopify storefront's catalogue and get one row per variant / SKU, not one row per product β each carrying its own sku, barcode, price, compareAtPrice, currency and available flag, with the store's option names (Color, Size) joined to that variant's option values. Alongside it you get a product roll-up row with the full option matrix, variant counts, availabilityRatio, skuCoverage and a true priceMin/priceMax range. Built for price monitoring, dropshipping research, PIM/ERP feeds and catalogue audits. Point it at one storefront or fifty and every store lands in the same dataset schema.
π§ What is Shopify Products Scraper With Variant & SKU Rows?
It reads a Shopify storefront's own public JSON endpoints β the catalogue listing and each product's detail page β and turns them into structured dataset rows: a product-level summary row and, for every purchasable variant, its own SKU-level row with the option matrix already joined. No Shopify account, app installation or API key is required from you; the Actor reads the same public endpoints a browser loads when it visits the store.
- Discovery by explicit storefront URL β you supply the store addresses (full URL, bare hostname, or
.myshopify.comdomain); the Actor walks the whole public catalogue behind each one, page by page, with duplicates removed. - Core identifying fields on every variant β
sku,barcode,price,compareAtPrice,currency,available, joinedoptionNames/optionValues. - Stock and price roll-ups on the product row β
variantCount,inStockVariantCount,availabilityRatio,skuCoverage,inventoryCoverage,priceMin/priceMax/priceVaries. - Descriptive and temporal fields β
vendor,productType,tagsText,publishedAt/createdAt/updatedAton the product row;variantCreatedAt/variantUpdatedAton the variant row. - Real filters exposed as input β row shape (
rowsPerVariant,includeParentProductRow), field-group selection (variantFields), and volume caps (maxProducts,maxVariantsPerProduct). - Export formats β results land in an Apify dataset and export to JSON, CSV, Excel (XLSX) or XML from the Console, or via the API/
apify_client.
π What data can I extract with Shopify Products Scraper With Variant & SKU Rows?
Every product and every variant/SKU on the storefronts you list, plus store-level run status when a storefront can't be read.
| Field | Row type | Example value | Use case |
|---|---|---|---|
productTitle | product, variant | "Death Wish Coffee - Ground" | Catalogue identity |
handle | product, variant | "death-wish-coffee-ground" | Stable product key / URL slug |
sku | variant (identity) | "DWC-GRND-12OZ" | Matching to your own catalogue |
barcode | variant (identity) | "0850002505016" | GTIN/UPC lookups |
optionNames / optionValues | variant (options) | ["Size"] / ["12oz"] | Filtering by size/colour/grind |
price / compareAtPrice | product, variant | 19.99 / 24.99 | Price and discount monitoring |
currency | product, variant | "USD" | Multi-currency comparison |
available | product, variant | true | In-stock filtering |
priceIsOutlier | variant | false | Excluding placeholder/draft prices |
inventoryQuantity | variant (stock) | 42 or null | Numeric stock level, where published |
variantCount / availabilityRatio | product | 12 / 0.75 | Assortment and stock-health scoring |
priceMin / priceMax / priceVaries | product | 14.99 / 29.99 / true | Product-level price range |
vendor / productType / tagsText | product | "Death Wish Coffee" / "Coffee" / "bold, dark-roast" | Category and brand segmentation |
catalogueTotal / catalogueComplete | product | 183 / true | Confirming the full catalogue was read |
storeUrl / productUrl | product, variant | "https://deathwishcoffee.com" / ".../products/death-wish-coffee-ground" | Source links |
π° Price, stock and availability signals
priceMin/priceMax/priceVaries are computed from in-stock variants only, skipping flagged outliers (priceBasis records which basis was actually used, falling back to "all_variants_no_stock" when nothing is in stock). hasPriceOutlier/priceOutlierCount on the product row and priceIsOutlier on each variant row flag prices that are β€ 0 or implausibly large relative to the product's own price band β flagged, never silently dropped. inventoryQuantity is only published by a minority of storefronts; where it isn't, the field is null, never a fabricated 0, and the product row's inventoryCoverage reports the real fraction of that store's variants that carried a number. Use this to build a stock-health or price-integrity check across a supplier catalogue before you trust it for repricing.
π Vendor, category and catalogue-scope signals
vendor, productType and tagsText are the fields you segment a catalogue by β brand mix, category distribution, tag-based collections. optionsMatrix/optionCount expose the raw option structure (names, positions, possible values) behind every variant. storeStatus, statusDetail, catalogueTotal and catalogueComplete tell you whether a given store's catalogue was actually read in full, so a comparison across several storefronts isn't silently skewed by one store that failed partway through.
βοΈ Why not build this yourself?
Shopify's public catalogue endpoint (/products.json) is what every storefront exposes by default, but pulling a clean, comparable dataset from it β across variants, across stores β is more than a single fetch call. Shopify's own Storefront and Admin APIs, by contrast, require an access token issued from inside the target store's own admin (per Shopify's authentication documentation, checked 2026-08-15) β so they aren't an option at all for reading a competitor's or supplier's catalogue you don't operate.
Building a reliable version of what this Actor does yourself means handling, per store:
- Pagination and dedup β the public endpoint returns at most 250 products per page (
LIST_PAGE_SIZEin this Actor); you have to loop pages, detect stores that echo an earlier page instead of ending the catalogue, and know when you've genuinely reached the end. - Two different money encodings β the catalogue and detail endpoints report price as a decimal string; a lighter payload some stores expose reports integer cents. Mixing the two up silently produces a 100x pricing error that still "validates" as a number.
- The option-name join Shopify doesn't do for you β variants carry
option1/option2/option3values with no labels; the names live separately on the product'soptionsarray and have to be joined by position. - Telling "no products" apart from "storefront is password-gated or headless" β both can return HTTP 200; only one is a real empty catalogue.
- Retry and blocking behaviour β this Actor retries retryable HTTP statuses (403, 429, 5xx, and others) up to 4 times with jittered exponential backoff, escalating the connection route on repeated failures, before giving up on a store.
If you already have your own store's Admin API credentials and only need your own catalogue, the official API is the right tool. If you need a consistent, pre-joined, per-SKU dataset across storefronts you don't administer, that's what this Actor is for.
π‘ How to use data extracted from Shopify?
π¦ Dropshipping and product sourcing
Point the Actor at several supplier storefronts with rowsPerVariant on, then filter the output to available: true and priceIsOutlier: false. Each surviving row already carries sku, price, compareAtPrice and the joined optionValues you need to build a listing β no manual join between a product export and a separate variant export.
π’ Agencies tracking client or competitor catalogues
Run the same storefront list on an Apify schedule and compare availabilityRatio, skuCoverage and catalogueComplete run over run. A dropping availabilityRatio or a growing variantCount on a client's or competitor's store is visible without opening the storefront by hand.
π Market research and assortment analysis
Run several competing Shopify brands in one job and aggregate priceMin/priceMax/priceVaries by vendor and productType to map price bands and assortment depth across a category β all in one dataset schema, regardless of which store each row came from.
π€ AI agents and automated pipelines
Feed the per-SKU rows into a PIM/ERP import, or give an agent structured sku/barcode/price/available context for inventory or repricing decisions, without the agent needing to parse raw Shopify JSON itself.
πΌ Input sample
| Parameter | Required | Type | Description | Example value |
|---|---|---|---|---|
storeUrls | No | array | Storefront addresses to read, one per line. Full URL, bare hostname or myshopify address all work; duplicates are removed. | ["https://deathwishcoffee.com"] |
startUrls | No | array | Backward-compatible alias for storeUrls. Used only when storeUrls is empty. | [] |
rowsPerVariant | No | boolean, default true | Turn a product with 56 variants into 56 rows instead of one. Each variant row carries its own SKU, option values, price, compare-at price and stock flag. | true |
includeParentProductRow | No | boolean, default true | Keep the one-row-per-product summary alongside the variant rows. | true |
variantFields | No | array (enum: identity, options, shipping, stock, dates) | Which extra field groups each variant row carries. | ["identity", "options", "shipping", "stock", "dates"] |
maxVariantsPerProduct | No | integer, min 0, default 0 | Cap variant rows per product. 0 = no cap. The product roll-up still reports the true total in variantCount. | 0 |
maxProducts | No | integer, min 0 | Maximum products to read per storefront. 0 = whole catalogue. When the key is omitted entirely the Actor uses 100. | 25 |
maxItems | No | integer, min 0 | Backward-compatible alias for maxProducts. Used only when maxProducts is empty. | β |
proxyConfiguration | No | object (Apify Proxy) | How requests reach the storefront. Default works for most stores. | { "useApifyProxy": false } |
JSON input example
{"storeUrls": ["https://deathwishcoffee.com", "https://lootcrate.com"],"rowsPerVariant": true,"includeParentProductRow": true,"variantFields": ["identity", "options", "shipping", "stock", "dates"],"maxVariantsPerProduct": 0,"maxProducts": 25,"proxyConfiguration": { "useApifyProxy": false }}
Common pitfall: maxProducts has a Console prefill of 25, but that is only the visual default in the input form β if the key is left out of a JSON input file entirely (rather than set to a value), the Actor falls back to 100, matching the actor's earlier default behaviour. Set it explicitly if you need a specific cap. Also note: if both rowsPerVariant and includeParentProductRow are turned off, the Actor re-enables includeParentProductRow automatically and logs a warning, so a run never returns zero rows by accident.
π½ Output sample
Every pushed row β product, variant, and store-status rows alike β is charged under the row_result event, including a status row for a storefront that couldn't be read. Export formats are the standard Apify dataset options: JSON, CSV, Excel (XLSX) or XML.
Product roll-up row (type: "product", isChild: false)
{"type": "product","isChild": false,"storeUrl": "https://deathwishcoffee.com","productId": 6800433512541,"handle": "death-wish-coffee-ground","productTitle": "Death Wish Coffee - Ground","productUrl": "https://deathwishcoffee.com/products/death-wish-coffee-ground","variantTitle": null,"sku": null,"optionNames": null,"optionValues": null,"optionsMatrix": [{ "name": "Size", "position": 1, "values": ["12oz", "5lb"] }],"optionCount": 1,"variantCount": 2,"inStockVariantCount": 2,"outOfStockVariantCount": 0,"unknownStockVariantCount": 0,"availabilityRatio": 1.0,"skuCoverage": 1.0,"inventoryCoverage": 0.5,"available": true,"priceMin": 19.99,"priceMax": 79.99,"priceVaries": true,"priceBasis": "in_stock_variants","currency": "USD","hasPriceOutlier": false,"priceOutlierCount": 0,"compareAtPrice": 24.99,"vendor": "Death Wish Coffee","productType": "Ground Coffee","tags": ["bold", "dark-roast"],"tagsText": "bold, dark-roast","publishedAt": "2021-03-01T12:00:00Z","createdAt": "2021-02-15T09:30:00Z","updatedAt": "2026-08-01T04:12:00Z","imageCount": 4,"storeStatus": "ok","statusDetail": "end_of_catalogue","catalogueTotal": 183,"catalogueComplete": true,"productsReturned": 1,"detailEnriched": true,"scrapedAt": "2026-08-15T10:03:11Z","store_url": "https://deathwishcoffee.com","product_url": "https://deathwishcoffee.com/products/death-wish-coffee-ground","product_id": 6800433512541,"title": "Death Wish Coffee - Ground","product_type": "Ground Coffee","price": "19.99","compare_at_price": "24.99","total_found": 183,"successful": 1,"full_data": { "product": { "...": "the raw Shopify product/detail payload" } }}
Note: on the product row,
priceandcompare_at_price(legacy snake_case fields) are the raw, unparsed values from the product's first variant β kept for backward compatibility. The normalized, computed figures arepriceMin/priceMax/compareAtPrice. On variant rows,priceandcompareAtPriceare the parsed, normalized floats. Don't mix the two conventions.
Variant / SKU row (type: "variant", isChild: true)
{"type": "variant","isChild": true,"storeUrl": "https://deathwishcoffee.com","variantId": 41067830870109,"parentProductId": 6800433512541,"parentHandle": "death-wish-coffee-ground","productId": 6800433512541,"handle": "death-wish-coffee-ground","productTitle": "Death Wish Coffee - Ground","productUrl": "https://deathwishcoffee.com/products/death-wish-coffee-ground","variantTitle": "12oz","price": 19.99,"compareAtPrice": 24.99,"currency": "USD","available": true,"priceIsOutlier": false,"scrapedAt": "2026-08-15T10:03:11Z","sku": "DWC-GRND-12OZ","barcode": "0850002505016","optionNames": ["Size"],"optionValues": ["12oz"],"position": 1,"weightGrams": 340,"weight": 0.34,"weightUnit": "kg","requiresShipping": true,"taxable": true,"inventoryPolicy": "deny","inventoryManagement": "shopify","inventoryQuantity": 42,"variantCreatedAt": "2021-02-15T09:30:00Z","variantUpdatedAt": "2026-08-01T04:12:00Z"}
The sku/barcode, optionNames/optionValues/position, weightGrams/weight/weightUnit/requiresShipping/taxable, inventoryPolicy/inventoryManagement/inventoryQuantity, and variantCreatedAt/variantUpdatedAt groups above only appear when their corresponding variantFields group (identity, options, shipping, stock, dates) is selected; all five are selected by default.
Store status row (type: "store_status", isChild: false)
Pushed instead of product/variant rows when a storefront's catalogue can't be read at all, or a run is interrupted partway through a store:
{"type": "store_status","isChild": false,"storeUrl": "https://example-closed-store.com","store_url": "https://example-closed-store.com","storeStatus": "store_not_found","statusDetail": "target_not_found","catalogueTotal": null,"catalogueComplete": false,"productsReturned": 0,"total_found": null,"successful": null,"scrapedAt": "2026-08-15T10:04:02Z"}
storeStatus is one of "ok" (product rows), "store_not_found", "catalogue_unavailable", "no_products_listed", or "not_completed" (run was interrupted). Filter type != "store_status" if you only want product/variant data β but remember these rows are still charged, so a run over a list with dead stores in it costs one row_result event per dead store too.
π― How do you filter and target specific product and variant rows?
This Actor doesn't take a search query or category β you point it at explicit storefront addresses and it reads the whole public catalogue behind each one. Targeting here means controlling row shape, volume and field width, not query scope:
- Row shape β
rowsPerVariantandincludeParentProductRoware independent toggles. Turn offincludeParentProductRowif you only want SKU-level rows for a repricing feed; turn offrowsPerVariantif you only want the product-level roll-up for a category overview. - Volume controls β
maxProductscaps how many products are read per storefront (0= whole catalogue);maxVariantsPerProductcaps how many variant rows a single product can produce without hiding the true count, which still lands invariantCounton the product row. - Field width β
variantFieldspicks which detail groups (identity,options,shipping,stock,dates) each variant row carries, so a run that only needs price and stock doesn't also pull weight and shipping fields.
{ "storeUrls": ["https://deathwishcoffee.com"], "rowsPerVariant": true, "includeParentProductRow": false, "variantFields": ["identity", "options"] }
{ "storeUrls": ["https://lootcrate.com"], "maxProducts": 0, "maxVariantsPerProduct": 3, "variantFields": ["identity"] }
{ "storeUrls": ["https://deathwishcoffee.com", "https://lootcrate.com"], "rowsPerVariant": false, "includeParentProductRow": true }
βΆοΈ Want to try other Shopify scrapers?
| Scraper | What it extracts |
|---|---|
| ../../Shopify-Merchant-Scraper/shopify-merchant-scraper-niche-and-keyword-store-search | Discovers Shopify stores by niche or keyword |
| ../../Shopify-Scraper/shopify-scraper-sales-channel-and-product-templates-data | Sales-channel and product-template metadata per store |
| ../../Shopify-Store-Scraper/shopify-store-scraper-markets-currencies-catalogs | Store-level markets, currency and catalogue configuration |
| ../../../amazon-product-details-scraper/amazon-product-details-scraper-bestsellers-and-new-releases | Comparable product-detail extraction on Amazon |
| ../../../eBay-Product-Listing-Scraper/ebay-product-listing-scraper-with-sold-price-data | Listing and sold-price data on eBay |
| ../../../walmart-reviews-scraper/walmart-reviews-scraper-with-seller-and-variant-details | SKU/variant-linked reviews on Walmart |
π How to extract Shopify data programmatically
This Actor runs like any Apify Actor β start it from the Console, on a schedule, via a webhook, or with a single REST/SDK call. No separate credential system: authenticate with your Apify API token.
Python example
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("<actor-id-from-this-actors-page>").call(run_input={"storeUrls": ["https://deathwishcoffee.com"],"rowsPerVariant": True,"maxProducts": 25,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():if item.get("type") == "variant" and item.get("available"):print(item["sku"], item["price"], item["optionValues"])
Export to spreadsheets or CRM
From the run's dataset, export directly to CSV or Excel and map columns straight across: sku β SKU, price/compareAtPrice β Price/List Price, optionNames+optionValues β Variant Attributes, available β In Stock, vendor β Supplier. No transformation needed β the keys already match a flat spreadsheet row.
βοΈ Is it legal to scrape Shopify?
Yes β this Actor reads product, price and stock data that a storefront already publishes openly to every visitor and search engine; it does not require logging in or bypassing any access control. This data is business/product catalogue information β prices, SKUs, stock, option values β not personal data about identifiable individuals, so it falls under the storefront's terms of service and general database-rights considerations rather than GDPR or CCPA, which govern personal data. Review the target storefront's terms of service before storing or republishing data at scale. Consult legal counsel for commercial applications involving bulk storage of scraped data.
β FAQ
How do I know if a product is discontinued or delisted?
The Actor doesn't mark historical state β it reports what a storefront returns right now. A product that has been removed simply stops appearing in catalogueTotal on the next run; compare handle values across runs to detect delistings. Within a single run, available (product and variant level) reflects current stock, not delisting.
Can I get stock and pricing data along with the SKU rows?
Yes β every variant row carries price, compareAtPrice, currency, available and priceIsOutlier by default, and enabling the stock field group adds inventoryQuantity, inventoryPolicy and inventoryManagement. inventoryQuantity is null on stores that don't publish numeric stock counts; check the product row's inventoryCoverage to see how much of that store's catalogue does.
How accurate is the price and stock data?
The Actor returns data exactly as it appears in the storefront's own public catalogue and product payloads at request time. Accuracy depends on how current the store keeps its own listings. For time-sensitive pricing decisions, re-run on a schedule rather than relying on a single snapshot.
How many rows can I get per run?
There's no fixed row cap in the Actor itself. maxProducts (default 100 if the key is omitted, 0 = whole catalogue) controls products read per store, and maxVariantsPerProduct (default 0 = no cap) controls variant rows per product. The public catalogue endpoint itself returns at most 250 products per page, which the Actor pages through automatically.
Can I run this against multiple storefronts in one job?
Yes β storeUrls accepts a list, and every store lands in the same dataset with the same row schema, distinguished by storeUrl. Each store is processed in sequence within the run.
Does Shopify Products Scraper With Variant & SKU Rows work with Claude, ChatGPT, and AI agent frameworks?
It's callable as a standard HTTP endpoint by any agent framework via the Apify API or apify_client β start a run, poll or wait for completion, and read the dataset. No actor-specific MCP integration is documented for this Actor.
Can I use this without a Shopify account or API key?
Yes. The Actor reads each storefront's own public JSON endpoints, the same ones a browser loads β no Shopify login, app installation, or API credentials are required from you. You only need an Apify account to run the Actor itself.
Conclusion
Shopify Products Scraper With Variant & SKU Rows turns a public storefront catalogue into a structured, per-SKU dataset β option names already joined to values, stock and price honestly flagged rather than guessed, and a product roll-up alongside every variant row. It's built for anyone who needs SKU-level Shopify data across one store or many, without writing a pagination-and-money-parsing layer first. Add your storefront URLs on the Actor's page in the Apify Console and run it to see the first rows land live.