# WooCommerce Products Scraper (`automation-lab/woocommerce-store-product-catalog`) Actor

Export public WooCommerce storefront products with IDs, prices, currency, stock flags and visible attributes for recurring catalog comparisons. Reports unsupported Store APIs explicitly.

- **URL**: https://apify.com/automation-lab/woocommerce-store-product-catalog.md
- **Developed by:** [Automation Lab](https://apify.com/automation-lab) (community)
- **Categories:** E-commerce
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.48 / 1,000 product exporteds

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

## WooCommerce Products Scraper

Export WooCommerce products from supplied public storefronts for recurring catalog and price comparisons. Get product IDs, names, URLs, prices with currency metadata, stock flags and conditionally visible attributes and variation references. The Actor reads anonymously accessible WooCommerce Store APIs; it does not need admin credentials and does not import, edit or write products.

### Who is this for?

- Merchandising analysts comparing a supplier's visible assortment.
- Ecommerce teams collecting price and availability snapshots.
- Data engineers exporting public catalog rows into spreadsheets or warehouses.

### Why use this Actor?

The export keeps the original minor-unit price strings and currency formatting alongside normalized numeric prices. Store-level access outcomes are separate from products, so a disabled API is not mistaken for an empty catalog or a charged result. Multiple supplied storefronts share one explicit global product cap.

### Get started

1. Enter the storefront's HTTPS installation root, such as `https://offermanwoodshop.com`.
2. Set **Maximum products per run**. The default is 100 across all stores.
3. Run the Actor and inspect Products and Storefront access status.
4. Export the dataset as JSON, CSV or Excel through Apify.
5. Schedule later runs if you need recurring snapshots, and compare downstream by `(storeUrl, productId)`.

```json
{"startUrls":[{"url":"https://offermanwoodshop.com"}],"maxItems":100,"pageSize":100}
```

### Inputs

| Field | Behavior |
|---|---|
| `startUrls` | 1–50 public HTTPS installation roots, in visit order. Use `{ "url": "https://your-store.example" }` entries. Preserve WordPress subdirectories. |
| `maxItems` | Global unique-product cap, default 100, allowed 1–100000. Zero and unlimited are unsupported. Later stores may not be visited. |
| `pageSize` | Requested products per API page, default 100, allowed 1–100. Fixed within each store so page offsets remain stable. |

Identical normalized roots are visited once. Product IDs deduplicate within a store, not across different stores. Do not supply product/category URLs, API paths, credentials, query strings, fragments, custom ports or private addresses. There are no search/category filters, proxy settings or login modes.

### Extracted data

| Fields | Meaning |
|---|---|
| `storeUrl`, `productId`, `productUrl` | Store provenance, store-local identifier and public permalink. |
| `name`, `slug`, `sku`, `productType` | Source product identity; custom product types remain unchanged. Names may contain encoded HTML entities. |
| `price`, `regularPrice`, `salePrice` | Numeric amounts derived from minor-unit strings; null if absent. Check `onSale` before interpreting sale prices. |
| `prices`, `currency`, `currencyMinorUnit` | Original price object, currency code and decimal precision. Original formatting and price ranges remain in `prices`. |
| `inStock`, `purchasable`, `onSale`, `lowStockRemaining` | Source flags; missing values are null, not false or zero. |
| `attributes`, `variations` | Only publicly visible metadata returned by the Store API. Arrays can be empty. Variation references are not fully expanded variant prices or inventory. |
| `categories`, `images` | Source category and image metadata. No image files are downloaded. |
| `scrapedAt` | UTC collection timestamp. |

For variable products, source price ranges do not imply every variant has that price. Numeric normalization is convenient for ordinary currency amounts; use original strings for exact financial arithmetic. Availability is the storefront's current public flag, not guaranteed inventory or fulfillment.

### Output example

A reduced example from a local public-store export:

```json
{
  "storeUrl":"https://rootree.ca",
  "productId":31192,
  "name":"250KG",
  "productUrl":"https://rootree.ca/product/250kg/",
  "productType":"extendo",
  "price":57,
  "currency":"CAD",
  "currencyMinorUnit":2,
  "prices":{"price":"5700","regular_price":"5700","sale_price":"5700","currency_code":"CAD","currency_minor_unit":2},
  "attributes":[],
  "variations":[]
}
```

Actual rows include all documented fields. Source values and prices may change between runs.

### Access status and failures

The `ACCESS-STATUS` key-value record includes saved count and per-store outcomes:

- `ok`: the available catalog was exhausted.
- `empty`: a valid API returned an empty catalog.
- `limit_reached`: the global cap stopped collection; coverage is partial.
- `not_visited_limit`: an earlier store consumed the cap.
- `unsupported_or_denied`: the public API is disabled, inaccessible, not JSON or returns an access/path error.
- `failed`: network/retry exhaustion or malformed product data; the run fails and any saved rows are partial.

An unsupported store can finish with zero product rows and an explicit access report. Access reports are not billable products. Transient network/429/5xx failures get at most two retries; 401/403 responses do not receive blind retries. A missing pretty-permalink endpoint gets one public WordPress query-route attempt. No browser, CAPTCHA solving, proxy bypass or private admin API fallback is included.

### How much does it cost to export WooCommerce products?

Pay-per-event pricing includes a **$0.001 one-time start event** and one `item` event for each unique product row saved. No separate event is charged for attributes, variations, images, access reports, duplicates or rejected records. Failed/empty exports may still incur the start event and charges for products already saved.

| Apify Store spend tier | Per product |
|---|---:|
| FREE | $0.00092 |
| BRONZE | $0.0008 |
| SILVER | $0.000624 |
| GOLD | $0.00048 |
| PLATINUM | $0.00048 |
| DIAMOND | $0.00048 |

Estimated BRONZE totals: 5 products **$0.005**, 25 products **$0.021**, 100 products **$0.081**. FREE 100 products: **$0.093**. Tiers follow qualifying aggregate Store spending under Apify's rules, not this Actor's result volume. Check the pricing panel for current prices and applicable taxes/platform terms. Billing limits and runtime timeouts can stop a run before the requested cap.

### Limits and coverage

Only anonymously enabled Store APIs are supported. A WooCommerce storefront can disable or restrict these endpoints, customize their response shape or hide products. There is no claim that every WooCommerce installation is supported. Supply an installation root rather than a shop page. Catalog edits during pagination can affect completeness; the API is not a transactional snapshot. No historical prices, reviews, alerts, admin-only SKUs, hidden variants, imports or write operations are provided.

The run timeout is five minutes. Very large limits are ceilings, not guarantees of complete upstream coverage within that time. Data is collected sequentially without downloading media or rendering pages.

### Integrations

Export datasets into Google Sheets for assortment comparisons, or use an Apify webhook to send successful run IDs to your ETL pipeline. Schedule daily runs in Apify, retain snapshots downstream and join by store URL plus product ID. Inspect access status before deciding a missing product was removed. This Actor itself does not calculate diffs or send price alerts.

### API usage

Keep your token private. This starts one asynchronous run:

```bash
curl -X POST 'https://api.apify.com/v2/acts/automation-lab~woocommerce-store-product-catalog/runs' \
  -H "Authorization: Bearer $APIFY_TOKEN" -H 'Content-Type: application/json' \
  -d '{"startUrls":[{"url":"https://offermanwoodshop.com"}],"maxItems":25}'
```

JavaScript with the Apify client:

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/woocommerce-store-product-catalog').call({
  startUrls: [{ url: 'https://offermanwoodshop.com' }], maxItems: 25
});
const { items } = await client.dataset(run.defaultDatasetId).listItems({ limit: 25 });
console.log(items);
```

Python:

```python
import os
from apify_client import ApifyClient
client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/woocommerce-store-product-catalog').call(
    run_input={'startUrls': [{'url': 'https://offermanwoodshop.com'}], 'maxItems': 25})
