# Shopify Scraper: products, prices, variants and stock (`bepolabs/shopify-products`) Actor

Turn Shopify store domains into rows of sizes, colours, SKUs, discounts, tags and photos. Pick one row per item or per option, schedule daily runs, pay per result. Costs 0.8 USD per 1,000 rows.

- **URL**: https://apify.com/bepolabs/shopify-products.md
- **Developed by:** [BEPO Labs](https://apify.com/bepolabs) (community)
- **Categories:** E-commerce, Lead generation, Developer tools
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.80 / 1,000 rows

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

### 🛍️ What is Shopify Products?

Point it at allbirds.com or colourpop.com and Shopify Products returns each product with vendor, type, weight and dates from the Shopify store's own open feed (`/products.json`). No account, no setup.

- **Competitor price tracking**: schedule a daily run on rival stores and spot each change and new discount
- **Catalog and assortment research**: compare product types, vendors, variants and price ranges across many stores
- **Dropshipping and product sourcing**: find lines worth reselling and what they cost before you list them
- **Lead generation for Shopify agencies and apps**: size a store's catalog before you pitch: products, variants, vendors and tags
- **Feeds for AI and analytics**: load clean product data into Sheets, a database or an AI agent

![Shopify Products: Any Shopify store URL to every product, with variants, prices, sale prices, SKUs, stock and images.](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/shopify-products-hero.png)

#### ✨ Why use this Actor?

- ✅ **Every variant**: sizes, colours and bundles with their own SKU, regular and compare-at price, and stock status
- ✅ **Products or variants**: one entry per product with sizes and colours nested, or one flat line for each of them, ideal for spreadsheets
- ✅ **Sale prices included**: compare-at figures show which items are discounted and by how much
- ✅ **No proxy, no browser**: reads the public `/products.json` feed, 250 products at a time
- ✅ **Polite by design**: each store's robots.txt is checked first; retries with backoff on 429 and 5xx
- ✅ **One bad store never stops the run**: a store that is not on Shopify or blocks requests is reported in the run summary and costs nothing

### 📦 What data can you get with Shopify Products?

| | | |
|---|---|---|
| 🛍️ Product title and handle | 🔗 Product URL | 🏭 Vendor and product type |
| 🏷️ Tags | 💲 Lowest and highest price | 🔻 Compare-at (sale) price |
| 📦 In stock or sold out | 🧩 Variants, options and SKUs | ⚖️ Weight in grams |
| 🖼️ Main image and all images | 📅 Published and updated date | 📝 Description (optional) |

### 🚀 How to use Shopify Products

Shopify Products works in a few clicks, no coding needed:

1. [Create a free Apify account](https://console.apify.com/sign-up) (the free plan includes 5 USD of monthly credit).
2. Open [Shopify Products](https://apify.com/bepolabs/shopify-products) and click **Try for free**.
3. Paste one or more Shopify store URLs or domains and choose whether each product or each variant gets its own line.
4. Click **Start** and wait for the run to finish (most runs take seconds).
5. Download your data as JSON, CSV, Excel, XML or HTML, or send it straight to Google Sheets, Make, Zapier or your AI agent.

![How Shopify Products works](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/shopify-products-workflow.png)

### ⬇️ Input

Add up to 100 Shopify store URLs or domains. Everything else is optional.

##### Products or variants?

The default, `output: products`, gives one entry per product with its variants nested inside. With `output: variants` every size or colour is its own row, the easiest shape for spreadsheets and price tracking.

##### Big catalogs

`maxProductsPerStore` stops a store after that many products (default 1,000, up to 25,000). The store is read 250 products per page.

##### Which stores work?

Every Shopify store that keeps the default public `/products.json`, which is most of them. A store that is not on Shopify, has closed the feed or blocks requests is listed in the run summary with the reason.

| Field | Type | What it does | Default |
|---|---|---|---|
| **Stores** (`stores`) | array | Shopify store URLs or domains (allbirds.com, https://colourpop.com). | `["https://www.allbirds.com"]` |
| **One row per** (`output`) | string | products: one row per product with its variants nested. | `"products"` |
| **Max products per store** (`maxProductsPerStore`) | integer | Stops a store after this many products (250 per page). | `1000` |
| **Include description** (`includeDescription`) | boolean | Adds the product description as plain text. | `false` |
| **Max retries** (`maxRetries`) | integer | Retries per request with exponential backoff on network errors, 429 and 5xx. | `3` |

![Shopify Products input form](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/shopify-products-input.png)

#### Input example

```json
{
    "stores": [
        "https://www.allbirds.com"
    ],
    "maxProductsPerStore": 300
}
```

### ⬆️ Output

Every product (or every variant) becomes one row with the same fields. The run summary in the key-value store (`OUTPUT`) lists each store with its count and the error if it failed.

![Shopify Products output table](https://api.apify.com/v2/key-value-stores/wdeAWGooHdIhvFgSY/records/shopify-products-output.png)

#### Output example

One product row (Allbirds, lists shortened):

```json
{
    "store": "https://www.allbirds.com",
    "productId": 7340901859408,
    "title": "Women's Allbirds Flip Flop - Dusty Pink",
    "handle": "womens-allbirds-flip-flop-dusty-pink",
    "url": "https://www.allbirds.com/products/womens-allbirds-flip-flop-dusty-pink",
    "vendor": "Allbirds",
    "productType": "Shoes",
    "tags": [
        "allbirds::carbon-score => undefined",
        "allbirds::cfId => color-a4d5d0f6620dc304306f503bf67bc5f9",
        "allbirds::complete => true"
    ],
    "publishedAt": "2026-09-25T16:58:13-07:00",
    "updatedAt": "2026-10-15T23:16:38-07:00",
    "image": "https://cdn.shopify.com/s/files/1/1104/4168/files/A12513_26Q2_Allbirds-Flip-Flop-Dusty-Pink_PDP_LEFT.png?v=1774646345",
    "priceMin": 25,
    "priceMax": 25,
    "available": true,
    "variantCount": 7,
    "options": [
        {
            "name": "Size",
            "values": [
                "5",
                "6",
                "7",
                "8",
                "9",
                "10",
                "11"
            ]
        }
    ],
    "images": [
        "https://cdn.shopify.com/s/files/1/1104/4168/files/A12513_26Q2_Allbirds-Flip-Flop-Dusty-Pink_PDP_LEFT.png?v=1774646345",
        "https://cdn.shopify.com/s/files/1/1104/4168/files/A12513_26Q2_Allbirds-Flip-Flop-Dusty-Pink_PDP_BACK.png?v=1774646345"
    ],
    "variants": [
        {
            "variantId": 42146889039952,
            "variantTitle": "5",
            "sku": "A12513W050",
            "price": 25,
            "compareAtPrice": 50,
            "available": false,
            "options": [
                "5"
            ],
            "grams": 455
        },
        {
            "variantId": 42146889072720,
            "variantTitle": "6",
            "sku": "A12513W060",
            "price": 25,
            "compareAtPrice": 50,
            "available": false,
            "options": [
                "6"
            ],
            "grams": 492
        }
    ]
}
```

#### Variant row example

With `output: variants` (ColourPop, tags shortened):

```json
{
    "store": "https://colourpop.com",
    "productId": 7660291391570,
    "title": "Under the Mistletoe",
    "handle": "under-the-mistletoe-mickey-mouse-ultra-glossy-lip",
    "url": "https://colourpop.com/products/under-the-mistletoe-mickey-mouse-ultra-glossy-lip",
    "vendor": "ColourPop",
    "productType": "Ultra Glossy Lip",
    "tags": [
        "Collab",
        "collab:Disney",
        "lip-gloss",
        "new-arrival"
    ],
    "publishedAt": "2026-10-08T09:37:12-07:00",
    "updatedAt": "2026-10-15T23:16:41-07:00",
    "image": "https://cdn.shopify.com/s/files/1/1338/0845/files/MickeyandMinnieHoliday_LipGloss_UndertheMistletoe_ProductStylized_Red.jpg?v=1790100995",
    "variantId": 42736686465106,
    "variantTitle": "Default Title",
    "sku": "LipGloss-UndertheMistletoe",
    "price": 12,
    "compareAtPrice": 0,
    "available": true,
    "options": [
        "Default Title"
    ],
    "grams": 41
}
```

View the results as a table or JSON in the Output tab and download them as JSON, CSV, Excel, XML, HTML or RSS, all fields or only those you pick.

### 💰 How much does Shopify Products cost?

Shopify Products is priced **per event**: **0.8 USD per 1,000 rows** (0.0008 USD per row), with no monthly rental. Each item saved to the dataset counts once: a product, or a variant with `output: variants`. Stores that fail cost nothing, and there are no proxy costs on top.

| You get | You pay |
|---|---|
| 100 rows | 0.08 USD |
| 1,000 rows | 0.8 USD |
| 10,000 rows | 8 USD |
| 100,000 rows | 80 USD |

💡 Apify's free plan gives you 5 USD of credit every month, enough for about **6,250 rows** at no cost. Set a spending limit per run and the Actor stops there.

### ⚖️ Shopify Products vs. the alternatives

| | Shopify Products | Browser-based store scrapers | Paid price-tracking apps |
|---|---|---|---|
| **Every variant with SKU and sale price** | ✅ | varies | ✅ |
| **Row per product or per variant** | ✅ your choice | ❌ | ❌ |
| **No proxy or browser costs** | ✅ | ❌ | ✅ |
| **Many stores in one run** | ✅ up to 100 | ✅ | plan limits |
| **Pay per result, no subscription** | ✅ 0.8 USD per 1,000 rows | ✅ | ❌ monthly plans |

### 🔌 Integrations, API and MCP

#### Connect Shopify Products to your AI agent (MCP)

Give Claude, ChatGPT, Cursor or any MCP client direct access to Shopify Products through the [Apify MCP server](https://mcp.apify.com). Add this URL to its settings:

```text
https://mcp.apify.com/?actors=bepolabs/shopify-products
```

For Claude Desktop, add it under `mcpServers` in `claude_desktop_config.json`:

```json
{
    "mcpServers": {
        "shopify-products": {
            "command": "npx",
            "args": [
                "-y",
                "@apify/actors-mcp-server",
                "--actors",
                "bepolabs/shopify-products"
            ],
            "env": {
                "APIFY_TOKEN": "<your Apify API token>"
            }
        }
    }
}
```

Then ask: *"List every product of allbirds.com that is discounted, with its regular and reduced price."*

#### Run it from your code

Python (`pip install apify-client`):

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("bepolabs/shopify-products").call(run_input={"stores":["https://www.allbirds.com"],"maxProductsPerStore":300})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

JavaScript (`npm install apify-client`):

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('bepolabs/shopify-products').call({"stores":["https://www.allbirds.com"],"maxProductsPerStore":300});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### No-code integrations

Send results to **Google Sheets, Slack, Airtable, HubSpot, Make, Zapier, n8n** and more from the Integrations tab, start runs on a **schedule**, or trigger your own endpoint with a **webhook** when a run finishes. The [Apify API](https://docs.apify.com/api/v2) gives you full control over runs and datasets.

### ❓ FAQ

##### Does it work on every Shopify store?

On every store that keeps Shopify's default public `/products.json`, which is most of them. Some large stores close it or block datacenter traffic; those are named in the run summary and cost nothing.

##### How do I find discounted products?

Look at `compareAtPrice`: when it is higher than `price`, the item is on sale. In our Allbirds test run 139 of 300 products had at least one discounted variant.

##### How many rows will I get with output: variants?

One per size, colour or option combination. The 300 Allbirds products of our test run had 3,336 variants, so plan your cost with the variant count in mind.

##### Can I track prices over time?

Yes: schedule the Actor daily and compare `price` and `compareAtPrice` per `variantId` between runs, or send each run to Google Sheets.

##### Is stock quantity included?

The public feed says whether each variant is available (`available`), not how many units are left.

##### What happens when a store fails?

The other stores still run, the run summary names the failed store and why, and you are not charged for it. The run fails only if no store returned products.

##### Is it legal to use Shopify Products?

The Actor reads only the product feed a Shopify store serves to every visitor, checks the store's robots.txt first and stops where it disallows `/products.json`. It needs no Shopify account and collects no personal data: prices and products are public catalogue data. A merchant's own terms may limit how you reuse their content; you are responsible for how you use the data.

##### What if something is missing or does not work?

Open an issue on the **Issues** tab; we read each one and reply. Feature requests are welcome too.

### 💬 Your feedback

Tell us what Shopify Products should add on the **Issues** tab or leave a review; your notes decide what we work on next.

### 🔗 Related Actors

| Actor | What it does |
|---|---|
| 🎮 [Steam Scraper](https://apify.com/bepolabs/steam) | Game prices, details and player reviews from the Steam store, by app id, store URL or game name. |
| ⭐ [App Store Reviews](https://apify.com/bepolabs/app-store-reviews) | iOS App Store reviews with stars, text, app version and date, plus the app's rating and details, for any store country. |
| 🧩 [Chrome Web Store Scraper](https://apify.com/bepolabs/chrome-web-store) | Users, rating, version, last update, developer, category and permissions of any Chrome extension. |
| 📦 [npm and PyPI Package Data](https://apify.com/bepolabs/npm-pypi) | Versions, downloads, licences, maintainers and release history of npm and PyPI packages in one table. |
| 💼 [ATS Jobs](https://apify.com/bepolabs/ats-jobs) | Every open job from company career boards on Greenhouse, Lever, Ashby, Workable, SmartRecruiters and Recruitee in one deduped feed. |
| 🌐 [Domain RDAP and DNS](https://apify.com/bepolabs/domain-rdap) | Domains to registrar, creation and expiry dates, age, status, nameservers, DNSSEC and DNS records from official RDAP, in bulk. |
| 📧 [Email Verifier](https://apify.com/bepolabs/email-dns-check) | Bulk email validation over DNS: valid, risky or invalid per address, with the reasons, a score, a typo fix, throwaway and shared-inbox flags. |
| 📢 [Google Ads Transparency Scraper](https://apify.com/bepolabs/google-ads-transparency) | Every ad a company runs on Google, by domain, advertiser ID or name, from the Ads Transparency Center. |

# Changelog

This Actor's version history is a separate document: https://apify.com/bepolabs/shopify-products/changelog.md

# Actor input Schema

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

Shopify store URLs or domains (allbirds.com, https://colourpop.com). Up to 100.

## `output` (type: `string`):

products: one row per product with its variants nested. variants: one row per variant (price, SKU, stock) with the product fields repeated.

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

Stops a store after this many products (250 per page). Up to 25,000.

## `includeDescription` (type: `boolean`):

Adds the product description as plain text.

## `maxRetries` (type: `integer`):

Retries per request with exponential backoff on network errors, 429 and 5xx.

## Actor input object example

```json
{
  "stores": [
    "https://www.allbirds.com"
  ],
  "output": "products",
  "maxProductsPerStore": 1000,
  "includeDescription": false,
  "maxRetries": 3
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset items, one row per result, in the overview table view.

# 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": [
        "https://www.allbirds.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("bepolabs/shopify-products").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": ["https://www.allbirds.com"] }

# Run the Actor and wait for it to finish
run = client.actor("bepolabs/shopify-products").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": [
    "https://www.allbirds.com"
  ]
}' |
apify call bepolabs/shopify-products --silent --output-dataset

```

## MCP server setup

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

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/IWRlc9MogYgwccv7u/builds/ijdqn43sGunjJDR8C/openapi.json
