# Feed Delta Guard — Product Feed Regression Audit (`passionate_legacy_pev/feed-delta-guard`) Actor

Compare product-feed snapshots to flag price changes, missing products, duplicate IDs and availability changes. Supply JSON, CSV or TSV and get English or Japanese reports in JSON, CSV, HTML and dataset output.

- **URL**: https://apify.com/passionate_legacy_pev/feed-delta-guard.md
- **Developed by:** [M TSUTSUMI](https://apify.com/passionate_legacy_pev) (community)
- **Security:** Limited permissions
- **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

## Feed Delta Guard

Check product-feed snapshots before an import or catalog update. Feed Delta Guard highlights price changes, missing or added products, duplicate IDs and availability changes, with finding messages in English or Japanese. Supply your own JSON rows or CSV/TSV text; no website access is needed.

### Start with two snapshots

Paste this synthetic example into the Actor input:

```json
{
  "currentRows": [
    {"id": "SKU-001", "price": "70.00 USD", "availability": "out_of_stock"},
    {"id": "SKU-003", "price": "15.00 USD", "availability": "in_stock"}
  ],
  "previousRows": [
    {"id": "SKU-001", "price": "100.00 USD", "availability": "in_stock"},
    {"id": "SKU-002", "price": "20.00 USD", "availability": "in_stock"}
  ],
  "priceDropPercent": 20,
  "priceIncreasePercent": 50,
  "removalPercent": 20,
  "reportLanguage": "en"
}
```

This example identifies SKU-001's price drop and availability change, SKU-002's removal and SKU-003's addition. The removal share also reaches the configured threshold. All example products are synthetic.

Provide exactly one of `currentRows` and `currentCsv`. For a comparison, also provide exactly one of `previousRows` and `previousCsv`. The baseline must be supplied explicitly on every run: it is not saved or automatically loaded from a previous run. Omit both previous fields for an initial audit; that checks current fields without inventing added or removed products. `previousRows: []` is an explicit empty baseline. `currentRows: []` is allowed and can reveal total product loss against a supplied baseline.

### CSV and TSV input

Use CSV/TSV text with a header instead of JSON rows. Remove any prefilled `currentRows` before using `currentCsv`. For example:

```json
{
  "currentCsv": "id,price,availability\nSKU-001,70.00 USD,out_of_stock\n",
  "previousCsv": "id,price,availability\nSKU-001,100.00 USD,in_stock\n",
  "delimiter": "comma",
  "reportLanguage": "ja"
}
```

For TSV, use tab characters (`\t` in JSON strings) and `delimiter: "tab"`. The default `auto` detects comma or tab. Quoted CSV cells and multiline values are supported; malformed records fail validation. CSV record numbers start at 2 after the header and count logical records, including quoted multiline values as one record. JSON record numbers start at 1.

Map custom columns with `idField`, `priceField`, `currencyField`, `availabilityField` and `gtinField`. Defaults are `id`, `price`, `currency`, `availability` and `gtin`. Mappings must be distinct and are case-sensitive. Headers are trimmed; product ID values preserve case, whitespace and leading zeros exactly. IDs must be nonblank strings; numeric IDs are not converted.

### Checks and settings

- **Prices:** non-negative plain decimals such as `100.00 USD`, or `100.00` with a separate `currency` field or `defaultCurrency`. Negative prices, comma separators and exponent notation are rejected as price findings. Missing prices produce warnings and prevent price comparison. Zero prices are flagged for review; relative growth from a zero baseline is not computed.
- **Price changes:** `priceDropPercent` defaults to 20 and `priceIncreasePercent` to 50. Thresholds are inclusive. Both prices must be valid and use the same currency. Currency changes are reported separately; there is no FX conversion. Currency validation checks three uppercase letters only, without consulting a currency registry. Conflicting inline and separate currencies are flagged.
- **Added and missing products:** compare IDs between snapshots. `removalPercent` defaults to 20 and flags a removal share at or above that percentage of eligible previous products.
- **Duplicate IDs:** report every duplicate copy in either snapshot. An ID duplicated in either snapshot is excluded from all difference comparisons and added/removed counts; it is never silently overwritten. `ambiguousIds` reports the number of these IDs. Rows with missing or non-string IDs are flagged and excluded from ID comparison.
- **Availability:** flag changes and review values outside `in_stock`, `out_of_stock`, `preorder` and `backorder`. This compares supplied fields, not actual inventory.
- **Optional GTIN:** when a nonempty `gtin` is supplied, check a single string for 8, 12, 13 or 14 digits and its check digit, ignoring spaces and hyphens. Keep leading zeros by using strings. Changed GTIN values are also reported. Assignment, ownership and GS1 registration are not verified.

Use `reportLanguage: "en"` (default) or `"ja"` for English or Japanese finding messages. Field names and finding codes remain stable. Unknown top-level input options and invalid input structure fail the run rather than returning a partial audit.

### Limits and completeness

Each snapshot supports at most **5,000 rows**. The **total input limit is 4 MiB** of UTF-8 serialized JSON, including both snapshots, options and JSON-encoding overhead. Each row supports at most 64 columns, header names at most 200 characters and cells at most 4,096 characters. Use flat records, not nested objects or arrays. Inputs over these limits fail; input rows are not silently truncated.

`maxFindings` limits returned detail to 2,000 findings by default, configurable from 1 to 20,000. Full counts still cover all detected findings, including when detail is capped. Check `findingsTotal`, `findingsReturned`, `findingsTruncated`, severity totals and `countsByCode` in the summary. Errors take retention priority over warnings, then informational findings. JSON, CSV, HTML and dataset finding rows contain only retained details: a capped detail report is not exhaustive. `reviewRequired` indicates whether errors or warnings were found; a successful Actor run does not mean the feed is free of issues.

### Get your results

- **JSON:** the key-value store record `OUTPUT` contains `summary` and `findings`, including codes, severity, product ID, snapshot, record number and before/after evidence.
- **CSV:** `FINDINGS.csv` contains retained findings with a UTF-8 BOM. Potential spreadsheet formulas receive a leading apostrophe for safer export; original evidence stays unchanged in JSON.
- **HTML:** `REPORT.html` is a standalone report with escaped input values, summary and retained findings.
- **Dataset:** the default dataset contains one `kind=summary` row followed by `kind=finding` rows. Filter by `kind` to select the rows you need.

### Pricing

**Pay per usage:** you pay Apify platform usage charges for execution and storage under your Apify account's applicable rates. There is **no additional report event fee**; customer billing events are disabled for this release. Usage charges can apply even if the report has no findings or a run fails. There is no measured per-run cost or savings guarantee. Review your account's usage and limits when running the Actor.

### Scope

Feed Delta Guard checks the data you supply. It does not fetch external websites, verify real inventory, validate images, establish product ownership, register offers, send messages or automatically schedule audits. It is not a complete Google Merchant Center specification validator and does not guarantee marketplace approval. Review findings before changing a catalog. These examples do not establish live cloud performance, customer demand or revenue.

# Actor input Schema

## `currentRows` (type: `array`):

Use currentRows OR currentCsv, not both. At most 5,000 flat records. IDs must be strings.

## `previousRows` (type: `array`):

Optional baseline. Omit for a first audit. An explicit empty array is a real empty baseline.

## `currentCsv` (type: `string`):

Use instead of currentRows. UTF-8 text with a header. Total input is limited to 4 MiB.

## `previousCsv` (type: `string`):

Optional baseline. Use instead of previousRows.

## `delimiter` (type: `string`):

Auto detection, or choose explicitly.

## `idField` (type: `string`):

Exact source header name. Column mappings must be distinct.

## `priceField` (type: `string`):

Exact source header name. Column mappings must be distinct.

## `currencyField` (type: `string`):

Exact source header name. Column mappings must be distinct.

## `availabilityField` (type: `string`):

Exact source header name. Column mappings must be distinct.

## `gtinField` (type: `string`):

Exact source header name. Column mappings must be distinct.

## `defaultCurrency` (type: `string`):

Optional uppercase three-letter currency code for bare prices. Syntax only; no currency registry or FX conversion.

## `priceDropPercent` (type: `number`):

Inclusive threshold. A change exactly at the threshold is reported.

## `priceIncreasePercent` (type: `number`):

Inclusive threshold. A change exactly at the threshold is reported.

## `removalPercent` (type: `number`):

Inclusive threshold. A change exactly at the threshold is reported.

## `maxFindings` (type: `integer`):

Full totals remain available when details are capped. Errors are retained before warnings and information.

## `reportLanguage` (type: `string`):

Messages in English or Japanese.

## Actor input object example

```json
{
  "currentRows": [
    {
      "id": "SKU-001",
      "price": "70.00 USD",
      "availability": "out_of_stock"
    },
    {
      "id": "SKU-003",
      "price": "15.00 USD",
      "availability": "in_stock"
    },
    {
      "id": "SKU-004",
      "price": "bad",
      "availability": "in_stock"
    }
  ],
  "delimiter": "auto",
  "idField": "id",
  "priceField": "price",
  "currencyField": "currency",
  "availabilityField": "availability",
  "gtinField": "gtin",
  "defaultCurrency": "USD",
  "priceDropPercent": 20,
  "priceIncreasePercent": 50,
  "removalPercent": 20,
  "maxFindings": 2000,
  "reportLanguage": "en"
}
```

# Actor output Schema

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

No description

## `json` (type: `string`):

No description

## `csv` (type: `string`):

No description

## `dataset` (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 = {
    "currentRows": [
        {
            "id": "SKU-001",
            "price": "70.00 USD",
            "availability": "out_of_stock"
        },
        {
            "id": "SKU-003",
            "price": "15.00 USD",
            "availability": "in_stock"
        },
        {
            "id": "SKU-004",
            "price": "bad",
            "availability": "in_stock"
        }
    ],
    "defaultCurrency": "USD"
};

// Run the Actor and wait for it to finish
const run = await client.actor("passionate_legacy_pev/feed-delta-guard").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 = {
    "currentRows": [
        {
            "id": "SKU-001",
            "price": "70.00 USD",
            "availability": "out_of_stock",
        },
        {
            "id": "SKU-003",
            "price": "15.00 USD",
            "availability": "in_stock",
        },
        {
            "id": "SKU-004",
            "price": "bad",
            "availability": "in_stock",
        },
    ],
    "defaultCurrency": "USD",
}

# Run the Actor and wait for it to finish
run = client.actor("passionate_legacy_pev/feed-delta-guard").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 '{
  "currentRows": [
    {
      "id": "SKU-001",
      "price": "70.00 USD",
      "availability": "out_of_stock"
    },
    {
      "id": "SKU-003",
      "price": "15.00 USD",
      "availability": "in_stock"
    },
    {
      "id": "SKU-004",
      "price": "bad",
      "availability": "in_stock"
    }
  ],
  "defaultCurrency": "USD"
}' |
apify call passionate_legacy_pev/feed-delta-guard --silent --output-dataset

```

## MCP server setup

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

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/kQv7f4rUqnwmfHhDV/builds/58IZ56HuAcRtEuhuz/openapi.json
