Shopify Products Scraper — Any Store, No Auth | $0.9/1K
Pricing
from $0.87 / 1,000 products
Shopify Products Scraper — Any Store, No Auth | $0.9/1K
Collect public Shopify product or variant records from a store's /products.json catalog. Get title, price, SKU, availability, and images. Run with store URLs and no Shopify login or API key. Pricing: $0.90 per 1,000 results on Free, plus Actor Start.
Pricing
from $0.87 / 1,000 products
Rating
0.0
(0)
Developer
Vitalii Bondarev
Maintained by CommunityActor stats
0
Bookmarked
8
Total users
2
Monthly active users
17 hours ago
Last modified
Categories
Features
Share
Shopify Products Scraper for Any Store
Scrape Shopify product catalogs from the public /products.json endpoint on a myshopify.com host or a custom domain. Each row is a product or one variant, and the run does not need a Shopify login or API key.
- Check competitor listing prices and the in-stock flag.
- Index vendors, product types, tags, and product URLs.
- Pull in-stock variant SKUs for a dropshipping supplier.
- Switch between one row per variant and one row per product.
What you get
The Actor reads public GET /products.json?limit=250&page=N and writes flat rows until a page returns an empty products array or maxProducts is reached for that store.
Default output is one row per variant. There is no currency field and no inventory-quantity field; stock is the boolean available.
| Family | Fields | Type | Notes |
|---|---|---|---|
| Store and product | store_domain, product_id, title, handle, vendor, product_type, tags | string, integer, string, string, string, string, list of strings | Requested host, Shopify product id, title, slug, vendor, store type, and tags normalized to a list. |
| Variant columns | variant_id, variant_title, price, compare_at_price, sku, available | integer or null, string or null, number or null, number or null, string or null, boolean or null | Current variant when one row per variant is on. Null in per-product mode, and null when the product has no variants. Prices are numbers parsed from the store price strings. |
| Nested catalog | options, variants, images | list, list, list of strings | On every row. Options are name plus values. Each variant object has variant_id, title, option1, option2, option3, sku, price, compare_at_price, available, grams, requires_shipping, and featured_image. Images are CDN URLs in position order. |
| Price span | price_min, price_max, compare_at_price_min, compare_at_price_max | number or null | Lowest and highest across that product's variants. Still set when the flat price column is null. |
| Links | image_url, product_url | string or null | First image, and https://<host>/products/<handle>. |
| Description | body_html | string or null | Raw HTML when description HTML is on. Otherwise null. |
| Timestamps | created_at, updated_at, published_at | string or null | Store ISO 8601 values, passed through. |
| Quality | parse_confidence, warnings | number, list of strings | Completeness score and warning codes. |
Quality score
A complete row scores 1. These codes reduce the score:
| Warning | What changes |
|---|---|
product_id_missing | Subtract 0.50 |
title_missing | Subtract 0.25 |
handle_missing | Subtract 0.10 |
created_at_missing | Subtract 0.05 |
no_variants | Subtract 0.20 more, only in per-variant mode when the product has no variants. The score is rounded to 3 decimals and does not go below 0. |
Sample output
One row from a successful run. The sample is shortened by omitting tags, options, variants, images, compare_at_price_min, compare_at_price_max, price_min, price_max, body_html, created_at, and updated_at. Values that remain are unchanged.
{"store_domain": "gymshark.myshopify.com","product_id": 6715692744907,"title": "Gymshark Power Washed Track Pants Short - Pitch Grey/Wash","handle": "gymshark-power-washed-track-pants-short-pants-grey-aw26","vendor": "Gymshark | Be a visionary.","product_type": "Womens>Apparel>Pants>wide_leg","variant_id": 39662273626315,"variant_title": "Large","price": 48,"compare_at_price": null,"sku": "B7B7S-GFPV-L","available": true,"image_url": "https://cdn.shopify.com/s/files/1/0098/8822/files/Power_Washed_Track_Pant_Short_GS_Pitch_Grey_WASH_B7B7S_GFPV_1.jpg?v=1789654609","product_url": "https://gymshark.myshopify.com/products/gymshark-power-washed-track-pants-short-pants-grey-aw26","published_at": "2026-10-29T19:00:00+00:00","parse_confidence": 1,"warnings": []}
Pricing
Billing is pay per event. Per-variant and per-product runs use the same Product price. A Product event is one saved dataset row. Filtered-out products and stores that save no rows do not add Product events. Actor Start is charged when the run starts, including a run that saves no rows. Its count is one event per GB of memory, with a minimum of one event.
product-item and variant-item have no price, so you are not charged for them.
| Plan | Actor Start (per event) | Product (per result) | 1,000 Product results |
|---|---|---|---|
| Free | $0.00005 | $0.0009 | $0.90 |
| Bronze | $0.0000495 | $0.000891 | $0.891 |
| Silver | $0.000049 | $0.000882 | $0.882 |
| Gold | $0.0000485 | $0.000873 | $0.873 |
| Platinum | $0.000048 | $0.000864 | $0.864 |
| Diamond | $0.0000475 | $0.000855 | $0.855 |
1,000 results = $0.90 on Free, plus one Actor Start event at $0.00005 on Free when memory is 1 GB or the one-event minimum. 10,000 results = $9 on Free.
The Apify Free plan includes $5 of monthly platform usage credit. After one Actor Start event, that credit covers 5555 Product results on Free.
On this pay-per-event Actor, platform usage (compute, Apify Proxy traffic including residential, and storage) is included in the event prices and paid by the Actor developer. This Actor does not use pay-per-event plus usage, so you do not pay those platform usage charges on top.
How to use
- Add one host or URL per Store URLs entry (
myshopify.comor a custom domain, with or withouthttps://). A path is dropped, the host is lowercased, and stores run in sequence. - Set Max products per store (default 100; 0 pages until a page returns no products).
- Leave One row per variant on for a row per SKU, or clear it for one row per product.
- Optionally add a case-insensitive handle or vendor substring. Leave description HTML on to keep
body_html. - Repeat with Apify Schedules. Daily is a reasonable starting point for price and availability checks; treat that cadence as a starting point only.
{"storeUrls": ["gymshark.myshopify.com"],"maxProducts": 10,"rowPerVariant": true,"includeBodyHtml": true,"proxyConfiguration": {"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]},"disableUsageStats": false}
Export the dataset as JSON or CSV, or read it through the Apify dataset API.
Input parameters
| Parameter | What it does | Default |
|---|---|---|
storeUrls | Hosts or URLs, scraped in order. Each becomes that host's products.json URL. A blank entry is skipped. | Empty. Form prefill: gymshark.myshopify.com and www.allbirds.com. |
maxProducts | Stops after this many products per store, before variant rows are built. 0 pages through every non-empty page of 250. Minimum 0. | 100 |
rowPerVariant | True writes one row per variant. False writes one row per product and leaves the six variant columns null. | true |
includeBodyHtml | True copies the store's body_html onto each row. False sets body_html to null. It does not change the row count. | true |
productHandleFilter | Keeps products whose handle contains this substring, case-insensitive. Blank keeps all. Applied after fetch, so it does not pull extra pages to fill the cap. | blank |
vendorFilter | Keeps products whose vendor contains this substring, case-insensitive. Blank keeps all. Same paging behavior as the handle filter. | blank |
proxyConfiguration | When set, requests use that Apify Proxy configuration. If proxy setup fails, the run logs a warning and continues without a proxy. | Omitted means no proxy. Form prefill: Apify Proxy, group RESIDENTIAL. |
disableUsageStats | True skips the usage-statistics record described under Usage statistics. | false |
Limits and edge cases
Note:
maxProductscounts products fetched per store, not dataset rows. Several variants on one product produce several rows when one row per variant is on.
Each products request uses a 30-second timeout. Pages are sequential, with no delay or concurrency input. A later-page failure saves nothing for that store and the run moves on; rows from stores that already finished stay. OUTPUT holds totalRows, rowPerVariant, scrapedAt (UTC), and stores (products_fetched and rows_pushed, or error and products 0).
| Condition | What you see | What to do |
|---|---|---|
storeUrls is missing or empty | Log warning. OUTPUT.error is no_store_urls. No dataset rows. | Add at least one host or URL. |
| Blank line in the URL list | That entry is ignored. Other stores still run. | Remove the blank line. |
| First page is an empty product list | Store finishes with products_fetched 0 and rows_pushed 0. No error key. | Confirm the host is the public storefront. |
| HTTP 404 | Log says the store was not found. OUTPUT error is store_not_found. No rows from that store. | Check the host, or that /products.json is public on it. |
| Any other fetch or transport error | Warning in the log. OUTPUT error is the message trimmed to 300 characters. Later stores still run. | Fix the host and run again. Earlier stores' rows remain. |
| Handle or vendor filter matches nothing | Products may be fetched while rows_pushed is 0. | Clear the filter or use a shorter substring. |
| Proxy setup throws | Warning that the run is proceeding without a proxy. | Continue, or set a valid Apify Proxy configuration. |
| Per-product mode | Flat variant columns are null. Use price_min, price_max, or variants for prices. | Turn one row per variant on when you need SKU rows. |
| Product has no variants in variant mode | One row, variant columns null, warning no_variants, confidence reduced by 0.20. | Treat that row as product-level only. |
FAQ
How much does it cost to scrape Shopify products?
See Pricing. A saved row is one Product event at that plan's price, the same in both row modes, plus Actor Start. Filtered-out products are not charged.
What if the dataset is empty?
Check OUTPUT for no_store_urls, products_fetched 0, rows_pushed 0, store_not_found, or error. Export rows already saved.
Why did one store fail while others succeeded?
Stores run in sequence. A timeout, a bad later page, or HTTP 404 drops that store only. If proxy setup fails, requests continue without a proxy.
Is reading this public Shopify data allowed under store ToS?
The Actor reads public /products.json and does not log in. Whether that use is allowed depends on the store's terms and the law that applies to your use case. This page does not say that your use is legal.
Note: This Actor is not affiliated with Shopify Inc.
Usage statistics
This Actor creates a small, content-free summary at the end of each run, used only to monitor reliability and improve this Actor. No input values, credentials or scraped data are sent.
A copy of the exact record for your run is saved as USAGE_STATS in your own Apify key-value store.
To opt out, set disableUsageStats to true in the input. Nothing is sent then.