# Shopping Feed Price & Stock Auditor (`voidstar17/shopping-feed-price-auditor`) Actor

Audit Google Shopping and Merchant Center feed prices, currencies and stock against live product-page structured offers. CSV/XML/JSON inputs, evidence per mismatch, cautious variant matching and scheduled checks. No account access.

- **URL**: https://apify.com/voidstar17/shopping-feed-price-auditor.md
- **Developed by:** [Riccardo Vecchi](https://apify.com/voidstar17) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$10.00 / 1,000 product page 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?

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

## Shopping Feed Price & Stock Auditor

Compare your Shopping feed with the structured offers actually published on your product landing pages. Find price, currency and stock mismatches, with the expected value, observed value, product identity and source URL in every report.

Built for ecommerce teams and PPC agencies that refresh catalogs on a schedule. It reads public pages and returns evidence; it never changes campaigns, feed data or Merchant Center settings.

### Quick start

Paste product records into **Products with expected feed values** and click Start:

```json
{
  "products": [{
    "id": "demo-bulbasaur",
    "url": "https://scrapeme.live/shop/Bulbasaur/",
    "price": "63.00 GBP",
    "availability": "in_stock"
  }],
  "maxProducts": 100,
  "priceTolerance": 0.01
}
```

The prefilled URL belongs to a public scraping demonstration store. Its live price can change; the example expected price is a test input, not a fixture injected into the output. Change the expected price to test a mismatch.

Alternatively, clear `products` and supply **feedUrl** or **feedText**. Use exactly one source. Supported formats: comma-delimited CSV, tab-delimited TSV, Google RSS/Atom XML, or a JSON array / `items` / `products` array. Files must be uncompressed UTF-8, at most 5 MB and 10,000 items. No private account or feed API connection is needed.

### What it checks

- Expected feed price versus an identified JSON-LD Product/Offer or scoped Microdata offer.
- Expected currency versus the offer currency, without conversion or guessing.
- `in_stock`, `out_of_stock`, `preorder` and `backorder` versus supported schema.org availability values.
- Active sale prices, including timezone-aware `sale_price_effective_date` intervals.
- Product identity through an explicit GTIN, explicit SKU, exact offer URL, or a single unambiguous offer on a URL without a variant query.
- Landing-page HTTP failures, robots exclusions, missing offers and ambiguous variants as explicit diagnostics or review records.

Variant query parameters are retained. If your feed `id` is also the product SKU, supply it explicitly as `sku` for identity matching. A feed ID is not automatically treated as a SKU.

### Input fields

Product records use `id`, `url` (or `link`), `price`, optional `currency`, `availability`, `sku`, `gtin`, `sale_price` and `sale_price_effective_date`. Price can be `19.99 EUR`, or a number with `currency: "EUR"`. Use decimal points. Sale intervals require explicit timezones, for example `2026-10-01T00:00:00Z/2026-10-31T23:59:59Z`.

`maxProducts` selects up to 1,000 records per run. `startOffset` selects later slices in a larger feed. The summary states the input size and selected slice; partial coverage is never presented as a full-feed audit. Exact duplicate input records are merged; different variants are kept.

### Results

| Field | Meaning |
| --- | --- |
| `status` | `match`, `mismatch`, `review`, `fetch_failed`, `skipped` or `unsupported` |
| `expectedPrice`, `expectedCurrency`, `expectedAvailability` | Values submitted in your feed |
| `observedPrice`, `observedCurrency`, `observedAvailability` | Values from the selected structured offer |
| `priceDifference` | Observed minus expected, only when currencies agree |
| `priceResult`, `availabilityResult` | Separate comparison outcomes |
| `matchMethod` | Identity selection or the reason identity was uncertain |
| `issues`, `reviewReasons` | Machine-readable discrepancy and uncertainty codes |
| `evidence` | Selected offer, identifiers, extraction method and source URL |
| `suggestedAction` | Next check to investigate the discrepancy |

Export JSON, CSV or Excel. Flat `issuesText` and `reviewText` fields are ready for spreadsheets. The key-value store also contains `SUMMARY` and a short `REPORT.md`.

### Pricing

**$10 per 1,000 successfully analyzed HTML landing pages ($0.01 each), platform usage included.** One `page-audited` event per HTML report, including `match`, `mismatch` and `review`. Missing structured offers still produce a useful review report and are charged when HTML was successfully analyzed. HTTP failures, robots exclusions, non-HTML responses and invalid input diagnostics are uncharged. No start fee or additional fee per detected problem.

Set the maximum charge in Run options to bound charged results. At $0.01 per report, 200 daily checks over 30 days cost $60; this is a buyer-cost example, not a savings or revenue forecast.

### Recurring use

Save a task with your public feed URL and schedule it daily or after catalog updates. Read the dataset through the Apify API or Make/n8n/Zapier and filter `status == "mismatch"` for alerts. The Actor does not send messages itself. It audits the selected feed slice afresh on each run; it does not maintain a historical price database.

### Scope and limitations

This is a **structured-data parity audit**. A match is not verification of rendered visible prices, checkout, taxes, shipping, discounts requiring membership, regional pricing, Google approval or account compliance. These require additional review. No monetary recovery or prevention of disapprovals is guaranteed.

Server HTML only: no JavaScript rendering, login, CAPTCHA bypass, proxy requirement or paid external API. JSON-LD and scoped Microdata are supported. Aggregate price ranges, multiple conflicting offers, unidentified variants and unsupported availability values are marked for review rather than guessed. At most 100 distinct structured offers per page are examined.

The crawler respects robots.txt, accepts public HTTP(S) destinations on standard ports only, rejects private/reserved networks, pins DNS resolution and permits redirects within the same hostname/www boundary. It waits at least one second between requests on an origin and honors crawl delays up to 10 seconds. HTML responses are capped at 2 MB and individual requests at 12 seconds. Some stores therefore return uncharged diagnostics; test representative URLs before auditing a large catalog.

For support, open an Actor issue with a public product URL, run ID and expected field values. Do not post private feed URLs, tokens or customer information.

### References

- [Google: price inconsistencies between feed and landing page](https://support.google.com/merchants/answer/9773429)
- [Google: product data specification](https://support.google.com/merchants/answer/7052112)
- [Google: Product structured data](https://developers.google.com/search/docs/appearance/structured-data/product-snippet)

Independent tool; not affiliated with Google, Shopify or WooCommerce.

# Actor input Schema

## `products` (type: `array`):

Product records with id, url/link, price, currency, availability, sku/gtin and optional sale fields. Clear this example when using a feed.

## `feedUrl` (type: `string`):

Public uncompressed UTF-8 CSV, TSV, RSS/Atom XML or JSON feed. Use one source only; clear products. At most 5 MB.

## `feedText` (type: `string`):

Paste an uncompressed feed up to 5 MB. Use one source only; clear products.

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

Selected feed slice, at most 1,000 landing pages per run.

## `startOffset` (type: `integer`):

Zero-based offset into the feed for controlled batch slices.

## `priceTolerance` (type: `number`):

Maximum accepted absolute difference, in the expected currency. Set 0 for exact comparison.

## `concurrency` (type: `integer`):

Up to five workers; requests to one origin remain serialized and polite.

## Actor input object example

```json
{
  "products": [
    {
      "id": "demo-bulbasaur",
      "url": "https://scrapeme.live/shop/Bulbasaur/",
      "price": "63.00 GBP",
      "availability": "in_stock"
    }
  ],
  "feedUrl": "",
  "feedText": "",
  "maxProducts": 100,
  "startOffset": 0,
  "priceTolerance": 0.01,
  "concurrency": 3
}
```

# Actor output Schema

## `reports` (type: `string`):

No description

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

No description

## `report` (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 = {
    "products": [
        {
            "id": "demo-bulbasaur",
            "url": "https://scrapeme.live/shop/Bulbasaur/",
            "price": "63.00 GBP",
            "availability": "in_stock"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("voidstar17/shopping-feed-price-auditor").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 = { "products": [{
            "id": "demo-bulbasaur",
            "url": "https://scrapeme.live/shop/Bulbasaur/",
            "price": "63.00 GBP",
            "availability": "in_stock",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("voidstar17/shopping-feed-price-auditor").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 '{
  "products": [
    {
      "id": "demo-bulbasaur",
      "url": "https://scrapeme.live/shop/Bulbasaur/",
      "price": "63.00 GBP",
      "availability": "in_stock"
    }
  ]
}' |
apify call voidstar17/shopping-feed-price-auditor --silent --output-dataset

```

## MCP server setup

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

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/0hy2BtOXyUj4YFnRn/builds/hhaJaR6NRwLwqXnv0/openapi.json
