# WooCommerce Catalog Change Guard (`willing_relic/woocommerce-catalog-change-guard`) Actor

Compare two supplied WooCommerce Store API snapshots for price and stock changes, additions, removal candidates, duplicate SKUs and data-quality issues. Flags incomplete captures so missing products are not treated as confirmed removals. Up to 1,000 products per snapshot. No store login or writes.

- **URL**: https://apify.com/willing\_relic/woocommerce-catalog-change-guard.md
- **Developed by:** [RevLab](https://apify.com/willing_relic) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$100.00 / 1,000 completed audits

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?

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 Catalog Change Guard

Compare two WooCommerce Store API snapshots and review price changes, stock changes, new products and missing-product candidates before sending alerts or updating downstream systems.

**An incomplete capture should not look like a product deletion.** Catalog Change Guard flags incomplete, empty or suspicious snapshots and marks missing products as unconfirmed when removal interpretation is unsafe.

### What you receive

Each completed run produces one JSON audit in the default dataset, an `AUDIT.json` backup and a readable `REPORT.html` in the run's key-value store.

The audit includes exact price deltas, stock changes, new products, removal candidates, duplicate SKU warnings, currency/price-scale changes and data-quality issues. Duplicate product IDs cause the run to reject the input.

### Who this is for

Use this Actor if your collector, scraper or integration already supplies catalog snapshots and you want a validation step before alerts or commercial decisions. This Actor compares supplied data. It does not fetch websites, log into stores, schedule catalog collection or modify products.

### Quick start

1. Open Input and use the synthetic example, or supply two snapshots from the same store and collection scope.
2. Keep the maximum run charge at $0.10 or higher and start the Actor.
3. Read the audit in Output. Open Storage to view `REPORT.html` or download `AUDIT.json`.
4. For the next audit, supply the previous capture and a newer capture in a new run.

### Input example

```json
{
  "previousSnapshot": {
    "sourceId": "my-store",
    "scope": "all-public-products",
    "capturedAt": "2026-09-03T12:00:00Z",
    "complete": true,
    "products": [{
      "id": 1, "type": "simple", "name": "Running tee", "sku": "TEE-1",
      "is_in_stock": true,
      "prices": {"price": "2500", "currency_code": "USD", "currency_minor_unit": 2}
    }]
  },
  "currentSnapshot": {
    "sourceId": "my-store",
    "scope": "all-public-products",
    "capturedAt": "2026-09-04T12:00:00Z",
    "complete": true,
    "products": [{
      "id": 1, "type": "simple", "name": "Running tee", "sku": "TEE-1",
      "is_in_stock": false,
      "prices": {"price": "2200", "currency_code": "USD", "currency_minor_unit": 2}
    }]
  }
}
```

This example reports a price change from $25.00 to $22.00 and a stock change. Supply prices as integer strings in minor units: `"2500"` with `currency_minor_unit: 2` means 25.00.

### Limits and supported format

- Up to 1,000 products per snapshot and 2 MB combined input.
- Both snapshots must have the same `sourceId` and `scope`, timezone-aware timestamps and an explicit `complete` boolean. The current timestamp must be newer.
- Products match by numeric product ID. Start a new baseline after store migrations or ID changes.
- Supported fields include `id`, `type`, `name`, `sku`, `is_in_stock` and `prices`. Raw WooCommerce REST v3 exports or arbitrary scraper output require mapping to this format.
- Optional `priceAlertPercent` ranges from 0 to 1,000; default 25.

### Interpreting missing products

Missing products remain unconfirmed when collection is incomplete, the current capture is empty, the product count falls below 70% of the previous count, or serious data-quality issues make removal interpretation unsafe. Otherwise, missing products are removal candidates. They are never independently verified deletions.

Completeness is declared by your collector and cannot be independently verified here. Only supplied variants can be checked. Variable/grouped parent prices are excluded from individual-variant comparisons. Findings are observations for review, not instructions to delete or reprice products.

### Pricing

$0.10 per completed audit, with platform usage included. One audit compares both snapshots and includes all detected changes up to the stated limits. There is no separate startup fee or per-product charge. Invalid input and budgets below one audit do not trigger the completed-audit event.

Results are stored before the audit event is charged. Recovery checks existing delivery and billing state. An uncertain charge is not automatically retried; this may leave an audit unbilled. Start a new run for a new comparison, rather than editing and resurrecting an old run.

### Data and support

The comparison makes no AI/model calls and sends no catalog data to other external services. Input and results are stored by Apify under its platform access and retention rules. Download results you need to retain.

For help, open an issue on this Actor with the run ID, expected behavior and a small sanitized example. Do not post credentials or confidential catalog data in a public issue.

# Actor input Schema

## `previousSnapshot` (type: `object`):

sourceId, scope, capturedAt with timezone, complete boolean, and up to 1,000 products. See README.

## `currentSnapshot` (type: `object`):

Same source and scope, newer capturedAt. Declare complete=false for partial collection.

## `priceAlertPercent` (type: `integer`):

Absolute percentage threshold; zero-to-nonzero is always reviewed.

## Actor input object example

```json
{
  "previousSnapshot": {
    "sourceId": "example-store",
    "scope": "all-public-products",
    "capturedAt": "2026-09-03T12:00:00Z",
    "complete": true,
    "products": [
      {
        "id": 1,
        "type": "simple",
        "name": "Product 1",
        "sku": "SKU-1",
        "is_in_stock": true,
        "prices": {
          "price": "1000",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      },
      {
        "id": 2,
        "type": "simple",
        "name": "Product 2",
        "sku": "SKU-2",
        "is_in_stock": true,
        "prices": {
          "price": "1000",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      },
      {
        "id": 3,
        "type": "simple",
        "name": "Product 3",
        "sku": "SKU-3",
        "is_in_stock": true,
        "prices": {
          "price": "1000",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      },
      {
        "id": 4,
        "type": "simple",
        "name": "Product 4",
        "sku": "SKU-4",
        "is_in_stock": true,
        "prices": {
          "price": "1000",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      },
      {
        "id": 5,
        "type": "simple",
        "name": "Product 5",
        "sku": "SKU-5",
        "is_in_stock": true,
        "prices": {
          "price": "1000",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      }
    ]
  },
  "currentSnapshot": {
    "sourceId": "example-store",
    "scope": "all-public-products",
    "capturedAt": "2026-09-04T12:00:00Z",
    "complete": false,
    "products": [
      {
        "id": 1,
        "type": "simple",
        "name": "Product 1",
        "sku": "SKU-1",
        "is_in_stock": true,
        "prices": {
          "price": "1",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      },
      {
        "id": 2,
        "type": "simple",
        "name": "Product 2",
        "sku": "SKU-2",
        "is_in_stock": false,
        "prices": {
          "price": "1000",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      },
      {
        "id": 3,
        "type": "simple",
        "name": "Product 3",
        "sku": "SKU-3",
        "is_in_stock": true,
        "prices": {
          "price": "900",
          "currency_code": "EUR",
          "currency_minor_unit": 2
        }
      },
      {
        "id": 4,
        "type": "simple",
        "name": "Product 4",
        "sku": "SKU-4",
        "is_in_stock": true,
        "prices": {
          "price": "",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      }
    ]
  },
  "priceAlertPercent": 25
}
```

# Actor output Schema

## `audit` (type: `string`):

Structured audit result stored as one item in the default dataset.

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

Human-readable HTML summary stored in the default key-value store.

# 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 = {
    "previousSnapshot": {
        "sourceId": "example-store",
        "scope": "all-public-products",
        "capturedAt": "2026-09-03T12:00:00Z",
        "complete": true,
        "products": [
            {
                "id": 1,
                "type": "simple",
                "name": "Product 1",
                "sku": "SKU-1",
                "is_in_stock": true,
                "prices": {
                    "price": "1000",
                    "currency_code": "USD",
                    "currency_minor_unit": 2
                }
            },
            {
                "id": 2,
                "type": "simple",
                "name": "Product 2",
                "sku": "SKU-2",
                "is_in_stock": true,
                "prices": {
                    "price": "1000",
                    "currency_code": "USD",
                    "currency_minor_unit": 2
                }
            },
            {
                "id": 3,
                "type": "simple",
                "name": "Product 3",
                "sku": "SKU-3",
                "is_in_stock": true,
                "prices": {
                    "price": "1000",
                    "currency_code": "USD",
                    "currency_minor_unit": 2
                }
            },
            {
                "id": 4,
                "type": "simple",
                "name": "Product 4",
                "sku": "SKU-4",
                "is_in_stock": true,
                "prices": {
                    "price": "1000",
                    "currency_code": "USD",
                    "currency_minor_unit": 2
                }
            },
            {
                "id": 5,
                "type": "simple",
                "name": "Product 5",
                "sku": "SKU-5",
                "is_in_stock": true,
                "prices": {
                    "price": "1000",
                    "currency_code": "USD",
                    "currency_minor_unit": 2
                }
            }
        ]
    },
    "currentSnapshot": {
        "sourceId": "example-store",
        "scope": "all-public-products",
        "capturedAt": "2026-09-04T12:00:00Z",
        "complete": false,
        "products": [
            {
                "id": 1,
                "type": "simple",
                "name": "Product 1",
                "sku": "SKU-1",
                "is_in_stock": true,
                "prices": {
                    "price": "1",
                    "currency_code": "USD",
                    "currency_minor_unit": 2
                }
            },
            {
                "id": 2,
                "type": "simple",
                "name": "Product 2",
                "sku": "SKU-2",
                "is_in_stock": false,
                "prices": {
                    "price": "1000",
                    "currency_code": "USD",
                    "currency_minor_unit": 2
                }
            },
            {
                "id": 3,
                "type": "simple",
                "name": "Product 3",
                "sku": "SKU-3",
                "is_in_stock": true,
                "prices": {
                    "price": "900",
                    "currency_code": "EUR",
                    "currency_minor_unit": 2
                }
            },
            {
                "id": 4,
                "type": "simple",
                "name": "Product 4",
                "sku": "SKU-4",
                "is_in_stock": true,
                "prices": {
                    "price": "",
                    "currency_code": "USD",
                    "currency_minor_unit": 2
                }
            }
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("willing_relic/woocommerce-catalog-change-guard").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 = {
    "previousSnapshot": {
        "sourceId": "example-store",
        "scope": "all-public-products",
        "capturedAt": "2026-09-03T12:00:00Z",
        "complete": True,
        "products": [
            {
                "id": 1,
                "type": "simple",
                "name": "Product 1",
                "sku": "SKU-1",
                "is_in_stock": True,
                "prices": {
                    "price": "1000",
                    "currency_code": "USD",
                    "currency_minor_unit": 2,
                },
            },
            {
                "id": 2,
                "type": "simple",
                "name": "Product 2",
                "sku": "SKU-2",
                "is_in_stock": True,
                "prices": {
                    "price": "1000",
                    "currency_code": "USD",
                    "currency_minor_unit": 2,
                },
            },
            {
                "id": 3,
                "type": "simple",
                "name": "Product 3",
                "sku": "SKU-3",
                "is_in_stock": True,
                "prices": {
                    "price": "1000",
                    "currency_code": "USD",
                    "currency_minor_unit": 2,
                },
            },
            {
                "id": 4,
                "type": "simple",
                "name": "Product 4",
                "sku": "SKU-4",
                "is_in_stock": True,
                "prices": {
                    "price": "1000",
                    "currency_code": "USD",
                    "currency_minor_unit": 2,
                },
            },
            {
                "id": 5,
                "type": "simple",
                "name": "Product 5",
                "sku": "SKU-5",
                "is_in_stock": True,
                "prices": {
                    "price": "1000",
                    "currency_code": "USD",
                    "currency_minor_unit": 2,
                },
            },
        ],
    },
    "currentSnapshot": {
        "sourceId": "example-store",
        "scope": "all-public-products",
        "capturedAt": "2026-09-04T12:00:00Z",
        "complete": False,
        "products": [
            {
                "id": 1,
                "type": "simple",
                "name": "Product 1",
                "sku": "SKU-1",
                "is_in_stock": True,
                "prices": {
                    "price": "1",
                    "currency_code": "USD",
                    "currency_minor_unit": 2,
                },
            },
            {
                "id": 2,
                "type": "simple",
                "name": "Product 2",
                "sku": "SKU-2",
                "is_in_stock": False,
                "prices": {
                    "price": "1000",
                    "currency_code": "USD",
                    "currency_minor_unit": 2,
                },
            },
            {
                "id": 3,
                "type": "simple",
                "name": "Product 3",
                "sku": "SKU-3",
                "is_in_stock": True,
                "prices": {
                    "price": "900",
                    "currency_code": "EUR",
                    "currency_minor_unit": 2,
                },
            },
            {
                "id": 4,
                "type": "simple",
                "name": "Product 4",
                "sku": "SKU-4",
                "is_in_stock": True,
                "prices": {
                    "price": "",
                    "currency_code": "USD",
                    "currency_minor_unit": 2,
                },
            },
        ],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("willing_relic/woocommerce-catalog-change-guard").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 '{
  "previousSnapshot": {
    "sourceId": "example-store",
    "scope": "all-public-products",
    "capturedAt": "2026-09-03T12:00:00Z",
    "complete": true,
    "products": [
      {
        "id": 1,
        "type": "simple",
        "name": "Product 1",
        "sku": "SKU-1",
        "is_in_stock": true,
        "prices": {
          "price": "1000",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      },
      {
        "id": 2,
        "type": "simple",
        "name": "Product 2",
        "sku": "SKU-2",
        "is_in_stock": true,
        "prices": {
          "price": "1000",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      },
      {
        "id": 3,
        "type": "simple",
        "name": "Product 3",
        "sku": "SKU-3",
        "is_in_stock": true,
        "prices": {
          "price": "1000",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      },
      {
        "id": 4,
        "type": "simple",
        "name": "Product 4",
        "sku": "SKU-4",
        "is_in_stock": true,
        "prices": {
          "price": "1000",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      },
      {
        "id": 5,
        "type": "simple",
        "name": "Product 5",
        "sku": "SKU-5",
        "is_in_stock": true,
        "prices": {
          "price": "1000",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      }
    ]
  },
  "currentSnapshot": {
    "sourceId": "example-store",
    "scope": "all-public-products",
    "capturedAt": "2026-09-04T12:00:00Z",
    "complete": false,
    "products": [
      {
        "id": 1,
        "type": "simple",
        "name": "Product 1",
        "sku": "SKU-1",
        "is_in_stock": true,
        "prices": {
          "price": "1",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      },
      {
        "id": 2,
        "type": "simple",
        "name": "Product 2",
        "sku": "SKU-2",
        "is_in_stock": false,
        "prices": {
          "price": "1000",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      },
      {
        "id": 3,
        "type": "simple",
        "name": "Product 3",
        "sku": "SKU-3",
        "is_in_stock": true,
        "prices": {
          "price": "900",
          "currency_code": "EUR",
          "currency_minor_unit": 2
        }
      },
      {
        "id": 4,
        "type": "simple",
        "name": "Product 4",
        "sku": "SKU-4",
        "is_in_stock": true,
        "prices": {
          "price": "",
          "currency_code": "USD",
          "currency_minor_unit": 2
        }
      }
    ]
  }
}' |
apify call willing_relic/woocommerce-catalog-change-guard --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,willing_relic/woocommerce-catalog-change-guard"
        }
    }
}

```

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/fSavcirbydIJR2Wmw/builds/TI4iZPiXSmyaZ1sZF/openapi.json
