# Product Feed Validator (`gifted_wagon/product-feed-validator`) Actor

Catch missing fields, invalid prices, duplicate IDs, inconsistent variants, and Google Merchant feed risks before import.

- **URL**: https://apify.com/gifted\_wagon/product-feed-validator.md
- **Developed by:** [Michael Olmos](https://apify.com/gifted_wagon) (community)
- **Categories:** E-commerce, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 1,000 product validateds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## Product Feed Validator

Catch catalog defects **before** they become rejected products, broken ads, failed imports, or manual cleanup work.

Product Feed Validator normalizes and checks product rows from an Apify dataset, an upstream Actor, or inline JSON. Every completed row gets a readiness score, structured issue evidence, and field-level repair suggestions. The checks are deterministic, require no external API key, and exclude original source rows from output by default.

### Why use it?

Product feeds often fail for ordinary but expensive reasons: missing required attributes, malformed prices, invalid links, duplicate IDs, bad identifiers, promotional titles, and variants that disagree with each other. Finding those issues after an import or campaign launch costs time and can interrupt revenue.

Use this Actor as a preflight gate before Google Merchant Center, an advertising workflow, a marketplace import, a PIM migration, or a catalog handoff.

### Validation profiles

- `google_merchant_2026` checks current structural requirements and common risk patterns from the Google Merchant product data specification.
- `generic_ecommerce` checks a smaller, channel-neutral product core and reports missing images or availability as recommendations.

Rules are versioned in every output row. The current Google profile covers the required `id`, `title`, `description`, `link`, `image_link`, `availability`, and `price` structure; field limits; price and sale-price consistency; URL formats; availability and condition values; GTIN check digits; identifier completeness; and title hygiene. It also performs whole-batch checks for duplicate IDs, reused links, inconsistent variant brands, and repeated color/size combinations.

This is deterministic preflight guidance. It does not crawl links, inspect image dimensions, verify inventory, or guarantee approval by Google or any other channel.

### Quick start

Run with no input to validate a safe built-in product, or paste products directly:

```json
{
  "products": [
    {
      "id": "runner-42-black",
      "title": "Example Men's Black Running Shoes - Size 42",
      "description": "Lightweight black running shoes with a breathable mesh upper and rubber sole.",
      "link": "https://example.com/products/runner-42-black",
      "image_link": "https://example.com/images/runner-42-black.jpg",
      "availability": "in_stock",
      "price": "79.99 USD",
      "brand": "Example",
      "gtin": "4006381333931",
      "condition": "new"
    }
  ]
}
```

For production, select an Apify dataset:

```json
{
  "datasetId": "YOUR_DATASET_ID",
  "profile": "google_merchant_2026",
  "maxProducts": 500,
  "includeNormalizedProduct": true,
  "includeOriginalProduct": false
}
```

Inline products and a selected dataset may be combined. The `maxProducts` limit applies across both sources and is capped at 5,000 per run.

### Field mapping

Common snake\_case and camelCase attributes are detected automatically. For a custom schema, map canonical fields to source paths:

```json
{
  "datasetId": "YOUR_DATASET_ID",
  "fieldMap": {
    "id": "catalog.sku",
    "title": "catalog.displayName",
    "imageLink": "media.primary.url",
    "price": "offers.current",
    "itemGroupId": "variants.parentSku"
  }
}
```

Dot-separated paths are supported, and an explicit mapping is tried before automatic aliases. Supported canonical fields include `id`, `title`, `description`, `link`, `imageLink`, `additionalImageLinks`, `availability`, `price`, `salePrice`, `brand`, `gtin`, `mpn`, `condition`, `itemGroupId`, `color`, `size`, `gender`, `ageGroup`, and `identifierExists`.

Prices can be numbers, strings such as `79.99 USD` or `USD 79.99`, or objects such as `{"amount":79.99,"currency":"USD"}`.

### Use it after another Actor

Add Product Feed Validator from the source Actor's **Integrations** tab. The upstream run's default dataset is accepted automatically, so a crawler or scraper can feed directly into validation.

Typical workflows:

- ecommerce scraper → feed validation → repair queue
- PIM export → feed validation → marketplace import
- scheduled catalog dataset → validation → webhook or alert
- merchant feed update → validation → ad-campaign gate

### Output

The default dataset contains one result per completed `product-validated` event:

```json
{
  "productId": "broken-104",
  "status": "invalid",
  "qualityScore": 41,
  "grade": "F",
  "issueCodes": [
    "LINK_INVALID",
    "PRICE_CURRENCY_MISSING_OR_INVALID",
    "PRODUCT_IDENTIFIERS_INCOMPLETE"
  ],
  "issues": [
    {
      "code": "LINK_INVALID",
      "severity": "error",
      "field": "link",
      "message": "Product link is not a valid HTTP or HTTPS URL.",
      "observed": "product/104",
      "expected": "An absolute HTTP or HTTPS URL",
      "ruleSource": "Google Merchant Center product data specification (accessed 2026-08-05)"
    }
  ],
  "repairSuggestions": [
    {
      "issueCode": "LINK_INVALID",
      "field": "link",
      "action": "Replace or map link so it matches: An absolute HTTP or HTTPS URL."
    }
  ]
}
```

Each row also includes severity counts, a ruleset version, normalized fields when enabled, and a validation timestamp. The default key-value-store `OUTPUT` record contains batch totals, grade distribution, issue counts, average score, source type, budget status, and the applied profile.

### Automate through the API

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/gifted_wagon~product-feed-validator/runs" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"datasetId":"YOUR_DATASET_ID","maxProducts":500}'
```

The run response contains storage IDs for the row-level results and summary. You can also call the Actor from an Apify client, schedule, webhook, Make, Zapier, or another Actor.

### Privacy and permissions

- Limited permissions: read the selected dataset; write the run's default dataset and key-value store.
- No product data is sent to an external AI model or validation service.
- Source URLs and image URLs are checked structurally but are not requested.
- Original product objects are excluded unless `includeOriginalProduct` is explicitly enabled.
- Output storage follows the access controls of the account running the Actor.

### Pricing

You pay for completed `product-validated` events only.

| Apify tier | Price per 1,000 products |
|---|---:|
| Free | $1.25 |
| Bronze | $1.00 |
| Silver | $0.75 |
| Gold, Platinum, Diamond | $0.50 |

There is also a $0.00005 Actor-start event. The Actor checks the run spending limit before paid work and stops cleanly when the remaining budget cannot cover another product.

### Scope and rule maintenance

The Google profile is based on the [Google Merchant product data specification](https://support.google.com/merchants/answer/7052112?hl=en) and is labeled with a version and access date. Channel requirements can change. The Actor's changelog records material rule updates, and a profile should be disabled or revised if a specification change makes it materially inaccurate.

The validator cannot determine factual accuracy, legal eligibility, policy compliance, landing-page equivalence, live stock, image quality, or account-specific enforcement. Review [Google's current 2026 specification changes](https://support.google.com/merchants/answer/16989427?hl=en) before relying on a rule for a high-risk workflow.

### Support

If your dataset uses an unsupported shape or a finding appears incorrect, open an issue from the Actor's **Issues** tab. Include the run ID, issue code, field mapping, and a redacted example. Do not post private catalog data in a public issue.

# Actor input Schema

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

Select an existing Apify dataset containing product rows.

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

Optional product objects. Common snake\_case and camelCase fields are detected automatically.

## `profile` (type: `string`):

Google Merchant 2026 applies current structural requirements. Generic ecommerce checks a smaller channel-neutral core.

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

Maximum number of product rows to read and charge for across all sources.

## `fieldMap` (type: `object`):

Optional canonical-field to source-path map, for example {"id":"sku","imageLink":"media.primary.url"}. Dot-separated paths are supported.

## `includeNormalizedProduct` (type: `boolean`):

Include the normalized canonical fields used by the validator in each result.

## `includeOriginalProduct` (type: `boolean`):

Copy the full original input row into each result. Enable only when the output dataset may safely retain the complete source record.

## `payload` (type: `object`):

Automatically supplied by Apify when this Actor is connected to another Actor run.

## Actor input object example

```json
{
  "products": [
    {
      "id": "runner-42-black",
      "title": "Example Men's Black Running Shoes - Size 42",
      "description": "Lightweight black running shoes with a breathable mesh upper and rubber sole.",
      "link": "https://example.com/products/runner-42-black",
      "image_link": "https://example.com/images/runner-42-black.jpg",
      "availability": "in_stock",
      "price": "79.99 USD",
      "brand": "Example",
      "gtin": "4006381333931",
      "condition": "new",
      "item_group_id": "runner-black",
      "color": "Black",
      "size": "42"
    }
  ],
  "profile": "google_merchant_2026",
  "maxProducts": 500,
  "fieldMap": {},
  "includeNormalizedProduct": true,
  "includeOriginalProduct": false
}
```

# Actor output Schema

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

One result for each product that was validated within the run budget.

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

Counts, scores, ruleset, and budget status for the run.

# 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": "runner-42-black",
            "title": "Example Men's Black Running Shoes - Size 42",
            "description": "Lightweight black running shoes with a breathable mesh upper and rubber sole.",
            "link": "https://example.com/products/runner-42-black",
            "image_link": "https://example.com/images/runner-42-black.jpg",
            "availability": "in_stock",
            "price": "79.99 USD",
            "brand": "Example",
            "gtin": "4006381333931",
            "condition": "new",
            "item_group_id": "runner-black",
            "color": "Black",
            "size": "42"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("gifted_wagon/product-feed-validator").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": "runner-42-black",
            "title": "Example Men's Black Running Shoes - Size 42",
            "description": "Lightweight black running shoes with a breathable mesh upper and rubber sole.",
            "link": "https://example.com/products/runner-42-black",
            "image_link": "https://example.com/images/runner-42-black.jpg",
            "availability": "in_stock",
            "price": "79.99 USD",
            "brand": "Example",
            "gtin": "4006381333931",
            "condition": "new",
            "item_group_id": "runner-black",
            "color": "Black",
            "size": "42",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("gifted_wagon/product-feed-validator").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": "runner-42-black",
      "title": "Example Men'\''s Black Running Shoes - Size 42",
      "description": "Lightweight black running shoes with a breathable mesh upper and rubber sole.",
      "link": "https://example.com/products/runner-42-black",
      "image_link": "https://example.com/images/runner-42-black.jpg",
      "availability": "in_stock",
      "price": "79.99 USD",
      "brand": "Example",
      "gtin": "4006381333931",
      "condition": "new",
      "item_group_id": "runner-black",
      "color": "Black",
      "size": "42"
    }
  ]
}' |
apify call gifted_wagon/product-feed-validator --silent --output-dataset

```

## MCP server setup

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

```

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/qa0O92xqY56TCcQde/builds/QxgJn8zx9mVbmxOaS/openapi.json
