# Shopify & WooCommerce Products Scraper (`brii3343/shopify-woocommerce-products-scraper`) Actor

Scrape products, variants, prices, SKUs and stock from any Shopify or WooCommerce store, and page by page from other stores. Paste store, collection, category or product links, get one clean format. Whole catalogs in seconds, no proxy needed. $0.50 per 1,000 products.

- **URL**: https://apify.com/brii3343/shopify-woocommerce-products-scraper.md
- **Developed by:** [Brian Gastaldelli](https://apify.com/brii3343) (community)
- **Categories:** E-commerce, Developer tools, 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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 & WooCommerce Products Scraper — any store, one format

Scrape **products, variants, prices and stock** from Shopify and WooCommerce stores, and from other online stores page by page, with **the same fields for every store**. Paste store links (or just domains), collection, category or product links, mixed, and get the whole catalog: SKU, barcode, price, compare-at price, availability, options, images, weight. No login, no browser, no proxy to set up.

#### Why this Actor

- **Two platforms, one dataset.** Shopify and WooCommerce run a large share of the world's online stores. Mix them in one run and get one table for price monitoring, catalog research or a product feed.
- **Fast and complete.** Shopify: 250 products per request. WooCommerce: 100 products per request, with every variant's price, SKU and stock. Six whole stores (1,065 products) matched the product count each store declares.
- **Also works where others stop.** Headless Shopify stores (Fashion Nova, Gymshark), WooCommerce stores with the product feed turned off, and other platforms are read page by page from the store's product sitemap, using the product data each page publishes for Google.
- **Checked against the real product pages.** 30 products from 15 stores compared with their pages: prices, currencies, SKUs and stock identical on all 30.
- **Reliable.** Direct connection, polite pace, automatic retries, and Apify Proxy only if a store blocks the run. Broken cookies, invisible characters in answers and moved sitemaps are handled.
- **Fair price:** $0.90 per 1,000 products from Shopify and WooCommerce feeds on the Starter plan, less on higher plans. Error rows are free.

#### Use cases

- **Price monitoring and repricing**: follow competitors' prices, discounts and stock every day.
- **E-commerce research**: whole catalogs of brands and niches, with vendors, product types, tags and launch dates (Shopify).
- **Dropshipping and marketplaces**: product data, images, variants and barcodes for sourcing and listings.
- **Market and trend analysis**: new products, price changes, out-of-stock items across hundreds of stores.
- **AI and data teams**: clean product data for embeddings, matching and training sets.

#### Input

| Field | Description |
|---|---|
| Store, collection or product links | Mixed, one per line. Home page or domain (`allbirds.com`) = the whole catalog; collection (`/collections/…`) or category (`/product-category/…`) page = only those products; product page = that product. |
| Max products per link | Default 100; 0 = every product. |
| One row per variant | One row for each size, color… with its own SKU, barcode, price and stock, instead of one row per product with a `variants` list. You still pay per product. |
| Proxy | Not needed: the Actor switches to Apify Proxy by itself when a store blocks it. |

Example:

```json
{
  "startUrls": [
    { "url": "https://www.allbirds.com" },
    { "url": "https://www.kelty.com/collections/backpacks" },
    { "url": "https://godinguitars.com" }
  ],
  "maxProductsPerUrl": 0,
  "variantRows": false
}
```

#### Output

One item per product, same fields for every store (real example, shortened):

```json
{
  "platform": "shopify",
  "storeUrl": "https://www.allbirds.com",
  "storeName": "Allbirds",
  "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",
  "categories": [],
  "tags": ["allbirds::gender => womens", "allbirds::material => sugar"],
  "price": 25,
  "priceMax": 25,
  "compareAtPrice": 50,
  "onSale": true,
  "currency": "USD",
  "available": true,
  "sku": "A12513W050",
  "description": "Sun on your feet. Comfort underneath. Light, easy, and made for warm weather…",
  "image": "https://cdn.shopify.com/s/files/1/1104/4168/files/A12513_26Q2_Allbirds-Flip-Flop-Dusty-Pink_PDP_LEFT.png?v=1774646345",
  "options": [{ "name": "Size", "values": ["5", "6", "7", "8", "9", "10", "11"] }],
  "variantCount": 7,
  "variants": [
    {
      "id": "42146889039952",
      "title": "5",
      "sku": "A12513W050",
      "barcode": null,
      "price": 25,
      "compareAtPrice": 50,
      "available": false,
      "options": { "Size": "5" },
      "weight": 0.455,
      "weightUnit": "kg",
      "inventoryQuantity": null,
      "image": null
    }
  ],
  "rating": null,
  "reviewCount": null,
  "createdAt": "2026-03-27T14:03:50-07:00",
  "updatedAt": "2026-09-28T20:07:24-07:00",
  "publishedAt": "2026-09-25T16:58:13-07:00",
  "source": "https://www.allbirds.com",
  "position": 1,
  "scrapedAt": "2026-09-29T03:07:24.620Z"
}
```

| Field | Meaning |
|---|---|
| `platform` | `shopify`, `woocommerce` or `other` (read from the product page). |
| `price`, `priceMax` | Lowest and highest variant price, in `currency`. `compareAtPrice`: the crossed-out price of the cheapest variant, when on sale. |
| `available` | True if at least one variant can be bought. Each variant has its own `available`. |
| `vendor` | Shopify vendor, WooCommerce brand, or the page's brand. |
| `categories`, `tags` | WooCommerce categories and tags; Shopify tags (Shopify has no public categories: use `productType` or collection links). |
| `options`, `variants` | Options (size, color…) with their values, and every variant with SKU, barcode, price, stock and weight. Simple products have one variant. |
| `rating`, `reviewCount` | WooCommerce reviews, or the page's rating. |
| `createdAt`, `updatedAt`, `publishedAt` | Shopify dates. |
| `source`, `position`, `scrapedAt` | The link you entered, the product's rank for that link, and when it was scraped. |

With **One row per variant**, each row also has `variantId`, `variantTitle`, `variantOptions`, `barcode`, `weight` and `inventoryQuantity`.

Rows with a `status` are not products and are **not charged**:

| Status | Meaning |
|---|---|
| `not_found` | The website, product, collection or category does not exist. |
| `unsupported` | Not a Shopify or WooCommerce store and its pages have no product data, or the page you gave is not a product page. |
| `blocked` | The store refused every connection, including Apify Proxy. |
| `unavailable` | The store is password-protected. |
| `no_results` | The collection or category is empty. |
| `invalid_input` | Not a web address. |
| `error` | The store kept failing; products saved before the error are kept. |

#### Tested (September 2026, on the Apify platform)

| Test | Result |
|---|---|
| Default input (Allbirds + Godin Guitars, 20 each) | 40 products in about 3 seconds |
| 20 products from 10 Shopify and WooCommerce stores vs their product pages | Prices, currencies, SKUs and stock 20 / 20 identical |
| 10 products read page by page (5 stores without a public feed) vs their pages | 10 / 10 identical |
| Whole catalogs of 6 stores (1,065 products) | 100% of the declared count, all distinct |
| Collection, category and product links | Only that collection's or category's products; a variable product with its 54 variants, all priced |
| 33 stores never seen before (21 WooCommerce, 12 Shopify brands) | 31 with products; 2 clear rows (one store blocks everyone, one has no product data) |
| Wrong inputs (not a store, unknown domain, missing product or collection) | Clear free rows, run succeeds |

#### Honest limits

- **Shopify lists at most 25,000 products per store or collection** (100 pages of 250). For bigger stores, add collection links: each collection has its own 25,000.
- **`title` is the product's name in the store's data.** A few stores show a shorter name on the page.
- **A Shopify collection may count more products than it shows**: products not published on the online store are not visible to anyone, so they are not scraped.
- **WooCommerce prices are those of the store's own feed**, with or without tax as the store is set up (UK stores usually include VAT).
- **Page-by-page reading depends on the store's pages.** It needs a product sitemap (for home page links) and product data in the page (schema.org, which most stores publish for Google). Prices are in the currency the page shows to a US visitor.
- **Big retailers with strong bot protection** (Amazon, Walmart, Zalando…) are not supported.

#### Pricing

- **$0.90 per 1,000 products** from Shopify and WooCommerce feeds on the Starter plan, down to **$0.70** on Business (`product` event; the Pricing tab shows the price for your plan).
- **$3 per 1,000 products read from their web page** (`product-page` event, $0.003 each): stores without a public feed and product page links from other platforms. Reading full pages costs more than a feed.
- A small start fee per run ($0.00005). Status rows are free. Set a maximum charge in the run options and the Actor stops there, saving only the products paid for.

# Actor input Schema

## `startUrls` (type: `array`):

Links to online stores, mixed: the home page (or just the domain, like <code>allbirds.com</code>) for the whole catalog, a collection or category page for that collection only, a product page for one product. Shopify and WooCommerce stores are read from their public product feed. Other stores (headless Shopify, WooCommerce with the feed turned off, other platforms) are read page by page: from their product sitemap when you give the home page, or from the product page links you add.

## `maxProductsPerUrl` (type: `integer`):

Limit for each link. 0 = every product of the store or collection.

## `variantRows` (type: `boolean`):

Output one row for each variant (size, color…) with its own SKU, barcode, price and stock, instead of one row per product with a <code>variants</code> list. You still pay per product.

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

Not needed: the scraper connects directly and switches to Apify Proxy only if a store blocks it. Set a proxy here only to force one.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.allbirds.com"
    },
    {
      "url": "https://godinguitars.com"
    }
  ],
  "maxProductsPerUrl": 20,
  "variantRows": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One item per product (or per variant): title, brand, price, sale price, currency, stock, SKU, barcode, variants, images, description, categories, tags, store.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.allbirds.com"
        },
        {
            "url": "https://godinguitars.com"
        }
    ],
    "maxProductsPerUrl": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("brii3343/shopify-woocommerce-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 = {
    "startUrls": [
        { "url": "https://www.allbirds.com" },
        { "url": "https://godinguitars.com" },
    ],
    "maxProductsPerUrl": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("brii3343/shopify-woocommerce-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 '{
  "startUrls": [
    {
      "url": "https://www.allbirds.com"
    },
    {
      "url": "https://godinguitars.com"
    }
  ],
  "maxProductsPerUrl": 20
}' |
apify call brii3343/shopify-woocommerce-products-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,brii3343/shopify-woocommerce-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/mOnOq4OM0MaymByJH/builds/JW2VFVEyE8UHrlShu/openapi.json
