# Merchant Feed Mismatch Checker (`proficientstack/merchant-feed-mismatch-checker`) Actor

Finds product pages where the schema.org price does not match the price shown on the page. Google reads the page and overrides your Merchant Center feed with it, so the store ends up advertising the wrong price or getting the product disapproved.

- **URL**: https://apify.com/proficientstack/merchant-feed-mismatch-checker.md
- **Developed by:** [Gabriel Barreto](https://apify.com/proficientstack) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-usage

## 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 Mismatch Checker

Finds product pages where the **schema.org price does not match the price shown on the page**.

This matters because of how Google actually behaves. Google's *automatic item updates* read price, availability and condition from the schema.org markup on your product page. When the page disagrees with your Merchant Center feed, **Google overrides the feed with the page** — so the store advertises the wrong price. When Google cannot determine the price at all, the product is disapproved.

> Source: [Google Merchant Center — automatic item updates](https://support.google.com/merchants/answer/3246284)

Give it a store homepage. It finds the product pages itself through the sitemap declared in `robots.txt`, samples them, and returns a **count you can verify**: "31 of 120 product pages checked". Not a percentage, not a promise — a number and three example URLs you can open right now.

### Who this is for

- **Google Ads and Shopping agencies** auditing a prospect or a new account before the first call.
- **Store owners** who keep getting disapprovals in Merchant Center and cannot see why.
- **Anyone who changed theme, currency, or pricing app** and wants to know what broke.

### What it refuses to report

A scanner that overreports costs more than it is worth: the person opens the page, sees nothing wrong, and concludes you do not know what you are talking about. Every guard below exists because the naive version got it wrong on a real store.

- **Recommended-product carousels.** On one store the scanner reported 8 of 8 pages as "price mismatch". The first JSON-LD block on the page belonged to a power socket in the recommendations; the page was a curtain. Now the right `Product` is the one whose `url`/`@id` matches the requested URL — and if several candidates exist and none match, nothing is claimed.
- **Schema injected by JavaScript.** If the `<script type="application/ld+json">` tags are present but empty, Google executes JS and sees the schema; we do not. Reporting a gap there would be a lie.
- **Struck-through, "compare-at", "from" and unit prices**, which produced false mismatches.
- **`$21 $30` read as `2130`** when the element text was joined instead of taking the first price.
- **Bundles, sets and gift cards**, where the schema legitimately sums several items while the page shows one.
- **"InStock but sold out" is not checked at all.** In static HTML that phrase belongs to a *size* ("Select A Size … Out of stock"), not the product. Tested on a real store: 9 of 14 accusations were false. Precision beats coverage.
- **Variants.** In a `ProductGroup` every variant carries its own price; the page shows one of them. All variant prices are collected before comparing, so showing variant #3 is not a mismatch.

### Input

| Field | Type | Description |
|---|---|---|
| `urls` | string list | Store homepages, one per line. Not product URLs. |
| `maxProducts` | integer | Product pages to sample per store. Default 25. |
| `onlyTargets` | boolean | Return only stores with findings. |
| `maxConcurrency` | integer | Stores crawled in parallel. Default 5. |

```json
{
    "urls": ["allbirds.com", "books.toscrape.com"],
    "maxProducts": 25,
    "onlyTargets": false
}
```

### Output

| Field | Meaning |
|---|---|
| `finding` | e.g. "31 of 120 product pages checked would be overridden or disapproved by Google". |
| `serious` | Pages with a price mismatch, no `Product` schema, or no price in the schema. |
| `minor` | Pages missing GTIN/MPN or brand — these cost you Shopping and PMax reach, not approval. |
| `clean` | Pages with nothing to report. |
| `indeterminate` | Pages we could not read from the outside. Counted, never claimed. |
| `examples` | Up to three URLs with the specific problem, so you can check before you speak. |
| `source` | The Google documentation page the finding rests on. |

### Pricing

Pay per store with findings. Clean stores, indeterminate stores and failures are all returned in the dataset **free of charge**.

### Notes

The sitemap is read from `robots.txt` first — trying only `/sitemap.xml` failed on 4 out of 5 real stores. Gzipped sitemaps are decompressed, which matters because the largest catalogues are exactly the ones served compressed. TLS certificates are verified.

# Actor input Schema

## `urls` (type: `array`):

One store per line. Paste the homepage (example.com), not a product URL — the Actor finds the product pages itself through the sitemap declared in robots.txt.

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

How many product pages to sample from each store. More pages means a more reliable count and a slower run.

## `onlyTargets` (type: `boolean`):

Skip stores where every sampled product page is clean or indeterminate.

## `maxConcurrency` (type: `integer`):

How many stores to crawl at the same time.

## Actor input object example

```json
{
  "urls": [
    "allbirds.com",
    "books.toscrape.com"
  ],
  "maxProducts": 25,
  "onlyTargets": false,
  "maxConcurrency": 5
}
```

# Actor output Schema

## `findings` (type: `string`):

One row per store: how many product pages were checked, how many Google would override or disapprove, and up to three example URLs you can open and verify yourself.

# 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 = {
    "urls": [
        "allbirds.com",
        "books.toscrape.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("proficientstack/merchant-feed-mismatch-checker").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 = { "urls": [
        "allbirds.com",
        "books.toscrape.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("proficientstack/merchant-feed-mismatch-checker").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 '{
  "urls": [
    "allbirds.com",
    "books.toscrape.com"
  ]
}' |
apify call proficientstack/merchant-feed-mismatch-checker --silent --output-dataset

```

## MCP server setup

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

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/Ie5zpH8vKgdbCXKGw/builds/raIPRVb00haaOubnO/openapi.json
