# WooCommerce Products Scraper — Prices, SKUs & Stock (`funny_ground/woocommerce-store-products-scraper`) Actor

Export public WooCommerce Store API products with currency-scaled prices, SKUs, stock flags, images, categories and parent variation options. Per-product fees and separate Apify platform usage apply.

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

## Pricing

from $0.50 / 1,000 woocommerce products

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Products Scraper — Prices, SKUs & Stock

WooCommerce Products Scraper exports **public Store API catalogs**: names, SKUs, currency-scaled prices, stock flags, categories, ratings, images and parent options for product research.

No WooCommerce login, consumer key, browser or paid proxy. Public Store API access is required; Apify API calls need your token.

### Quick start

1. Enter the **WordPress installation root** or public collection endpoint—not a product/category page.
2. Set limits/filters and click **Start**.
3. Export **Products** as JSON/CSV/Excel; inspect the source summary for limits/errors.

```json
{
  "storeUrls": ["https://woocommerce.com"],
  "maxProductsPerStore": 10,
  "maxProducts": 100,
  "includeDescription": false
}
```

`{}` requests up to 10 WooCommerce.com demo products. **10 saved products = $0.005 in event fees plus Apify usage.** Results are not guaranteed; no store affiliation.

#### Accepted URLs

- Installation root: `https://store.com/` or `https://store.com/wordpress/`.
- Collection: `https://store.com/wordpress/wp-json/wc/store/v1/products`.
- Query route: `https://store.com/?rest_route=/wc/store/v1/products`; `index.php` routes also work.

`/shop/` may not be the installation root. URL query filters are rejected; use Actor fields. No consumer keys, cookies or access tokens, and no admin/cart/checkout/order/customer endpoints.

A first-page 404 can trigger the equivalent public query route—not a fallback for 401/403 denial, login pages or challenges.

### Input fields

| Field | Default | Purpose |
|---|---|---|
| `storeUrls` | Demo store | 1–20 public HTTPS installation roots or collection endpoints |
| `maxProductsPerStore` | 10 | Matching products saved per store, 1–5,000 |
| `maxProducts` | 1,000 | Global saved-product cap, 1–10,000 |
| `onlyInStock` | false | Require `is_in_stock=true`; exclude explicit backorders |
| `onlyOnSale` | false | Require the returned `on_sale=true` flag |
| `search` | empty | Store-side search text, up to 200 characters |
| `category` | empty | Up to 20 comma-separated positive category IDs; match any |
| `productType` | `any` | `any`, `simple`, `variable`, `grouped` or `external` |
| `includeDescription` | false | Plain-text descriptions and short descriptions |
| `pageSize` | 100 | Requested products per page, 1–100 |
| `failOnStoreError` | false | Stop and fail at the first source error |

Stock/sale/type/category filters are rechecked locally. Unknown stock is not in stock; backorder flags are not inferred. Search rules and category IDs are store-specific.

#### In-stock product search

```json
{
  "storeUrls": ["https://seedsforgenerations.com"],
  "onlyInStock": true,
  "search": "onion",
  "maxProductsPerStore": 10,
  "includeDescription": true
}
```

`onlyInStock` is a stock filter, not a physical/virtual-product filter. Replace example URLs with your own targets.

#### Variable parents and option mappings

```json
{
  "storeUrls": ["https://seedsforgenerations.com"],
  "productType": "variable",
  "maxProductsPerStore": 3
}
```

`variationOptions` includes exposed child IDs/options in the parent fee. **No child SKU, price, image or inventory details are fetched or expanded**, and no option combinations are invented.

### Output and price interpretation

One row is one unique public product:

- Store/product hash `id`, source `productId`, name, slug, type, SKU and product/store/source URLs.
- `currency`, `currencyMinorUnit`, `rawPrices`; numeric `price`, `regularPrice`, `salePrice`, `minPrice`, `maxPrice` and decimal `*Text` counterparts.
- `onSale`, `isInStock`, `isOnBackorder`, derived `stockStatus` and conditional `lowStockRemaining`.
- Categories, tags, brands, attributes, parent `variationOptions`, grouped IDs, image links and aggregate ratings/review counts—not individual reviews.
- Optional descriptions, truncation flags and `scrapedAt` (collection time, not product creation/update time).