items = client.dataset(run['defaultDatasetId']).list_items(limit=25).items
print(items)
```

Verify terminal success and access status before treating the dataset as a complete result.

### MCP usage

Use the scoped hosted endpoint with an authenticated client. Claude Code:

```bash
claude mcp add --transport http apify "https://mcp.apify.com?tools=automation-lab/woocommerce-store-product-catalog"
```

Claude Desktop, Cursor and VS Code: use their supported HTTP MCP configuration (client key names may vary):

```json
{"mcpServers":{"apify":{"url":"https://mcp.apify.com?tools=automation-lab/woocommerce-store-product-catalog"}}}
```

Example prompts: “Export at most 25 products from this public WooCommerce store and show prices and stock flags.” “Inspect access status before comparing this catalog with yesterday's export.”

Discover actual names and schemas with `tools/list`; scoped Actor selection also exposes run/data helper tools. Discovery alone does not authorize execution. Start once and retain the returned run ID and storage IDs: these are metadata, not product rows. If still running, check the same run with bounded backoff (2, 4, 8 seconds, capped at 10) and a 120-second consumer deadline. Recover a known run after a client timeout rather than starting again. Report pending at the deadline; failed runs yield partial data only.

After success, read dataset pages with explicit limit/offset/fields. For model context, use pages of 20, at most 100 source rows and 64 KiB serialized UTF-8 total, whichever comes first. Enforce bytes host-side before injecting into a model; disclose omitted oversized content. Track source offsets, stop at exhaustion/budget, and report continuation offset and incomplete coverage. Keep full exports outside model context. Clients unable to intercept response size cannot guarantee a byte ceiling. No numeric token-savings claim is made.

### Legality, responsible use and non-affiliation

Use only storefronts and public data you are authorized to collect. Respect applicable laws, source terms and rate limits. Public access is not a blanket permission to republish data. This independent Actor is not affiliated with or endorsed by WooCommerce or any storefront. It uses standard Apify user terms, with no custom agreement.

### Data handling and diagnostics

No AI provider is called by the Actor. Input store URLs are sent to those storefronts; public catalog data is saved in your Apify dataset and access reports in your run's key-value store. We do not create a cross-run cache or store credentials. Apify storage/log retention follows your account settings; delete run storage through Apify when no longer needed. You control downstream exports and their retention.

Failed operations send sanitized diagnostic input, exceptions and actor/build/run IDs to our private GlitchTip service for repair; secret fields and URL queries are removed and reports are retained for 30 days. Runtime recipients are the supplied storefronts, Apify and our private diagnostic service. Company-owned infrastructure costs are included in Actor pricing; there are no separate API-key or proxy fees.

### FAQ and troubleshooting

**Why did I get no products?** Inspect Storefront access status. `empty` is different from a denied or unsupported API. Try the actual WordPress installation root rather than a category or product page.

**Can I export hidden/admin data or import this into WooCommerce?** No. This is a public read-only export, not a migration/import tool or authenticated admin API client.

**Are every variant's prices included?** No. Only API-visible attributes and variation references are preserved, with parent price metadata and conditional ranges.

**Why did a later store not run?** The product cap is global. Increase it or run stores separately.

**Can I report a problem?** Use the Actor's Apify issues tab with a run link and sanitized reproduction input. Do not share credentials or private catalog data in a public issue.

### Related workflows

This is a standalone cross-store public catalog exporter. For spreadsheet processing, use your existing ETL or Apify integrations; no unrelated Actor is required to collect these records.

# Changelog

This Actor's version history is a separate document: https://apify.com/automation-lab/woocommerce-store-product-catalog/changelog.md

# Actor input Schema

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

Supply 1–50 public HTTPS storefront installation roots, including any WordPress subdirectory. Not product, category or API URLs. No credentials, query strings or custom ports. Duplicate identical roots are visited once; sources are processed in order.

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

Global cap on unique product rows across all stores, after per-store ID deduplication. Default 100; 1–100000; zero/unlimited unsupported. Later stores may remain unvisited. API access statuses are not product rows.

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

Requested page size, 1–100 (default 100). Fixed within each store to keep pagination offsets stable; the initial remaining global cap may reduce it. Does not limit total products independently of maxItems.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://offermanwoodshop.com"
    }
  ],
  "maxItems": 20,
  "pageSize": 100
}
```

# Actor output Schema

## `dataset` (type: `string`):

Public WooCommerce product rows.

## `accessStatus` (type: `string`):

Coverage, denied APIs, empty catalogs and limit outcomes.

# 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://offermanwoodshop.com"
        }
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/woocommerce-store-product-catalog").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://offermanwoodshop.com" }],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/woocommerce-store-product-catalog").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://offermanwoodshop.com"
    }
  ],
  "maxItems": 20
}' |
apify call automation-lab/woocommerce-store-product-catalog --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/woocommerce-store-product-catalog"
        }
    }
}
```

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/7hIrJXq99kCCP3Y1G/builds/zwve3C9tHPwJhUbAL/openapi.json
