# WooCommerce Product Scraper (`khadinakbar/woocommerce-product-scraper`) Actor

Scrape public WooCommerce product catalogs for price, stock, rating, and category monitoring. Use for competitor or supplier research, not private data. Returns normalized product rows with price, availability, reviews, and source provenance. $0.004/product plus a $0.00005 start fee; usage extra.

- **URL**: https://apify.com/khadinakbar/woocommerce-product-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.00 / 1,000 product returneds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## WooCommerce Product Scraper

WooCommerce Product Scraper is an Apify Actor for public WooCommerce catalogs. It accepts one or more store URLs and returns one normalized product record per dataset item. Each row can include product ID, title, canonical product URL, store URL and domain, source endpoint, price fields, sale status, stock status, review counts, categories, tags, attributes, variation count, image URLs, and scrape timestamp.

Use it for public competitor or supplier catalog research where published product data is the source of truth. The Actor works through the Apify platform and can also be invoked through Apify MCP for agent workflows that need structured WooCommerce catalog rows from known store URLs.

### Best fit and connected workflows

This Actor fits workflows that start from a public WooCommerce storefront and end with normalized product data ready for analysis.

Good routing patterns include:

- catalog monitoring for price, stock, and rating changes across known stores
- supplier assortment review from public product pages and store categories
- product discovery by text search, category IDs, sale status, featured status, or stock status
- agent pipelines that need a compact dataset row rather than raw HTML

Because this Actor returns one validated product row per dataset item, it works well when downstream steps expect predictable fields and provenance through `sourceEndpoint`.

### Practical scenario

Maya manages a merchandising dashboard and starts with two public store URLs plus a search phrase for a product family. She runs the Actor with `maxProducts` set to 50 and `stockStatuses` set to `instock`. The returned rows include `title`, `price`, `stockStatus`, `averageRating`, `reviewCount`, and `productUrl`. Maya uses the stock and review fields to shortlist products for a weekly assortment review, then opens the `productUrl` links for manual comparison.

### Input

The Actor accepts up to 100 public WooCommerce store URLs. It uses the public Store API and extracts published product data only.

#### Input fields

| Field | Type | Purpose |
| --- | --- | --- |
| `storeUrls` | array of strings | Public WooCommerce store URLs, including a homepage or a store in a subdirectory |
| `maxProducts` | integer | One run-wide product cap across all stores, from 1 to 10,000 |
| `search` | string | Public Store API search phrase for products |
| `categoryIds` | array of integers | Public WooCommerce category IDs to narrow the result set |
| `stockStatuses` | array of strings | Filter by `instock`, `outofstock`, or `onbackorder` |
| `onSale` | boolean | Filter to products marked on sale by the public Store API |
| `featured` | boolean | Filter to products marked as featured |
| `sortBy` | string | Sort field: `date`, `price`, `popularity`, or `rating` |
| `sortOrder` | string | Sort direction: `asc` or `desc` |
| `proxyConfiguration` | object | Optional Apify Proxy configuration for public Store API access |

#### Focused JSON input example

