# WooCommerce Store Products Scraper - Any Store, Full Catalog (`fabrikit/woocommerce-store-products-scraper`) Actor

Export the full product catalog of any WooCommerce store from its public REST API: titles, SKU, prices, sale prices, stock, categories, tags, images, attributes and every variation with its own price and stock. Optional price and stock change tracking. From US$0.50 per 1,000 products.

- **URL**: https://apify.com/fabrikit/woocommerce-store-products-scraper.md
- **Developed by:** [Fabrikit](https://apify.com/fabrikit) (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.50 / 1,000 product scrapeds

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

## WooCommerce Store Products Scraper - Any Store, Full Catalog

Export the **complete product catalog of any WooCommerce store**: title, SKU, price, regular and sale price, stock status, categories, tags, brand, images, attributes and **every variation** with its own price, SKU and stock. Paste a domain, a category URL or a product URL. No login, no API key.

It uses the public **WooCommerce Store API** that stores expose by default (`/wp-json/wc/store/v1/products`), 100 products per request, so it is fast and cheap. If a store turned that API off, it falls back to the WordPress product feed (`/wp-json/wp/v2/product`, titles, links, dates, categories, image, but no prices because WordPress does not expose them there).

**Price: US$0.50 per 1,000 records.** The output uses the same field names as our Shopify product scraper, so mixed Shopify + WooCommerce monitoring is one schema. It can also run as a **price and stock monitor** (Changes mode).

### What you get

- Full catalog of one or many stores in a single run, automatic pagination.
- Scope by store, category URL (`/product-category/...`), category name/slug/id, search keyword, or single product URL. Stores installed in a sub-folder are found automatically; sites that block `/wp-json` are tried through `?rest_route=`.
- Prices converted from the API's minor units into real numbers, with `currency`, `price`, `compareAtPrice` (regular price when on sale), `minPrice` / `maxPrice`.
- Variations for variable products (`variants[]` with `id`, `sku`, `price`, `compareAtPrice`, `available`, `options`).
- One record per product, or **one row per variation** for spreadsheets.
- `createdAt` / `updatedAt` from the WordPress feed when the store exposes it.
- **Non-WooCommerce sites are detected** and reported per store (`not_woocommerce`, `wordpress_no_woocommerce`, `woocommerce_restricted`, `empty`, `blocked`).
- Works with Apify datacenter proxy and switches to residential automatically if a store rate-limits or blocks.

### Input

| Field | Description |
|---|---|
| `stores` | Domains or URLs, one per line. |
| `mode` | `catalog` (default) or `changes`. |
| `categories`, `searchQuery`, `onlyOnSale`, `onlyInStock` | Filters. |
| `flattenVariants` | One row per variation. |
| `includeVariations`, `includeDates` | Extra requests that enrich variable products / add dates (on by default). |
| `maxItems`, `maxItemsPerStore` | Result caps (default 50). |
| `includeDescription`, `includeDescriptionHtml` | Add the long description. |
| `listCategories` | Save the store's category tree to the key-value store (`CATEGORIES_<domain>`), free. |
| `changeTrackingStoreName`, `emitBaseline` | Changes mode settings. |
| `proxyConfiguration` | Apify proxy (default datacenter, automatic residential fallback). |

Example:

```json
{
  "stores": ["nutribullet.com", "https://yithemes.com/product-category/plugins/"],
  "maxItems": 500
}
```

### Output example

```json
{
  "store": "nutribullet.com",
  "storeName": "nutribullet",
  "productId": 1037584,
  "handle": "nutribullet-turbo-chill-bundle",
  "title": "Turbo & Chill Bundle",
  "sku": "ECOM01684-PDP",
  "type": "variable",
  "vendor": null,
  "productType": "Bundles",
  "categories": [
    "Bundles"
  ],
  "tags": [
    "1000 watts",
    "24oz"
  ],
  "createdAt": "2026-09-29T23:15:14Z",
  "updatedAt": "2026-10-13T07:01:41Z",
  "publishedAt": "2026-09-29T23:15:14Z",
  "url": "https://www.nutribullet.com/shop/bundles/nutribullet-turbo-chill-bundle/",
  "images": [
    "https://nbmedia.imgix.net/FwKE4J1f-NBA30350AMZ_CrispLite-Vision-Air-Fryer_Black_Ecomm_PDP-1_Config_1500x1201.jpg?auto=compress%2Cformat&ixlib=php-3.3.0"
  ],
  "attributes": [
    {
      "name": "Color",
      "values": [
        "Matte Black",
        "Matte White"
      ]
    }
  ],
  "options": [
    {
      "name": "Color",
      "values": [
        "Matte Black",
        "Matte White"
      ]
    }
  ],
  "available": false,
  "stockStatus": "outofstock",
  "lowStockRemaining": null,
  "onSale": true,
  "price": 224.99,
  "compareAtPrice": 299.98,
  "minPrice": 224.99,
  "maxPrice": 224.99,
  "currency": "USD",
  "rating": 0,
  "reviewCount": 0,
  "variantCount": 2,
  "variants": [
    {
      "id": 1037586,
      "sku": "ECOM01685",
      "title": "Matte White",
      "price": 224.99,
      "compareAtPrice": 299.98,
      "available": false,
      "options": {
        "Color": "Matte White"
      },
      "image": "https://nbmedia.imgix.net/NBA30350AMZ_CrispLite-Vision-Air-Fryer_White_Ecomm_PDP-1_Config_1500x1201.jpg?auto=compress%2Cformat&ixlib=php-3.3.0"
    }
  ],
  "dataSource": "store-api",
  "scrapedAt": "2026-10-13T17:16:12.929Z"
}
```

With `flattenVariants`, each variation becomes a record with `variantId`, `variantTitle`, `variantOptions`, `variantImage`, and `sku`, `price`, `compareAtPrice`, `available` of that variation.

### Price and stock change tracking

Set `mode` to `changes` and schedule the actor. The first run saves a compact snapshot in a **named key-value store** (`changeTrackingStoreName`) and outputs nothing (turn on `emitBaseline` to also get the catalog). Later runs output only `new`, `removed` and `changed` products, with `changes: [{variantId, sku, field, from, to}]` for price, regular price, stock, added/removed variations and title. You pay only for output records.

### Pricing

| Event | Price |
|---|---|
| Record saved (`product-result`) | US$0.50 per 1,000 |

Plus the small standard Apify actor-start event.

### FAQ

**Which stores work?** Any WooCommerce store whose Store API is on (default since WooCommerce 7). Stores protected by a firewall that blocks API calls may need the residential proxy (automatic fallback).

**Why are some prices missing?** Only in fallback mode (`dataSource: "wp-rest"`): WordPress itself does not publish prices; stores that disabled the Store API give no price data to anyone.

**Does it return stock quantities?** Only `stockStatus` (in stock / out of stock / on backorder) and `lowStockRemaining` when the store shows it.

### Use cases

Price monitoring, catalog backups and migrations, competitor assortment research, marketplace feeds, product data for analytics.

***

### En espanol

Exporta el **catalogo completo de cualquier tienda WooCommerce** usando su API publica: titulo, SKU, precio, precio de oferta, stock, categorias, imagenes, atributos y todas las variaciones con su propio precio y stock. Pega un dominio, una categoria o un producto. Sin login ni API key. Detecta sitios que no son WooCommerce. Mismo formato que nuestro scraper de Shopify. Modo **cambios** para monitorear precios y stock. Precio: US$0,50 por 1.000 registros.

# Actor input Schema

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

WooCommerce store domains or URLs, one per line. A store URL scrapes the whole catalog; a category URL (https://store.com/product-category/shoes/) scrapes only that category; a product URL (https://store.com/product/my-shirt/) scrapes one product. Stores in a sub-folder (store.com/shop) are found automatically.

## `mode` (type: `string`):

Catalog: export every product. Changes: compare with the previous run of the same store (kept in a named key-value store) and output only new, removed and price/stock-changed products.

## `flattenVariants` (type: `boolean`):

Output one record per variation (product fields repeated on each row; sku, price and stock are the variation's) instead of one record per product with a variants array. Counts every variation as one result. Ignored in Changes mode.

## `maxItems` (type: `integer`):

Total records to save across all stores (products, or variants when 'One row per variant' is on).

## `maxItemsPerStore` (type: `integer`):

Optional cap for each store, useful when you list many stores.

## `categories` (type: `array`):

Only these categories (slug, name, id or category URL). Applies to the whole run for each store.

## `searchQuery` (type: `string`):

Only products matching this keyword (uses the store's own search).

## `onlyInStock` (type: `boolean`):

Skip products that are out of stock. Ignored in Changes mode.

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

Skip products that are not on sale. Ignored in Changes mode.

## `includeVariations` (type: `boolean`):

For variable products, also load every variation with its own SKU, price, sale price and stock (1 extra request per ~20 variable products).

## `includeDates` (type: `boolean`):

Add createdAt/updatedAt from the WordPress feed (1 extra request per 100 products). Skipped automatically if the store hides it.

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

Add the product description as plain text.

## `includeDescriptionHtml` (type: `boolean`):

Add the original description HTML.

## `listCategories` (type: `boolean`):

Save each store's categories (id, name, slug, parent, product count, URL) to a key-value store record named CATEGORIES\_<domain>. Free, not counted as results.

## `changeTrackingStoreName` (type: `string`):

Name of the key-value store that remembers the previous run. Use the same name on every scheduled run; use a different name to track a separate watch-list.

## `emitBaseline` (type: `boolean`):

By default the first Changes run only stores the baseline and outputs nothing. Turn this on to also get every product (marked changeType 'baseline').

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

Most stores answer datacenter IPs. If a store rate-limits or blocks, the actor automatically switches to a residential proxy for the rest of the run.

## Actor input object example

```json
{
  "stores": [
    "nutribullet.com"
  ],
  "mode": "catalog",
  "flattenVariants": false,
  "maxItems": 50,
  "onlyInStock": false,
  "onlyOnSale": false,
  "includeVariations": true,
  "includeDates": true,
  "includeDescription": false,
  "includeDescriptionHtml": false,
  "listCategories": false,
  "changeTrackingStoreName": "woocommerce-store-products-snapshots",
  "emitBaseline": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

All records collected during 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": [
        "nutribullet.com"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("fabrikit/woocommerce-store-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": ["nutribullet.com"],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("fabrikit/woocommerce-store-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": [
    "nutribullet.com"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call fabrikit/woocommerce-store-products-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,fabrikit/woocommerce-store-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/wWDBeAVxLFxtUk6ZN/builds/8pJgSSFbGCcJnFvfv/openapi.json
