# Google Merchant Feed Audit: Product Feed Errors & Changes (`zaiq/merchant-feed-quality`) Actor

Check your product feed for invalid fields, duplicate IDs and changes. Optionally compare exact variants against public product-page structured data.

- **URL**: https://apify.com/zaiq/merchant-feed-quality.md
- **Developed by:** [Zaiq](https://apify.com/zaiq) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 product batches

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

## Merchant Feed Health & Change Audit

![Merchant Feed Health & Change Audit: Check your product feed for invalid fields, duplicate IDs and changes](https://api.apify.com/v2/key-value-stores/4VJNANhwKgqPpXtAi/records/hero-merchant-feed-quality.jpg)

Check a product feed for missing or duplicate identifiers, invalid prices, currency and availability values, and optional GTIN checksum errors. Compare compatible complete snapshots to see issue changes.

Use your own feed text or a record in Apify's key-value store, or point to an existing Apify dataset. The default is a free fictional demo. Optional public product-page checks require an exact SKU and declared matching locale.

### What you get

| Field | What it holds |
|---|---|
| Product batches | Up to ten validated products per row, with stable result ID, issues and supplied metrics. |
| Page evidence | Optional free JSON-LD comparison, or an explicit unknown or blocked note; batch charges cover feed validation only. |
| SUMMARY | Completion, counts, notes, snapshot and comparable changes. |
| HTML report | Issue counts and changes for a completed audit. |

### What people use it for

- **Feed checks:** Find errors before sending a feed.
- **Recurring audits:** Compare issue changes for the same complete feed and rules.
- **Prioritisation:** Order issues by impressions provided by the buyer.

### How to use it

1. Run the free fictional demo or supply feed text, a default-store record, or select a dataset.
2. Choose a format, market currency and product limit. Optionally enable public page checks and provide a locale.
3. Open the dataset and SUMMARY. For changes, use a stable scope and pass the previous complete snapshot in the next input.
4. Select an existing private product dataset with the dataset picker (READ). Legacy dataset ID/name inputs remain for environments where access is already granted; they do not themselves grant limited-permission access. Use one input source. The record key refers to the run default store.

### Input

| Field | Example | Notes |
|---|---|---|
| Feed text | CSV, TSV, JSON or XML | One source per run; maximum 5 MB and 5,000 rows. |
| Record key, dataset picker or legacy dataset ID/name | Your Apify storage | Keep customer data in your own Apify storage. |
| Market currency | USD | Optional ISO currency rule. |
| Snapshot scope | feed-a | Use the same label and rules across complete runs. |

### Output

Each result is one row in the run's dataset (download it as JSON, CSV, Excel, XML or HTML, or read it through the API). An example row (values shortened):

```json
{
  "recordType": "product-batch",
  "demo": true,
  "products": [
    {
      "id": "demo-001",
      "price": "12.00",
      "currency": "USD",
      "availability": "in stock",
      "issues": [],
      "metrics": {
        "impressions": "120"
      }
    }
  ],
  "syntheticLabel": "Fictional synthetic demo; not real buyer data."
}
```

This example is fictional synthetic demo data, not a real run of a seller's feed. The SUMMARY record gives counts, notes and, for complete audits with a scope, the snapshot and changes. The input example is fictional and sanitised. Missing, duplicate or oversized IDs are not charged. For multiple such rows, one free dataset note contains every 1-based input row number in rowIndexes; a single invalid row is named in its note's message. SUMMARY.invalidItems gives the count within the selected product limit. These IDs make the audit incomplete, so no report or snapshot comparison is produced.

### Pricing

- The fictional demo is free.
- $0.02 per batch of up to 10 identified products for feed validation, including a partial final batch; page checks are separate and free, even when unavailable; missing and duplicate IDs are free notes.
- $0.10 for an optional completed report; incomplete reports are free.
- Apify's start charge is $0.00005 per GB of allocated RAM, rounded up, with a minimum of one unit.

What typical jobs cost at the list price:

| Job | Cost |
|---|---|
| Fictional demo | Free, aside from any platform start charge |
| 10 products without report at up to 1 GB | $0.02005 including start |
| 21 products and a report at up to 1 GB | $0.16005 including start |

Set the maximum run cost. Remaining batches and reports are skipped when they do not fit; free notes remain available. The platform start charge varies with allocated RAM.

### Tips

- Use the same scope and rules to compare snapshots.
- Supply impressions to rank reported issues; they are not estimates of lost sales.

### Use it through the API

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("zaiq/merchant-feed-quality").call(run_input={"feedText": "id,price,currency,availability\nfictional-item-001,12.00,USD,in stock\n", "format": "csv"})
for row in client.dataset(run.default_dataset_id).iterate_items():
    print(row)
```

**JavaScript**

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('zaiq/merchant-feed-quality').call({"feedText": "id,price,currency,availability\nfictional-item-001,12.00,USD,in stock\n", "format": "csv"});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

**HTTP (one call, results back)**

```bash
curl -X POST 'https://api.apify.com/v2/acts/zaiq~merchant-feed-quality/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>' \
  -H 'Content-Type: application/json' \
  -d '{"feedText": "id,price,currency,availability\nfictional-item-001,12.00,USD,in stock\n", "format": "csv"}'
```

### Integrations and schedules

- **Schedules:** run it every hour, day or week from the Apify Console (Schedules) and keep a history of results.
- **Make, Zapier, n8n, Google Sheets, Slack, Airtable:** connect it through Apify's integrations, or send each finished run to a **webhook**.
- **Datasets:** results stay in the run's dataset; export them or read them by API whenever you need them.

### Use it with AI agents (MCP)

Add Apify's MCP server (`https://mcp.apify.com`) to Claude, ChatGPT, Cursor, VS Code or any MCP client. The agent can find this Actor and run it for you: ask it for an audit of my product feed. AI agents can also pay for runs directly through Apify's agentic payments.

### Limits

- Does not check actual merchant approval, ad performance, sales, losses or stock quantities.
- GTIN is optional; a supplied value is checked for length and checksum only.
- Page comparisons need one Product with an exact SKU, one Offer, a matching declared locale, price, currency and availability. Otherwise the result is unknown.
- Only public HTTPS URLs without credentials or query strings are accepted. No redirects or retries. A login, CAPTCHA, human or bot check, 401, 403 or 429 immediately stops all page checks.
- At most 20 page requests per run, with at least one second between starts within that run. The buyer must have permission to use the supplied data and URLs.
- Snapshot comparison requires complete audits, the same scope and rules, and unique IDs; removed products are shown separately rather than called resolved issues.
- Currency recognition uses a bundled list and needs periodic updates. Dataset and key-value access depend on Apify permissions.
- On a same-run restart, uncertain billing or mismatched event counts stop further paid work and require review; existing output is retained. This does not guarantee exactly-once charging.
- Concurrent executions sharing the same default store are last-writer-wins for SUMMARY and REPORT.html. Run-scoped result IDs and report records do not provide transactional billing.

### FAQ

**Is GTIN required?**

No. If present, its length and checksum are checked.

**Can this prove approval or lost sales?**

No. It checks supplied fields and optional page evidence only.

**Does it edit my feed?**

No.

**Is the demo a real seller?**

No, all demo records are fictional.

### Related Actors from Zaiq

- [shopify-products-scraper](https://apify.com/zaiq/shopify-products-scraper): collect product data into a dataset

### Support

Questions, a site that changed, or a field you need? Open an issue on this Actor's **Issues** tab: we answer there, usually within a day.

***

Also found as: merchant feed audit, product feed validation, feed quality, product data audit.

# Actor input Schema

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

Paste UTF-8 CSV, TSV, JSON array, or XML. Leave empty to use a storage input or the fictional free demo.

## `format` (type: `string`):

Format of feed text or record.

## `recordName` (type: `string`):

Optional key in the default key-value store containing feed content. Use an API upload to that record before starting the Actor.

## `datasetId` (type: `string`):

Optional ID of your Apify dataset containing product objects. Provide exactly one input source. Legacy input: it does not itself grant limited-permission access; use the corresponding resource picker for private storage.

## `marketCurrency` (type: `string`):

Optional ISO 4217 currency code. Applied only to the source currency field, without guessing a market.

## `marketLocale` (type: `string`):

Required for page comparisons, for example en_US. Comparison stays unknown unless the page explicitly declares this locale.

## `comparePages` (type: `boolean`):

Fetch permitted public HTTPS links. Page checks are free; product-batch charges cover feed validation only. A login, verification, 401, 403 or 429 stops all page checks immediately.

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

Optional snapshot copied from a complete earlier SUMMARY. Differences are shown only for matching scope and complete audits.

## `snapshotScope` (type: `string`):

A stable label identifying the same complete feed and market in each run. Required for snapshot comparisons.

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

Bound the feed to at most this many products. If the feed exceeds the limit the audit is incomplete and no snapshot comparison is made.

## `report` (type: `boolean`):

For a complete non-demo audit, create an HTML report and charge one report event. The free demo includes a free report.

## `datasetName` (type: `string`):

Optional name of your Apify dataset containing product objects. Use one input source only. Legacy input: it does not itself grant limited-permission access; use the corresponding resource picker for private storage.

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

Select an existing buyer dataset of product objects. Use one input source only.

## Actor input object example

```json
{
  "feedText": "",
  "format": "csv",
  "recordName": "",
  "datasetId": "",
  "marketCurrency": "",
  "marketLocale": "",
  "comparePages": false,
  "snapshotScope": "",
  "maxProducts": 1000,
  "report": true,
  "datasetName": ""
}
```

# Actor output Schema

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

Dataset: the results.

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

What each input returned, and notes.

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

A one-page view of the results to open in a browser.

# 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("zaiq/merchant-feed-quality").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("zaiq/merchant-feed-quality").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 zaiq/merchant-feed-quality --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zaiq/merchant-feed-quality"
        }
    }
}
```

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/RixRgD54uI6mnxDcA/builds/Fw8WgNfdlRmXS1VJT/openapi.json