```json
{
  "storeUrls": [
    "https://porterandyork.com",
    "https://example.com/shop"
  ],
  "maxProducts": 100,
  "search": "organic coffee",
  "categoryIds": [12, 27],
  "stockStatuses": ["instock"],
  "onSale": true,
  "featured": false,
  "sortBy": "price",
  "sortOrder": "asc",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

### Output

The Actor writes one validated public WooCommerce product per dataset row. The default key-value store also contains `OUTPUT` and `RUN_SUMMARY` records for terminal outcome, counts, warnings, and charge details.

#### Output fields

| Field | Type | Purpose |
| --- | --- | --- |
| `productId` | string | Stable WooCommerce product ID |
| `title` | string | Published product name |
| `slug` | string or null | Store-provided product slug, when present |
| `productUrl` | string | Canonical public product URL |
| `storeUrl` | string | Normalized store URL supplied to the Actor |
| `storeDomain` | string | Store hostname without the `www` prefix |
| `sourceEndpoint` | string | Public WooCommerce Store API endpoint used as provenance |
| `sku` | string or null | Public SKU, when available |
| `productType` | string or null | WooCommerce product type |
| `description` | string or null | Plain-text product description |
| `shortDescription` | string or null | Plain-text short description |
| `currency` | string or null | ISO 4217 currency code |
| `currencyMinorUnit` | integer or null | Number of fractional digits used in price normalization |
| `price` | number or null | Current public price |
| `regularPrice` | number or null | Regular public price |
| `salePrice` | number or null | Sale public price |
| `onSale` | boolean | Whether the product is marked on sale |
| `purchasable` | boolean | Whether the product is purchasable |
| `inStock` | boolean | Whether the product is marked in stock |
| `onBackorder` | boolean | Whether the product is marked available on backorder |
| `stockStatus` | string | Normalized stock state |
| `lowStockRemaining` | integer or null | Public low-stock quantity, when exposed |
| `averageRating` | number or null | Published average rating |
| `reviewCount` | integer | Published customer review count |
| `catalogVisibility` | string or null | Store API visibility state |
| `isPasswordProtected` | boolean | Whether the product is password protected |
| `categories` | array of strings | Public category names |
| `tags` | array of strings | Public product tag names |
| `attributes` | array of objects | Public attribute dimensions and values |
| `variationsCount` | integer | Number of variation IDs returned |
| `imageUrl` | string or null | Primary product image URL |
| `imageUrls` | array of strings | Up to ten public product image URLs |
| `scrapedAt` | string | UTC timestamp for normalization |

#### Illustrative output record

```json
{
  "productId": "42",
  "title": "Organic Espresso Blend",
  "slug": "organic-espresso-blend",
  "productUrl": "https://example.com/product/organic-espresso-blend/",
  "storeUrl": "https://example.com",
  "storeDomain": "example.com",
  "sourceEndpoint": "https://example.com/wp-json/wc/store/v1/products?page=1&per_page=100",
  "sku": "ESP-500",
  "productType": "simple",
  "description": "A balanced medium-roast espresso blend.",
  "shortDescription": "Whole-bean espresso coffee.",
  "currency": "USD",
  "currencyMinorUnit": 2,
  "price": 19.99,
  "regularPrice": 24.99,
  "salePrice": 19.99,
  "onSale": true,
  "purchasable": true,
  "inStock": true,
  "onBackorder": false,
  "stockStatus": "instock",
  "lowStockRemaining": 3,
  "averageRating": 4.75,
  "reviewCount": 12,
  "catalogVisibility": "visible",
  "isPasswordProtected": false,
  "categories": ["Coffee"],
  "tags": ["Organic"],
  "attributes": [
    {
      "name": "Grind",
      "values": ["Whole bean", "Ground"]
    }
  ],
  "variationsCount": 2,
  "imageUrl": "https://cdn.example.com/product.jpg",
  "imageUrls": ["https://cdn.example.com/product.jpg"],
  "scrapedAt": "2026-07-14T12:00:00.000Z"
}
```

### How it works

For each store URL, the Actor requests the public WooCommerce Store API and normalizes the published product data into validated dataset rows. It applies the supported filters before pagination, follows the Store API pagination flow, and writes each validated product row together with source provenance.

The implementation uses direct HTTP requests by default. Apify Proxy can be enabled when a public Store API needs a proxy path. The Actor also writes outcome records to the default key-value store:

- `OUTPUT` for compact terminal outcome and product-count contract
- `RUN_SUMMARY` for per-store diagnostics and charge summary

### Pricing

This Actor uses Pay per event pricing plus Apify platform usage. The live Pricing tab on the Actor page is the place to review the current event charges and platform usage details.

The charged events are:

- Actor start
- Product returned

For example, a run that returns one hundred products includes one Actor start event and one hundred Product returned events, and the billed total also includes Apify platform usage. The exact amount is shown in the live Pricing tab and in the run cost breakdown.

### Use with AI agents (MCP)

This Actor is available as an Apify Actor usable through Apify MCP. It is a structured tool for agent workflows that need public WooCommerce catalog rows, provenance, and predictable product fields.

Actor identity: `khadinakbar/woocommerce-product-scraper`

> Pull the public WooCommerce catalog for `https://porterandyork.com`, keep the result set to 25 products, return only items in stock, and summarize the returned price, rating, review count, and source endpoint for each product.

How to interpret the output:

- each dataset item represents one validated public product row
- `sourceEndpoint` shows the public Store API endpoint used as provenance
- `productUrl` points to the canonical public product page
- `stockStatus`, `price`, `regularPrice`, `averageRating`, and `reviewCount` are ready for downstream sorting or comparison
- pagination follows the Store API flow until the run reaches `maxProducts`
- billing tracks the Actor start event and each Product returned event, plus Apify platform usage

### Apify API example

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

const client = new ApifyClient({
  token: process.env.APIFY_TOKEN,
});

const input = {
  storeUrls: ["https://porterandyork.com"],
  maxProducts: 10,
  search: "coffee",
  stockStatuses: ["instock"],
  sortBy: "price",
  sortOrder: "asc",
  proxyConfiguration: { useApifyProxy: false },
};

const run = await client.actor("khadinakbar/woocommerce-product-scraper").call(input);

const dataset = await client.dataset(run.defaultDatasetId).listItems({ clean: true });