Raw `"325"` becomes `"3.25"` at scale 2, `"325"` at 0 or `"0.325"` at 3. Scales 0–6 are supported. Zero is retained; malformed amounts/scales become null. Unsafe numeric conversions become null while supported exact text remains. Use text/raw fields for financial arithmetic.

Range bounds use the exposed range or current summary price, not an audit of child prices. Check `onSale` rather than the presence of `salePrice`. Prices use anonymous storefront tax/currency settings; no FX conversion.

Stock flags are **not private inventory counts**. No private stock, sales, customer data or authoritative dates are inferred. Missing values stay null/empty arrays. Descriptions reflect the public API—not an Actor-side redaction guarantee. No passwords/cookies or protected-content unlocking.

### Current pricing and billing

Current USD rates; consult the [Pricing tab](https://apify.com/funny_ground/woocommerce-store-products-scraper/pricing) and run Usage report.

| Charge | Current rate |
|---|---|
| `apify-default-dataset-item` | **$0.0005 per saved product — $0.50 per 1,000** |
| Actor startup event | **None configured** |
| Exposed parent option mappings and optional descriptions | Included |
| Apify compute, transfer and storage operations | **Billed separately to the running user** at their plan rates |

**Pay per event + usage**, not all-inclusive. Saved rows are automatically billed once. No paid upstream Actor/data service is called.

Invalid/excluded/error/duplicate records incur no product fee. Empty/failed runs can cost usage; saved rows remain billable after later failure. `maxProducts` and the event budget limit rows, **not platform usage**. Event allowance is checked before requests/save batches.

### Pagination, reliability and limits

- Sequential stores, `orderby=id&order=asc`. Page size is reduced for initial result/budget caps, then fixed per store. Total-page headers outrank short-page heuristics. Live catalog changes can affect pagination.
- Canonical stores/recognized redirect aliases and store/product IDs are deduplicated per run. Different stores remain distinct. Repeated pages stop; new runs bill saved rows again.
- Public HTTPS/443 only; no URL credentials, literal IPs or private/local targets. DNS/redirects are checked; TLS validation stays enabled.
- **100 pages/store, 120 HTTP requests/run, 4 MiB decoded JSON/response**, fixed 256 MB memory, two-minute collection deadline and 180-second default run timeout. In-flight calls may finish later. One HTTP 429/502/503/504 retry; no access-control bypass/paid fallback.
- Descriptions: 10,000 characters; short notes: 3,000. Lists/nested options: 100 entries; variation mappings/grouped IDs: 1,000. Check `descriptionTruncated`, `metadataTruncated` and `variationOptionsTruncated`.

`OUTPUT` reports counts, pages, source totals, errors and stops. **Successful samples can have `complete:false`.** Errors normally allow other stores to continue; all failing without valid output fails the run. `failOnStoreError: true` stops at the first error. Empty matches can succeed. Completeness is not guaranteed.

### FAQ

**Do I get every variation's price and SKU?**\
No. Variable parents include public option mappings, not expanded child detail rows.

**Why does a WooCommerce website return no products?**\
The public API may be disabled, protected, empty or incompatible. Check the installation root/collection URL; restrictions are not bypassed.

### API and related Actors

Use `funny_ground/woocommerce-store-products-scraper` via Apify API/SDK with the same JSON; read its dataset and key-value `OUTPUT`. Keep your token private. Official reference: [WooCommerce Products API](https://developer.woocommerce.com/docs/apis/store-api/resources-endpoints/products/).

- [Shopify Products Scraper](https://apify.com/funny_ground/shopify-products-scraper) — public Shopify catalogs.
- [Website Contact & Social Scraper](https://apify.com/funny_ground/website-contact-social-scraper) — separate website contact/social extraction.

Follow store terms/copyright; export grants no redistribution rights.

# Actor input Schema

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

Paste 1–20 public HTTPS WordPress installation roots, such as https://store.com/ or https://store.com/wordpress/, or the full /wp-json/wc/store/v1/products collection URL. Public ?rest_route=/wc/store/v1/products routes also work. Do not enter a shop/category/product page, private credentials, cart/admin API or query filters; use the options below. Duplicate canonical stores/products are not billed again within this run.

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

Default 10 products cost $0.005 in event fees. Applied after invalid items, duplicates and local stock/sale/type/category checks. Available variation option mappings are included in each product row; no child-detail expansion or extra option fee.

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

Global result cap after deduplication. Stores are processed in input order. Your event-charge budget is also respected, but it does not cap separately billed platform usage. Early-stop reasons are reported in OUTPUT.

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

Request the API's instock filter, then require is_in_stock=true and exclude products explicitly marked is_on_backorder=true before writing. This is a public product-level flag, not an exact inventory count. Missing backorder metadata is not inferred.

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

Request on_sale=true and require the returned on_sale flag. The presence of a sale_price alone does not mean a promotion is active.

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

Passed to the store's own public search parameter. Matching rules depend on its WooCommerce version/search extensions. Applied on the server before pagination.

## `category` (type: `string`):

For example 22,43. Match at least one category ID. IDs are local to each store and are not portable between stores. Server filtering is backed by a local returned-category check. Leave blank for all categories.

## `productType` (type: `string`):

Any returns the store's default public product collection. Variable returns parent products with available child IDs/options, not separately fetched child SKUs/prices. No private/admin variation endpoint is used.

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

Optional descriptions up to 10,000 characters and short descriptions up to 3,000. No extra event fee. Password-protected descriptions remain unavailable; no password or cookie is submitted.

## `pageSize` (type: `integer`):

Up to 100, reduced for smaller initial product/budget caps and then kept fixed throughout a store's pagination. Reduce if a store's response exceeds 4 MiB. At most 100 pages per store / 120 HTTP requests per run / two minutes of collection. Small page sizes can hit these safety caps before a large export finishes.

## `failOnStoreError` (type: `boolean`):

By default, continue with other stores and report failed/partial sources in OUTPUT. If all stores fail with no valid results, the run fails. When enabled, stop and fail at the first source error; previously saved products remain available and billable.

## Actor input object example

```json
{
  "storeUrls": [
    "https://woocommerce.com"
  ],
  "maxProductsPerStore": 10,
  "maxProducts": 1000,
  "onlyInStock": false,
  "onlyOnSale": false,
  "search": "",
  "category": "",
  "productType": "any",
  "includeDescription": false,
  "pageSize": 100,
  "failOnStoreError": false
}
```

# Actor output Schema

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

Unique public products with price strings, SKUs, stock flags, categories, images and available variation options. Export JSON, CSV or Excel.

## `summary` (type: `string`):

Per-store pagination, counts, completion flags, limits and errors. Not a billable product row.

# 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://woocommerce.com"
    ],
    "maxProductsPerStore": 10,
    "maxProducts": 1000,
    "onlyInStock": false,
    "onlyOnSale": false,
    "search": "",
    "category": "",
    "productType": "any",
    "includeDescription": false,
    "pageSize": 100,
    "failOnStoreError": false
};

// Run the Actor and wait for it to finish
const run = await client.actor("funny_ground/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 = {
    "storeUrls": ["https://woocommerce.com"],
    "maxProductsPerStore": 10,
    "maxProducts": 1000,
    "onlyInStock": False,
    "onlyOnSale": False,
    "search": "",
    "category": "",
    "productType": "any",
    "includeDescription": False,
    "pageSize": 100,
    "failOnStoreError": False,
}

# Run the Actor and wait for it to finish
run = client.actor("funny_ground/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 '{
  "storeUrls": [
    "https://woocommerce.com"
  ],
  "maxProductsPerStore": 10,
  "maxProducts": 1000,
  "onlyInStock": false,
  "onlyOnSale": false,
  "search": "",
  "category": "",
  "productType": "any",
  "includeDescription": false,
  "pageSize": 100,
  "failOnStoreError": false
}' |
apify call funny_ground/woocommerce-store-products-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,funny_ground/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/3darg8c7M3uKGaPTC/builds/xsCyE8hLBCRsIuP7O/openapi.json
