# Shopify Products Scraper - Prices, Variants, Stock & Monitoring (`tinyrex/shopify-products-scraper`) Actor

Export all products from any Shopify store: prices, variants, SKUs, stock, images and discounts. Works on headless stores, monitors new products and price changes. Pay per product.

- **URL**: https://apify.com/tinyrex/shopify-products-scraper.md
- **Developed by:** [TinyRex](https://apify.com/tinyrex) (community)
- **Categories:** E-commerce, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 products

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Shopify Products Scraper: prices, variants, stock and monitoring

Export every product from any Shopify store: prices, discounts, variants (size, color), SKUs, stock status, images, tags and descriptions. Add store domains, collection URLs or product URLs and get clean, structured data in seconds. You pay only for the products you get.

**Why this one:** **$0.70 per 1,000 products**, cheaper than popular Shopify scrapers on the Store (about $1–10 per 1,000). Non-Shopify, blocked or password-protected stores and filtered-out products are **free**.

### Why this scraper

- **Fast and light.** It reads the public product feed that every Shopify store provides. No browser, so runs are quick and cheap.
- **Works on headless stores too.** Many big brands run a custom front end on top of Shopify. The scraper finds the store's `*.myshopify.com` domain and reads the feed from there, and switches to it automatically if the storefront starts blocking.
- **Large stores.** Shopify lists at most 25,000 products per listing. For bigger stores the scraper continues through the store's collections.
- **Monitoring built in.** Get only **new products**, or new products plus **price and stock changes** with the previous values, on every scheduled run.
- **Pay only for results.** Inputs that are not Shopify stores, password-protected or blocked stores, and products removed by your filters are **free**.
- **Stock quantity and barcode** (optional): added per variant when the store exposes them.

### What you get

| Field | Example |
|---|---|
| Store name, URL, currency, country | Allbirds, https://www.allbirds.com, USD, US |
| Product ID, handle, URL, title | 7205191974992, mens-dasher-nz, …/products/mens-dasher-nz, Men's Dasher NZ |
| Vendor, product type, tags | Allbirds, Shoes, \[mens, running] |
| Price, max price, compare-at price, discount % | 140, 160, 180, 22 |
| In stock, in-stock variants, variant count | true, 3, 13 |
| Options | Size: 8, 9, 10 … |
| Variants | id, title, SKU, price, compare-at price, available, options, weight |
| Images | main image + all image URLs |
| Dates | created, published, updated |
| Description | plain text or HTML |
| With the stock option | inventory quantity, inventory policy, barcode per variant, total inventory |
| In monitoring mode | change type, previous price, previous availability |

### How to use

1. Add stores to **Shopify stores, collections or products**:
   - a domain: `allbirds.com`
   - a collection: `https://www.allbirds.com/collections/mens`
   - a single product: `https://colourpop.com/products/lip-locked`
2. Optional filters: keywords, exclude keywords, vendors, product types, price range, only in stock, only on sale, published in the last N days.
3. Choose **one row per product** (variants nested) or **one row per variant** (flat, best for spreadsheets and price tracking).
4. Run, then download the results as JSON, CSV, Excel or HTML, or use them through the API, webhooks or integrations (Google Sheets, Make, Zapier, n8n, Slack).

#### Example input

```json
{
  "stores": ["deathwishcoffee.com", "https://www.allbirds.com/collections/mens"],
  "outputMode": "products",
  "onlyAvailable": true,
  "maxProductsPerStore": 500
}
```

#### Example output (shortened)

```json
{
  "storeName": "Allbirds",
  "currency": "USD",
  "productId": 7205191974992,
  "url": "https://www.allbirds.com/products/mens-dasher-nz-anthracite",
  "title": "Men's Dasher NZ - Anthracite (Dark Anthracite Sole)",
  "vendor": "Allbirds",
  "productType": "Shoes",
  "price": 140,
  "compareAtPrice": null,
  "onSale": false,
  "available": true,
  "availableVariants": 3,
  "variantsCount": 13,
  "options": [{ "name": "Size", "values": ["8", "8.5", "9"] }],
  "featuredImage": "https://cdn.shopify.com/s/files/1/1104/4168/files/...png",
  "variants": [{ "id": 41271176757328, "title": "8", "sku": "A12417M080", "price": 140, "available": false }],
  "publishedAt": "2026-08-24T09:53:01-07:00"
}
```

### Monitoring new products and price changes

Set **Monitoring mode** and schedule the Actor (for example daily):

- **Only new products:** each run returns products that were not seen before.
- **New products and price/stock changes:** also returns products whose price, compare-at price or availability changed, with `changeType`, `previousPrice` and `previousAvailable`.

The first monitoring run returns all matching products as the baseline. Use a different **State key** for each schedule or filter set. The state is stored in your account in the key-value store `shopify-products-state`.

### Run report

Besides the dataset, each run saves:

- **`STORES`**: one record per input with the status (`ok`, `not_shopify`, `blocked`, `password_protected`, `unreachable`, `not_found`), the method used (`direct` or `myshopify-fallback`), store name, currency and product counts.
- **`SUMMARY`**: totals for the run.

### Pricing

Pay per event:

- **Product** (`product`): one charge per row saved to your dataset (per product, or per variant in variant mode).
- **Stock details** (`inventory-details`): only with the stock option, and only for products where stock data was actually found.
- **Free:** stores that are not Shopify, blocked or password-protected stores, unreachable sites and filtered-out products.

See the *Pricing* tab for current prices. Set a maximum cost per run and the Actor stops gracefully when it is reached.

### Tips

- Use **variant mode** with **only on sale** to build a discount feed.
- Use a **collection URL** to scrape just one category of a big store.
- If a store returns `blocked`, or a run is slowed down by rate limiting (HTTP 429), try again with Apify Proxy (Advanced section).

### Limitations

- Only data the store publishes in its public storefront is available. Reviews, sales numbers and cost prices are not.
- Stock quantity is only available when the store exposes it. Many stores do not.
- Some headless stores hide their Shopify domain. These are reported as `not_shopify` or `blocked` and are not charged.
- For stores with more than 25,000 products, products that are not in any public collection can be missing.

### Use with AI agents (MCP)

This Actor works as a tool for AI agents through the **Apify MCP server** at `https://mcp.apify.com`. Connect Claude, Cursor, VS Code, n8n or any other MCP client to `https://mcp.apify.com?tools=tinyrex/shopify-products-scraper` and the agent can run it from a plain-language request, for example: *"Export all products under $50 from allbirds.com"*. Results come back as clean, structured JSON at the same pay-per-result price, and failed inputs stay free.

📘 **Step-by-step guide with Python, JavaScript, curl and MCP examples:** [How to export all products from any Shopify store to CSV or JSON](https://emirmrkaljevic.github.io/tinyrex-data-tools/export-shopify-store-products-to-csv/)

### Related actors

- [Tech Stack Detector](https://apify.com/tinyrex/tech-stack-detector): Have a list of domains? Find out which ones are Shopify stores first (use its `onlyIfUses` lead filter with `Shopify`), then feed them here.
- [WooCommerce Products Scraper](https://apify.com/tinyrex/woocommerce-products-scraper): The same product export for WooCommerce stores.
- [ATS Jobs Scraper](https://apify.com/tinyrex/ats-jobs-scraper): See which brands are hiring: jobs from Greenhouse, Lever, Ashby, Personio and more.
- [Workday Jobs Scraper](https://apify.com/tinyrex/workday-jobs-scraper): Jobs from enterprise Workday career sites.

### FAQ

**Is it legal?** The Actor reads public product data that Shopify stores publish for browsers, apps and search engines. It does not log in, does not access customer or order data, and does not bypass passwords. Use the data in line with the store's terms and your local law.

**How fast is it?** In our test, 30 stores with about 66,000 products took under 2 minutes. Speed depends on store size and response times.

**My store isn't recognized.** Pass the store's `xxx.myshopify.com` domain directly, or open an issue with the URL and we will take a look.

# Actor input Schema

## `stores` (type: `array`):

Store domains (allbirds.com), store URLs, collection URLs (https://store.com/collections/sale) or product URLs (https://store.com/products/handle). Headless stores are supported when their \*.myshopify.com domain can be found. Inputs that are not Shopify stores are skipped and not charged.

## `maxProductsPerStore` (type: `integer`):

Maximum number of products to save per input (after filters). 0 = all products.

## `outputMode` (type: `string`):

Product: one row per product with a nested variants list. Variant: one flat row per variant (size/color), easiest for spreadsheets and price tracking. One charge per row.

## `keywords` (type: `array`):

Keep only products whose title, vendor, product type or tags contain any of these words (case-insensitive).

## `excludeKeywords` (type: `array`):

Drop products whose title or tags contain any of these words.

## `vendors` (type: `array`):

Keep only products from these vendors (partial match).

## `productTypes` (type: `array`):

Keep only these product types (partial match), e.g. Shoes, Coffee.

## `minPrice` (type: `integer`):

Lowest variant price must be at least this (store currency). Leave empty for no limit.

## `maxPrice` (type: `integer`):

Lowest variant price must be at most this (store currency). Leave empty for no limit.

## `onlyAvailable` (type: `boolean`):

Keep only products with at least one variant available for sale.

## `onlyOnSale` (type: `boolean`):

Keep only products with a compare-at price higher than the price (discounted).

## `publishedWithinDays` (type: `integer`):

Keep only products published in the last N days. 0 = any time.

## `descriptionFormat` (type: `string`):

Product description as plain text, HTML, both, or none (smaller output).

## `includeInventory` (type: `boolean`):

Fetches each product page feed to add inventory quantity, inventory policy and barcode per variant, when the store exposes them. Slower (one extra request per product). Charged per product where stock data was found.

## `monitorMode` (type: `string`):

Off: return all matching products. New: only products not seen in previous runs. Changes: new products plus price, compare-at price or availability changes (with previous values). State is kept per store under the state key. The first monitoring run returns everything as the baseline.

## `stateKey` (type: `string`):

Name of the monitoring state. Use different keys for different schedules or filters.

## `maxConcurrency` (type: `integer`):

How many stores are processed at the same time. Pages of one store are fetched politely one after another.

## `proxyConfiguration` (type: `object`):

Usually not needed. Use a proxy if a store blocks requests (HTTP 403/429).

## Actor input object example

```json
{
  "stores": [
    "deathwishcoffee.com",
    "https://www.allbirds.com/collections/mens"
  ],
  "maxProductsPerStore": 0,
  "outputMode": "products",
  "keywords": [],
  "excludeKeywords": [],
  "vendors": [],
  "productTypes": [],
  "onlyAvailable": false,
  "onlyOnSale": false,
  "publishedWithinDays": 0,
  "descriptionFormat": "text",
  "includeInventory": false,
  "monitorMode": "off",
  "stateKey": "default",
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `products` (type: `string`):

Products with prices, variants, stock and images.

## `stores` (type: `string`):

For every input: status (ok, not_shopify, blocked, password_protected...), method, store name, currency, products found/saved, notes.

## `summary` (type: `string`):

Totals for the run.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "stores": [
        "deathwishcoffee.com",
        "https://www.allbirds.com/collections/mens"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tinyrex/shopify-products-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "stores": [
        "deathwishcoffee.com",
        "https://www.allbirds.com/collections/mens",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("tinyrex/shopify-products-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "stores": [
    "deathwishcoffee.com",
    "https://www.allbirds.com/collections/mens"
  ]
}' |
apify call tinyrex/shopify-products-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tinyrex/shopify-products-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/uiiWExB0eHdTURGb9/builds/STZxWT73Eqatutpj7/openapi.json