console.log(dataset.items);
```

Set `APIFY_TOKEN` in your environment before running the example. The readback uses the run's default dataset, which contains the normalized product rows.

### Best results and outcome guidance

Use a focused set of store URLs and filters that match the research question. `maxProducts` applies as one run-wide cap across all requested stores, so it works well for bounded catalog checks. `search` is useful for product families, while `categoryIds`, `stockStatuses`, `onSale`, and `featured` narrow the result set in different ways. If a store exposes the public Store API through a subdirectory, include that subdirectory in the store URL. For agent workflows, read `OUTPUT` first when you need the terminal run state, then inspect the dataset rows for product-level analysis.

### Design note

I found that `maxProducts` is a single hard cap across every requested store, and it stops billing and pagination after that many validated product rows.

### Focused standalone workflow

This Actor is designed as a focused standalone workflow.

### FAQ

#### When should I use `storeUrls` versus `search`?

Use `storeUrls` to identify the public WooCommerce store sources, then use `search` when you want product rows matching a text phrase within those stores.

#### How do I narrow results to a category?

Provide public WooCommerce category IDs in `categoryIds`. The IDs are store-specific and come from the public Store API or product data.

#### How does this Actor handle stock-related workflows?

Use `stockStatuses` to return `instock`, `outofstock`, or `onbackorder` products. The dataset rows also include `inStock`, `onBackorder`, and `stockStatus`.

#### Can this Actor be used for store comparison through Apify MCP?

Yes. It is an Apify Actor usable through Apify MCP, and it is well suited to agent workflows that compare public product rows from known WooCommerce stores.

#### Where should I look for terminal run status?

Check the `OUTPUT` record for the compact result state and the `RUN_SUMMARY` record for per-store diagnostics and charge details.

### Responsible use

This Actor collects publicly accessible WooCommerce product catalog data. Use it in line with each target store's terms, applicable law, copyright and database rights, privacy obligations, and internal policies. It is intended for public catalog research and monitoring rather than private, authenticated, or personal data access.

# Actor input Schema

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

Use this when you need a public WooCommerce store catalog, such as 'https://porterandyork.com'. Add a homepage URL or a store installed in a subdirectory, and the actor calls its public Store API. The actor extracts published product data only and accepts up to 100 stores. Do not use product, order, customer, checkout, or WordPress admin URLs here.

## `maxProducts` (type: `integer`):

Use this to set one hard product cap across every requested store, such as 100. It accepts whole numbers from 1 through 10,000 and defaults to 100. Billing and Store API pagination stop after this many validated product rows. It is not a per-store cap and does not count pages, categories, or variants separately.

## `search` (type: `string`):

Use this to ask the WooCommerce Store API for products matching a text phrase, such as 'organic coffee'. It accepts up to 200 characters and is empty by default, which returns the full catalog. Store search behavior is supplied by each target store and may not match its storefront search exactly. It is not a Google query or a product URL.

## `categoryIds` (type: `array`):

Use this to limit output to public WooCommerce category IDs, for example \[12, 27]. It accepts positive numeric IDs and defaults to an empty list, which applies no category filter. IDs are store-specific, so obtain them from the store's public Store API or product data first. This is not a list of category names or URL slugs.

## `stockStatuses` (type: `array`):

Use this to return products in one or more public stock states, such as 'instock'. It accepts instock, outofstock, and onbackorder and defaults to an empty list, which applies no stock filter. Multiple values are sent to the official Store API as an array filter. It is not an exact inventory-count filter.

## `onSale` (type: `boolean`):

Use this when you need only products that the public Store API marks as on sale. Set true to apply the filter; false is the default and leaves the catalog unfiltered by sale status. The value is sent directly to the Store API rather than inferred from price comparisons. It does not guarantee that a store's promotion has a regular-price field.

## `featured` (type: `boolean`):

Use this when you need only catalog items that WooCommerce marks as featured. Set true to apply the filter; false is the default and leaves the catalog unfiltered by featured status. The flag is read from the public Store API and can differ from a theme's visual merchandising. It is not a filter for best-selling or newest products.

## `sortBy` (type: `string`):

Use this to choose the Store API sorting field, for example price. It accepts date, price, popularity, or rating and defaults to date. Set sortOrder separately to choose ascending or descending results. It does not sort output after retrieval or bypass the maximum product cap.

## `sortOrder` (type: `string`):

Use this to choose ascending or descending order for the selected Store API sort field. It accepts asc or desc and defaults to desc. The setting applies to the target API before pagination begins. It is not a way to order multiple stores relative to each other.

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

Use this only if a public Store API blocks the default direct request path. Set useApifyProxy to true and optionally choose a proxy group or two-letter country code. It defaults to direct HTTP requests because the public WooCommerce Store API is usually accessible without a proxy. This setting never accepts third-party credentials, cookies, or authorization tokens.

## Actor input object example

```json
{
  "storeUrls": [
    "https://porterandyork.com",
    "https://example.com/shop"
  ],
  "maxProducts": 100,
  "search": "organic coffee",
  "categoryIds": [
    12,
    27
  ],
  "stockStatuses": [
    "instock"
  ],
  "onSale": true,
  "featured": true,
  "sortBy": "price",
  "sortOrder": "asc",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

Normalized WooCommerce product rows from the public Store API.

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

Compact terminal outcome and product-count contract.

## `runSummary` (type: `string`):

Detailed per-store diagnostic and charge summary.

# 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": [
        "https://porterandyork.com"
    ],
    "maxProducts": 100,
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/woocommerce-product-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": ["https://porterandyork.com"],
    "maxProducts": 100,
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/woocommerce-product-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    "https://porterandyork.com"
  ],
  "maxProducts": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call khadinakbar/woocommerce-product-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=khadinakbar/woocommerce-product-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/wNKFSEi4wb1iXE87g/builds/0s7FVaFkzVoiYoQu8/openapi.json
