# Shopping Feed Leak Watch — Shopify & WooCommerce (`jeanswiegers/shopping-feed-leak-watch`) Actor

Shopify feed price mismatch monitor: compare Shopify, WooCommerce or feed variants with live pages; track price, stock, GTIN and image exceptions.

- **URL**: https://apify.com/jeanswiegers/shopping-feed-leak-watch.md
- **Developed by:** [Jean Swiegers](https://apify.com/jeanswiegers) (community)
- **Categories:** E-commerce, Automation
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 audited variants

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

### What does Shopping Feed Revenue-Leak Watch do?

**Shopify feed price mismatch monitor** for evidence-backed, stateful exception lists. Compare a public product feed or [Shopify](https://www.shopify.com/) / WooCommerce catalog with the corresponding product page. Track NEW, CHANGED and RESOLVED findings instead of repeatedly exporting the same audit.

This is a **private technical proof of concept**, not a validated revenue-loss predictor. Customer pilots and willingness-to-pay validation have not passed. No daily schedule or messages are created automatically.

### Why use a feed/page drift API?

Paid-shopping agencies can review products whose public feed price, offer stock, currency, GTIN or image disagree with the exact variant's structured page evidence. Unknown fields are reported separately. A blocked page or missing GTIN never silently becomes a clean bill of health. Previously active issues remain active until the same check produces comparable matching evidence.

Use your actual merchant feed for an independent comparison. Public Shopify `products.json` and WooCommerce Store API mode are convenient catalog consistency tests, **not access to Merchant Center diagnostics**. They can share an upstream backend with the landing page, so agreement is not independent proof of advertising eligibility.

### What data is returned?

| Field | Meaning |
|---|---|
| kind / event | exception versus diagnostic; NEW, CHANGED, RESOLVED, optionally PERSISTENT |
| title / sku / variantId | Product identity where available |
| field | currency, structured_price, visible_price, availability, gtin, image or variant |
| expected / actual | Feed value and observed page value |
| firstSeen / lastSeen | Observation timestamps; not when Google first disapproved a product |
| evidenceUrl | Exact variant landing page |
| reviewRequired | Image differences require human review |

The default dataset contains change events and coverage diagnostics. The default key-value store's `SNAPSHOT` contains all checked variants/checks; `SUMMARY` records request/coverage counts. Download the dataset as JSON, HTML, CSV or Excel or use Apify's API tab.

### How to run a Shopify or WooCommerce feed mismatch check

1. Enter up to five public `stores` objects with `url`, `platform` and a known `currency`, or supply HTTPS `feedUrls`.
2. For a feed-only run set `stores: []`. Supported feed formats are Google-style XML/RSS, CSV and a JSON item array. Fields: id, link, price, currency, availability, variant_id, sku, gtin, image_link. A price such as `29.00 USD` carries its currency.
3. Start small with `maxItems: 5`, `maxRequests: 20`.
4. Reuse the same `monitorId` on later runs for diffs; use a new ID for a different market, currency or configuration. Do not run the same monitor concurrently.
5. Inspect UNKNOWN checks and diagnostics as carefully as exceptions.

Example public demo input:

```json
{"stores":[{"url":"https://theme-dawn-demo.myshopify.com","currency":"CAD"}],"maxItems":1,"maxRequests":6,"monitorId":"dawn-cad"}
```

Illustrative output, not a finding about that demo store:

```json
{"kind":"exception","event":"NEW","field":"structured_price","expected":29,"actual":19,"evidenceUrl":"https://example.com/product?variant=123"}
```

### Cost and proposed pricing

Private prototype only: Apify compute/storage/transfer applies; no monetization has been configured. Fetching is bounded and uses no proxy by default. Publication proposal, subject to Jean's approval and measured margins: **US$0.002 per successfully audited variant event (US$2/1,000)**, not per alert. Charging only anomalies cannot cover audits that find no problems. Diagnostics/individual field findings would not be additional charges. The `audited-variant` hook bills at most once per completed exact-identity audit with at least one comparable non-identity field. UNKNOWN-only/error rows, diagnostics and extra field findings do not add charges. The run charge cap is respected; no fees are activated while the Actor remains unpriced.

### Limits, safety and support

This is a static HTML/JSON-LD checker, not a browser-rendered checkout audit. Static displayed-price checks require one unambiguous recognized current amount. WooCommerce sale prices prefer the active `ins` amount over `del` regular prices, including accessibility-hidden duplicate markup. UnitPriceSpecification arrays distinguish current versus ListPrice values; European decimal/currency-suffix amounts are supported. This is not a browser-computed visibility or checkout test, and ambiguous/JS-only amounts remain UNKNOWN. Exact variant/SKU selection is mandatory. Missing variants are unknown, not proven mismatches. Missing Shopify barcodes can be enriched through the documented public [Ajax Product API](https://shopify.dev/docs/api/ajax/reference/product), matching the exact variant ID; this adds at most one cached request per product. GTIN comparisons require independently supplied feed/catalog and page values, valid check digits, and normalized UPC/EAN padding. A SKU-like barcode is not treated as a GTIN. Identifiers omitted by WooCommerce or either page remain UNKNOWN with a coverage reason. Image URLs are normalized for common Shopify CDN aliases and sizes, not visually compared. No image bytes are fetched. WooCommerce uses the public, unauthenticated [Store API](https://developer.woocommerce.com/docs/apis/store-api/resources-endpoints/products/) `type=simple`, preserving installation subdirectories. WooCommerce catalog mode covers simple products; variable products need explicit variant feed links and may remain unknown.

Only public HTTPS destinations are accepted; credentials/custom ports/private/reserved IPs and DNS addresses are rejected. Robots policies, byte caps, timeout and total-request limits are enforced. No retries, login bypass, admin changes, checkout, feed corrections or alerts are performed. Use sources you may lawfully access, respect licensing/terms, and do not include personal data or secrets in feeds. Private named state persists between runs; the per-run default store is not the history store. Keep monitor IDs separated. Raise implementation issues through the Actor's Issues tab when access is available.

### WooCommerce example and coverage

```json
{"stores":[{"url":"https://demo.woostify.com","platform":"woocommerce"},{"url":"https://websitedemos.net/brandstore-02","platform":"woocommerce"}],"maxItems":2,"maxRequests":8,"monitorId":"woo-two-demo-stores"}
```

No WooCommerce admin keys are requested. The public catalog's minor currency units are normalized. Summary `checkCoverage` separates MATCH, MISMATCH and UNKNOWN for every field. An empty exception dataset does not prove all fields were audited; always inspect SUMMARY and SNAPSHOT. Public demo stores are technical fixtures, not customer pilots. No Merchant Center account, refund, lost-sales estimate or automatic correction is involved.

# Actor input Schema

## `stores` (type: `array`):

Objects: url, platform (shopify or woocommerce), and optional ISO currency. Public Shopify catalog mode is not your Merchant Center feed.

## `feedUrls` (type: `array`):

HTTPS Google Merchant XML/RSS, CSV or JSON feed URLs. WooCommerce feed URLs supported.

## `feedItems` (type: `array`):

Optional explicit feed rows: id, link, price (e.g. 29.00 USD), availability, variant_id, sku, gtin, image_link. For tests clearly label seeded mutations outside the Actor.

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

Total rows across all sources; store allocation divided fairly across configured stores.

## `maxRequests` (type: `integer`):

Includes robots.txt requests. No retries or proxy escalation.

## `monitorId` (type: `string`):

Reuse for daily diffs. Change for a new market/configuration. Account-private persistent named KVS; not a schedule.

## `emitPersistent` (type: `boolean`):

False emits new/changed/resolved only. Diagnostics still emitted.

## `enrichShopifyGtin` (type: `boolean`):

Read the documented public product Ajax API once per product, matching the exact variant ID. Adds a request; missing/invalid GTIN stays UNKNOWN. Does not copy the landing-page GTIN into feed expectations.

## Actor input object example

```json
{
  "stores": [
    {
      "url": "https://theme-dawn-demo.myshopify.com",
      "platform": "shopify",
      "currency": "CAD"
    }
  ],
  "feedUrls": [],
  "feedItems": [],
  "maxItems": 5,
  "maxRequests": 20,
  "monitorId": "demo-feed",
  "emitPersistent": false,
  "enrichShopifyGtin": true
}
```

# Actor output Schema

## `results` (type: `string`):

No description

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

No description

## `snapshot` (type: `string`):

No description

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("jeanswiegers/shopping-feed-leak-watch").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("jeanswiegers/shopping-feed-leak-watch").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 '{}' |
apify call jeanswiegers/shopping-feed-leak-watch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jeanswiegers/shopping-feed-leak-watch"
        }
    }
}
```

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/iiDFEDwlFHiZ3O8Jb/builds/RZ7Mad5kaoMISNX6I/openapi.json
