# WooCommerce Product Catalog Exporter: Prices, SKUs & Stock (`technicaldost/woocommerce-public-catalog`) Actor

Export public WooCommerce Store API products with exact prices, SKUs, images, categories and stock flags. Multi-store limits, optional variation-only export and explicit coverage reports. No API key.

- **URL**: https://apify.com/technicaldost/woocommerce-public-catalog.md
- **Developed by:** [Technical Dost Solutions](https://apify.com/technicaldost) (community)
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.80 / 1,000 successful products

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 Public Catalog Exporter

Export products from public WooCommerce stores into structured JSON, CSV, Excel or XML. Get product names, SKUs, exact price strings, currency, sale flags, public stock indicators, image metadata, categories and product URLs. Every row includes its API evidence URL and observation time.

This Actor reads the **public WooCommerce Store API**. It does not need an API key or store login and does not write to the store. It does not use the authenticated WooCommerce management API.

### Pricing

$0.80 per 1,000 successful products. No run fee. Standard-run platform usage is included. Only successful eligible rows in the default dataset trigger the result charge. Error, not-found, skipped and robots-denied diagnostics do not trigger a result charge. The run fee, where listed, still applies to empty or failed runs. Memory is limited to 256–512 MB. Set a maximum run cost in Apify; inspect the actual dataset and run charge breakdown after an interruption. Input item limits bound work and do not replace the run spending limit.

### When to use it

- Export a public WooCommerce catalog for analysis or comparison.
- Compare listed prices and public availability across a bounded set of stores.
- Collect public product metadata for your own catalog research workflows.
- Export variation rows separately when a store exposes them through the Store API.

It is not an inventory-management integration, historical price monitor, review scraper or checkout tool. There is no promise that every WooCommerce store exposes a readable API.

### Quick start

1. Enter the public HTTPS **WordPress installation root**, such as `https://your-store.com/`. If WordPress is installed under `/wordpress/`, include that subdirectory. Do not enter a product page, `/shop/` page, category page, or full API URL.
2. Choose a global product limit and optional per-store limit. Stores are processed sequentially in input order.
3. Run the Actor and download the dataset. Check the **RUN_REPORT** output for stores that were limited, blocked or incomplete.

Example input, with a placeholder URL you must replace:

```json
{
  "storeUrls": ["https://your-store.com/"],
  "maxItems": 500,
  "maxProductsPerStore": 500,
  "pageSize": 100,
  "includeDescriptions": true
}
```

A valid empty catalog creates no product rows and a complete, zero-product report. An inaccessible store creates an error report, not a fabricated product. The run fails if none of the requested stores could be read; mixed successes and failures preserve successful products and report the failures.

### Inputs

| Field | Default | Meaning |
| --- | --- | --- |
| `storeUrls` | Required | 1–20 public HTTPS installation roots. Duplicate normalized URLs are collapsed. |
| `maxItems` | 1,000 | Global product-row limit, 1–100,000. |
| `maxProductsPerStore` | 1,000 | Per-store limit, 1–100,000, also subject to the global cap. |
| `maxPagesPerStore` | 100 | Maximum successful-page attempts per store, up to 1,000. Requests may include retries and a robots.txt read. |
| `pageSize` | 100 | Fixed number of products requested per API page, 1–100. |
| `search` | Empty | Optional Store API search text. |
| `category` | Empty | Optional comma-separated category IDs or slugs. IDs differ between stores. |
| `onSaleOnly` | false | Request only products marked on sale. |
| `productType` | `all` | `all`, `simple`, `variable`, `variation`, `grouped`, or `external`. |
| `includeDescriptions` | true | Include the public description HTML fields. |
| `includeRaw` | false | Include the complete public API product object. |
| `requestDelayMs` | 1,000 | Minimum spacing between requests, 1,000–30,000 ms. |

Search, category, type and sale filters apply to every input store. `all` means the default API product collection, **not** parents plus every variation. Separate variation rows are excluded by the API by default. Select `variation` for a variation-only export. The Actor does not perform an extra variation crawl for each parent product.

### Output

The dataset contains only product records. Common fields:

- `storeUrl`, `productId`, `parentProductId`, `name`, `slug`, `sku`, `productType`, `variation`, `productUrl`.
- `currency`, `currencyMinorUnit`, `price`, `regularPrice`, `salePrice`.
- `priceMinor`, `regularPriceMinor`, `salePriceMinor`, `priceRange`.
- `onSale`, `inStock`, `purchasable`, `hasOptions`, `passwordProtected`.
- `averageRating`, `reviewCount`, `images`, `categories`, `tags`, `attributes`.
- Optional `descriptionHtml`, `shortDescriptionHtml`, and `raw`.
- `sourceUrl` and `fetchedAt` for provenance.

Prices are **decimal strings**, not floating-point numbers. For example, a source price of `"1005"` with minor unit `2` becomes `"10.05"`; the original `"1005"` is retained. Missing prices stay null. A source sale-price field alone does not prove an active discount: use `onSale`. `priceRange` preserves the source object and its minor-unit values rather than inventing a single variant price.

Stock and purchasability are the store's public flags at observation time. They are not available inventory quantities or guarantees that a purchase can complete. No cart or checkout endpoint is called. Product type and other fields vary by WooCommerce version and installed extensions; unavailable values are null or empty arrays. The product ID is unique within a store, not globally.

HTML descriptions are untrusted source data. Sanitize them before rendering in a website. CSV/Excel users should treat source text as data, including values that start with spreadsheet formula characters.

### Coverage and pagination

`RUN_REPORT` in the default key-value store provides per-store counts, pages fetched, duplicate IDs skipped, reported total counts, completion status, limits reached, and exact error codes. `allStoresComplete` is true only when every selected store reached a supported end condition without detected mismatch. A complete report means the requested API collection was traversed at that time, not that private products or all variants were exported.

The Actor requests ascending product ID order and keeps `per_page` fixed. It uses `X-WP-TotalPages` when available and retains that bound if a later response omits the header; otherwise it ends on a short/empty page or a recognized page-out-of-range response after a prior page. It never exceeds the output limits. Repeated pages, contradictory totals and changes in advertised totals prevent an unqualified completeness claim. APIs without headers or with custom pagination can still hide omissions that cannot be detected.

Catalogs can change while pages are being read, so results are not an atomic snapshot. Duplicate product IDs within a store are suppressed. Interruptions may leave a partial dataset; this version does not promise checkpoint/resume across restarts. Start a fresh run to retry and inspect its report.

### Access and safety

- HTTPS only on port 443. No credentials, cookies, API keys or arbitrary request headers are accepted.
- Local, private, metadata, reserved and mixed public/private DNS targets are refused. IPv6 targets must be global unicast; private-address translation prefixes and documentation ranges are refused. Each connection uses a validated, pinned public DNS address while retaining TLS hostname verification.
- Only the selected installation's products collection and origin-level robots.txt are requested. Product/image URLs in responses are recorded, not fetched.
- Cross-origin redirects, API-path/query-changing redirects, excessive redirects and invalid TLS fail rather than being bypassed. Use the canonical store root if needed.
- Explicit robots.txt disallow rules are honored. An unavailable or malformed robots.txt stops the store conservatively; 404/410 means no published robots file. Every product page and redirect is checked against the policy, including query-specific restrictions. Published crawl delays apply to pages, retries and redirects up to 60 seconds; a longer delay stops the store.
- Sequential requests, at least one second apart, with at most three attempts for transient failures. HTTP 401/403 is not retried. A server backoff longer than 60 seconds stops rather than being shortened.
- Responses are capped at 8 MiB. A large response may require a smaller `pageSize`.

Use only stores you are permitted to access and follow applicable terms and law. No login, CAPTCHA solving, access-control bypass, proxy rotation, cart mutation or checkout is performed.

### Limitations and troubleshooting

- **HTTP 401/403, robots denial:** access is blocked. This Actor does not bypass it.
- **HTTP 404 / NOT_JSON / INVALID_PRODUCTS:** verify the WordPress installation root. The Store API may be disabled, altered, or unavailable.
- **RATE_LIMITED:** the store requested a long backoff. Try later with lower limits.
- **INCONSISTENT_PAGINATION / REPEATED_PAGE:** custom plugins or caches may have broken the expected page behavior. Existing rows remain available; the report is incomplete.
- **global_item_limit / store_item_limit / page_limit:** intentional truncation. Increase the relevant bounds if appropriate.
- Password-protected descriptions remain redacted unless the public API itself provides them. The Actor never submits a product password.
- Displayed prices can depend on tax, geolocation, currency plugins or anonymous customer context. No personalized or logged-in price is claimed.

### References

- [WooCommerce Store API](https://developer.woocommerce.com/docs/apis/store-api/)
- [Official products endpoint and variation behavior](https://developer.woocommerce.com/docs/apis/store-api/resources-endpoints/products/)
- [WordPress REST API pagination](https://developer.wordpress.org/rest-api/using-the-rest-api/pagination/)

This is an independent tool, not affiliated with or endorsed by WooCommerce or Automattic.

# Actor input Schema

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

Public HTTPS WordPress installation roots, not product or shop URLs. For a subdirectory install use https://store.com/wordpress/. Maximum 20.

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

Hard global output limit across all stores, in input order.

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

Hard per-store output limit, also bounded by the global limit.

## `maxPagesPerStore` (type: `integer`):

Additional request bound; reaching it produces an incomplete coverage report.

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

Fixed page size throughout pagination. Smaller pages can help slow stores.

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

Optional Store API search text, applied to every store.

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

Optional comma-separated Store API categories, applied to every store. IDs are store-specific.

## `onSaleOnly` (type: `boolean`):

Apply the Store API on_sale filter.

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

Default uses the API collection, which excludes separate variations. Choose variation to export only variation rows; not parents and variations together.

## `includeDescriptions` (type: `boolean`):

Preserve public description and short-description HTML as data. Never render unsanitized HTML.

## `includeRaw` (type: `boolean`):

Adds the complete public product response. Increases output size.

## `requestDelayMs` (type: `integer`):

At least 1000 ms. Longer robots.txt crawl delays are respected, up to 60 seconds.

## Actor input object example

```json
{
  "storeUrls": [
    "https://wpdemo.archiwp.com/engitech/"
  ],
  "maxItems": 1,
  "maxProductsPerStore": 1,
  "maxPagesPerStore": 1,
  "pageSize": 1,
  "onSaleOnly": false,
  "productType": "all",
  "includeDescriptions": true,
  "includeRaw": false,
  "requestDelayMs": 1000
}
```

# Actor output Schema

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

One successfully saved product per store/product ID. Download JSON, CSV, Excel or XML from the dataset.

## `report` (type: `string`):

Per-store counts, completeness, stop reasons, robots decisions and errors. Always check this when a catalog may be incomplete.

# 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://wpdemo.archiwp.com/engitech/"
    ],
    "maxItems": 1,
    "maxProductsPerStore": 1,
    "maxPagesPerStore": 1,
    "pageSize": 1
};

// Run the Actor and wait for it to finish
const run = await client.actor("technicaldost/woocommerce-public-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 = {
    "storeUrls": ["https://wpdemo.archiwp.com/engitech/"],
    "maxItems": 1,
    "maxProductsPerStore": 1,
    "maxPagesPerStore": 1,
    "pageSize": 1,
}

# Run the Actor and wait for it to finish
run = client.actor("technicaldost/woocommerce-public-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 '{
  "storeUrls": [
    "https://wpdemo.archiwp.com/engitech/"
  ],
  "maxItems": 1,
  "maxProductsPerStore": 1,
  "maxPagesPerStore": 1,
  "pageSize": 1
}' |
apify call technicaldost/woocommerce-public-catalog --silent --output-dataset

```

## MCP server setup

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