How to Scrape Shopify Products to CSV
Every public Shopify store exposes a product catalog that is good enough to shop from — and, if you are careful and respectful, good enough to research. Price monitoring, assortment analysis, affiliate catalogs and competitor scoring all start from the same question: can I get this store's products, variants, prices and stock into a CSV? This guide shows how, without a Shopify admin login.
You will use the Shopify Product Scraper on Apify. Point it at a store or a collection URL and export titles, vendors, types, tags, prices, compare-at prices, discount percent, availability, variants, SKUs and images. You can choose one row per product or one row per variant (size, colour, SKU).
By the end of this article you will have a CSV or JSON file on your machine, and a short Python snippet you can rerun or schedule. The same Actor is also callable from JavaScript and from AI agents through the Apify MCP server.
What you need
- An Apify account. The Free plan is enough to try a small run.
- A list of inputs for the Actor (URLs, IDs or search terms — details in the steps below).
- Optional: Python 3 with the
apify-clientpackage if you want to automate the run.
The Actor reads the store's public catalog (including the well-known products.json feed when the merchant leaves it available). You do not need the merchant's password or an admin API token.
How to run it in the Apify Console
Step 1: Open the Actor
Open https://apify.com/veenkes/veenkes-shopify-products and click Try for free.
Step 2: Paste store URLs
A homepage such as https://colourpop.com works. A /collections/... URL limits the run to that collection.
Step 3: Choose row shape and a market
Use product rows for a catalog overview, or variant rows for price and stock monitoring. Set the country if you need market-specific currency and pricing.
Step 4: Run and export CSV
Cap max products on the first run. When the dataset is ready, export CSV or JSON. Turn on descriptions only if you need the body copy.
Only available skips sold-out items. Updated since is the right filter for incremental monitoring so you are not re-exporting an unchanged catalog every day.
How to run it from Python
Install the official client and call the Actor by its Store id veenkes/veenkes-shopify-products. Replace YOUR_APIFY_TOKEN with a token from Apify Console > Integrations. Do not commit the token to a public repository.
pip install apify-client from apify_client import ApifyClient client = ApifyClient("YOUR_APIFY_TOKEN") run = client.actor("veenkes/veenkes-shopify-products").call(run_input={ "stores": [ "https://colourpop.com" ], "maxProductsPerStore": 100, "outputLevel": "product" }) # Write every dataset item, then export from the Console or keep going in code. for item in client.dataset(run["defaultDatasetId"]).iterate_items(): print(item) The JavaScript client (apify-client on npm) uses the same Actor id and the same input object. You can also start the run with a plain HTTP POST to the Apify API if you prefer.
Sample output
Here is a shortened example of one dataset record (field values are illustrative of the schema, taken from a real sample run shape):
{ "store": "https://www.tentree.com", "storeName": "Tentree", "collection": null, "productId": 8143544320186, "title": "Lookout Long Puffer", "handle": "lookout-long-puffer-forest-pine", "url": "https://www.tentree.com/products/lookout-long-puffer-forest-pine", "vendor": "tentree", "productType": "Womens", "tags": [ "back-to-school", "best-sellers", "bogo-tote" ], "currency": "USD", "market": "US", "createdAt": "2025-06-06T10:20:29-07:00", "publishedAt": "2026-11-11T14:23:07-07:00", "updatedAt": "2026-11-12T14:01:32-07:00", "imageUrl": "https://cdn.shopify.com/s/files/1/2341/3995/files/Green-Cloud-Shell-Long-Puffer-TCW3532-5590_11.jpg?v=1749230441", "price": 348, "priceMax": 348, "compareAtPrice": null, "discountPercent": null, "available": true, "variantsCount": 5, "options": [ { "name": "Color", "values": [ "FOREST PINE" ] }, { "name": "Size", "values": [ "XS", "S", "M" ] } ], "variants": [ { "id": 44905051095226, "title": "FOREST PINE / XS", "sku": "TCW3532-5590-XS", "price": 348, "compareAtPrice": null, "available": false }, { "id": 44905051127994, "title": "FOREST PINE / S", "sku": "TCW3532-5590-S", "price": 348, "compareAtPrice": null, "available": false }, { "id": 44905051160762, "title": "FOREST PINE / M", "sku": "TCW3532-5590-M", "price": 348, "compareAtPrice": null, "available": false } … } Once the run has finished, open the dataset in the Console and use Export > CSV if a spreadsheet is your destination. JSON is usually better for code and for language models.
What to use the data for
Brands track competitors' prices and discounting. Retail analysts map an assortment by vendor and product type. Affiliate and comparison sites keep a fresh product file with images and canonical URLs. Because variant mode is one row per SKU, restock and price-change jobs are straightforward to schedule.
Pricing
Pay-per-result pricing starts at $1.00 per 1,000 products on the Apify Free plan, with lower unit prices on paid Apify plans, plus a small per-run start fee. Always check the live pricing on the Actor page, because plans and unit prices can change. For a first test, keep the input tiny so you can inspect the schema before you scale up.
Scheduling and automations
In the Apify Console you can schedule the Actor (daily or hourly) and leave the same input in place. For incremental jobs, prefer a "since" or "posted after" style filter when the Actor offers one, so you are not paying to re-collect old rows. When a run finishes you can send a webhook, or connect the Actor in Zapier, Make or n8n. AI agents can discover and call veenkes/veenkes-shopify-products through Apify's MCP server using the same input.
Good practices and limits
Only scrape public storefront data, and respect the merchant's terms and robots rules. Do not use this to copy a store's creative assets or descriptions into a competing shop. Some merchants disable public JSON endpoints; results then depend on what the storefront still exposes. The Actor is not affiliated with Shopify.
If a run returns fewer rows than you expected, check the input caps, language or country filters, and the Actor log. A zero-row run is usually a filter or an unavailable source, not a silent crash — read the log before you increase limits.
Next step
Open the Actor and run a small job: Shopify Product Scraper: Prices, Variants & Stock.
If you later want this on a schedule, save the input that worked, add a date filter where it applies, and export CSV automatically from the dataset or from the API snippet above.
