# Shopify & WooCommerce Store Scraper ⚡ Products, Prices, Stock (`pulselab/shopify-woocommerce-scraper`) Actor

Extract all products from any Shopify or WooCommerce store: prices, discounts, availability, variants, images, dates. Plus one summary row per store (currency, country, total products, price stats, share on sale / sold out, top brands, theme). No login, no proxies. Pay per product.

- **URL**: https://apify.com/pulselab/shopify-woocommerce-scraper.md
- **Developed by:** [Pulse Lab](https://apify.com/pulselab) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 product 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

## Shopify & WooCommerce Store Scraper – Products, Prices, Stock, Store Info

Give it a list of **store URLs** and get back every product with prices, discounts, availability, variants and images – plus a **one-row summary per store** (currency, country, total products, price range, share on sale, share sold out, top brands, theme).

Works with **Shopify** stores (via the public `products.json` / `meta.json` endpoints) and **WooCommerce** stores (via the public Store API). No login, no API key, no proxies, no HTML scraping of product pages – so it is fast and reliable, and the data is exactly what the store publishes.

### What it does

1. **Detects the platform** for each URL: tries Shopify's `products.json`, then the WooCommerce Store API, then checks the homepage for platform signals.
2. **Checks `robots.txt`** of the store and skips stores that disallow the endpoint it would use (reported as `BLOCKED_BY_ROBOTS`, not charged).
3. **Fetches the catalog** page by page (250 products per request on Shopify, 100 on WooCommerce) and normalizes every product into one common row.
4. **Writes a store summary row**: platform, store name, currency, country/city (Shopify), total products and collections, price min / max / average / median, number and share of products on sale, average discount, share sold out, top brands / product types / categories / tags, newest product date, products added in the last 30 days, theme name, shipping countries, Shop Pay installments.

Optional: **inventory quantity per variant** (Shopify, via each product's `.js` endpoint), **descriptions**, and filters for **keywords**, **on sale**, **available** and **updated after a date** (new products / price changes since your last run).

### Use cases

- **Competitor price monitoring** – run daily with `updatedAfter` to catch price drops, new products and sell-outs.
- **Dropshipping & product research** – find what a store sells, which products are discounted, which are sold out, how many variants.
- **Lead generation / market research** – store summaries tell you size (product count), price positioning, platform and theme.
- **Catalog export** – pull a clean product list from any store for feeds, spreadsheets or comparison tools.

### Input

| Field | Description |
|---|---|
| `storeUrls` (required) | Store homepages or domains. Platform is auto-detected. |
| `maxProductsPerStore` | Max product rows saved per store (default 500, max 20,000). |
| `keywords` | Keep only titles containing one of these words. |
| `onlyOnSale` | Keep only discounted products. |
| `onlyAvailable` | Keep only products with at least one purchasable variant. |
| `updatedAfter` | Keep only products created/updated on or after this date (Shopify only – the WooCommerce Store API has no dates). |
| `includeDescription` | Also store the description (text + HTML). |
| `includeInventory` | Shopify only: fetch exact inventory quantity per variant (one extra request per product). |
| `includeStoreSummary` | Add the store summary row (default on). |

Example:

```json
{
  "storeUrls": ["allbirds.com", "https://colourpop.com", "kyliecosmetics.com"],
  "onlyOnSale": true,
  "maxProductsPerStore": 1000
}
```

### Output

Two dataset views:

**Products** – one row per product (`type: "product"`):
`platform, store, storeName, productId, title, handle, url, brand, productType, tags, categories, currency, price, priceMax, compareAtPrice, onSale, discountPercent, available, variantCount, availableVariantCount, totalInventory, variants[], images[], imageCount, mainImage, rating, reviewCount, createdAt, publishedAt, updatedAt, descriptionText, descriptionHtml, sku, stockStatus, onBackorder, checkedAt`

Each entry in `variants[]` has `id, title, sku, price, compareAtPrice, available, options[], inventoryQuantity, inventoryPolicy, grams`.

**Store summaries** – one row per store (`type: "store"`):
`store, status, platform, storeName, url, currency, country, city, province, myshopifyDomain, theme, productCount, collectionCount, productsFetched, productsMatched, priceMin, priceMax, priceAvg, priceMedian, onSaleCount, onSaleShare, avgDiscountPercent, availableCount, soldOutShare, topBrands[], topProductTypes[], topCategories[], topTags[], newestProductAt, latestUpdateAt, productsAddedLast30Days, shipsTo[], shopPayInstallments, checkedAt`

`status` values: `OK`, `PRODUCT_API_DISABLED` (platform detected but the public product endpoint is turned off – common for big "headless" brands), `BLOCKED_BY_ROBOTS`, `PLATFORM_NOT_FOUND`, `ERROR`, `INVALID_INPUT`.

Example product row (Shopify):

```json
{
  "type": "product",
  "platform": "shopify",
  "store": "gymshark.com",
  "storeName": "Gymshark US",
  "title": "Gymshark Leather Lifting Straps - Spiced Brown",
  "url": "https://gymshark.com/products/gymshark-leather-lifting-straps-equipment-brown-aw25",
  "productType": "Unisex>Accessories>Equipment>lifting_straps",
  "currency": "USD",
  "price": 19.6,
  "compareAtPrice": 28,
  "onSale": true,
  "discountPercent": 30,
  "available": true,
  "variantCount": 1,
  "availableVariantCount": 1,
  "variants": [{ "id": "39795354009802", "title": "Default Title", "sku": "I1B6R-NC52-OS", "price": 19.6, "compareAtPrice": 28, "available": true }],
  "imageCount": 3,
  "createdAt": "2025-01-20T16:04:31.000Z",
  "updatedAt": "2026-10-20T03:09:06.000Z"
}
```

Example store summary row:

```json
{
  "type": "store",
  "store": "colourpop.com",
  "status": "OK",
  "platform": "shopify",
  "storeName": "ColourPop",
  "currency": "USD",
  "country": "US",
  "productCount": 1063,
  "collectionCount": 190,
  "priceAvg": 26.83,
  "priceMedian": 16,
  "onSaleShare": 0,
  "soldOutShare": 3.33,
  "theme": "Colourpop/Main",
  "shipsTo": ["AD", "AE", "AF", "…", "ZW"]
}
```

### Pricing

Pay per event – you only pay for what is found:

- **product** – one product row saved
- **store** – one store summary row

Stores that are not Shopify/WooCommerce, have their product endpoint disabled, or disallow it in `robots.txt` are reported for free. Platform usage is included in the event price.

### Limitations (please read)

- Only stores whose **public product endpoint is enabled** return products. Large brands running custom "headless" storefronts (e.g. Fashion Nova, Tesla Shop) disable it – they come back as `PRODUCT_API_DISABLED`. The actor also tries the `www.` / non-`www.` variant of the domain, which is enough for some brands (e.g. `gymshark.com` works while `www.gymshark.com` is headless).
- Shopify prices are in the store's own currency (from `meta.json`); the WooCommerce Store API returns prices with their currency code. No currency conversion is done.
- `totalInventory` and variant `inventoryQuantity` are filled only with `includeInventory` (Shopify). Many stores hide exact quantities; `available` is always reliable.
- The WooCommerce Store API has no created/updated dates, so `updatedAfter` cannot filter WooCommerce products; `rating`/`reviewCount` exist only for WooCommerce.
- This actor respects `robots.txt`. If a store disallows the endpoint, nothing is fetched.

# Actor input Schema

## `storeUrls` (type: `array`):

Store homepages or domains (allbirds.com, https://shop.example.com). The platform (Shopify or WooCommerce) is detected automatically. Stores that disable their public product endpoint or disallow it in robots.txt are reported, not charged.

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

Upper limit of product rows saved (and charged) per store. The store summary still reports the store's total product count.

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

Keep only products whose title contains at least one of these words (case-insensitive). Leave empty for all products.

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

Keep only products with a compare-at / regular price higher than the current price.

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

Keep only products that currently have at least one purchasable variant (in stock).

## `updatedAfter` (type: `string`):

Keep only products created or updated on/after this date (YYYY-MM-DD) – handy for spotting new products and price changes. Shopify only (the WooCommerce Store API has no dates).

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

Also save the product description (plain text + HTML). Rows get larger.

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

Fetch each product's .js endpoint to get the exact inventory quantity per variant. One extra request per product, so large stores take longer.

## `includeStoreSummary` (type: `boolean`):

Add one summary row per store: platform, currency, country, total products, price range/average, share on sale, share sold out, top brands/types, newest product date, theme.

## Actor input object example

```json
{
  "storeUrls": [
    "allbirds.com",
    "https://colourpop.com",
    "kyliecosmetics.com"
  ],
  "maxProductsPerStore": 500,
  "keywords": [],
  "onlyOnSale": false,
  "onlyAvailable": false,
  "includeDescription": false,
  "includeInventory": false,
  "includeStoreSummary": true
}
```

# Actor output Schema

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

No description

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

No description

# 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 = {
    "storeUrls": [
        "allbirds.com",
        "https://colourpop.com",
        "kyliecosmetics.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("pulselab/shopify-woocommerce-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 = { "storeUrls": [
        "allbirds.com",
        "https://colourpop.com",
        "kyliecosmetics.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("pulselab/shopify-woocommerce-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 '{
  "storeUrls": [
    "allbirds.com",
    "https://colourpop.com",
    "kyliecosmetics.com"
  ]
}' |
apify call pulselab/shopify-woocommerce-scraper --silent --output-dataset

```

## MCP server setup

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