# Supplier Feed Change Checker — CSV/JSON SKU Diff (`autonome_bots/supplier-feed-change-checker`) Actor

Compare two supplier catalogs by SKU. Find added, removed and changed products from CSV or JSON snapshots, with clear validation and downloadable JSON and CSV reports. $0.50 per completed comparison.

- **URL**: https://apify.com/autonome\_bots/supplier-feed-change-checker.md
- **Developed by:** [Autonome Bots](https://apify.com/autonome_bots) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.50 / completed feed comparison report

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

## Supplier Feed Change Checker — CSV/JSON SKU Diff

Compare two supplier catalog snapshots and see which products were added, removed or changed. Supply CSV text or flat JSON records, choose a stable identifier such as SKU, and receive a JSON report and a spreadsheet-friendly CSV change table.

Use the results to review a supplier update before importing it into your catalog. Both snapshots come from you; the Actor does not fetch feeds or update your store.

### Try a comparison

Paste this synthetic example into the Apify JSON input editor:

```json
{
  "comparison": {
    "baseline": [
      { "sku": "A-001", "price": "19.99" },
      { "sku": "A-002", "price": "8.00" }
    ],
    "current": [
      { "sku": "A-001", "price": "21.99" },
      { "sku": "A-003", "price": "5.00" }
    ],
    "keyField": "sku",
    "fields": ["price"]
  },
  "rightsConfirmed": true
}
```

The result contains one added product (`A-003`), one removed product (`A-002`), one changed product (`A-001`) and zero unchanged products. The changed price is recorded as `"19.99"` before and `"21.99"` after.

For CSV input, replace either row array with CSV text such as `"sku,price\nA-001,19.99\nA-002,8.00\n"`. Each snapshot can use either supported format. Use comparable value types in both snapshots: CSV values are strings, so a CSV price can differ from a numeric JSON price even when they look alike.

### Inputs

| Field | Purpose |
| --- | --- |
| `comparison.baseline` | Previous snapshot, as CSV text or an array of flat JSON objects |
| `comparison.current` | Current snapshot in either supported format |
| `comparison.keyField` | Unique identifier column; defaults to `sku` |
| `comparison.fields` | Optional non-key fields to compare; omit to compare all observed non-key fields. An empty list compares identifier presence only |
| `comparison.delimiter` | CSV separator: comma by default, semicolon, or tab (`"\t"`) |
| `rightsConfirmed` | Must be `true`; confirms that you have permission to process both snapshots |

Use complete snapshots covering the same population. An identifier missing from the current snapshot is reported as removed, even if the cause is an incomplete upstream export. A valid empty current snapshot reports every baseline product as removed. Verify that this is intentional before running a comparison.

### Matching rules

Outer whitespace is trimmed from headers, identifiers and string values. Identifiers are case-sensitive. Numeric key `1` and string key `"1"` match; string key `"001"` remains distinct. Supply identifiers as strings when leading zeroes matter.

Non-key JSON types remain distinct: numeric `1` differs from string `"1"`. Missing values, `null` and empty strings are different states. Input row order and JSON property order do not affect the comparison.

Duplicate, missing or empty identifiers stop the comparison with a diagnostic. CSV diagnostic row numbers count data rows, excluding the header. Resolve ambiguous identifiers in the source before trying again.

### Limits

| Limit | Maximum |
| --- | ---: |
| Combined encoded comparison input | 2 MiB |
| Rows per snapshot | 5,000 |
| Columns per snapshot | 50 |
| Explicitly selected comparison fields | 40 |
| Characters per field value | 4,000 |
| Characters per identifier | 256 |
| Complete hosted JSON report, including metadata | 8 MiB |
| Hosted CSV report | 8 MiB |

These limits apply together. A comparison within the input limits can still produce an oversized report. Reduce the selected fields or divide both snapshots using the same stable identifier partition. Splitting each snapshot independently by row position can create false additions and removals.

Inputs must be flat CSV or JSON records. Nested objects and arrays, Excel files, XML, URLs, credentials, fuzzy matching and currency conversion are not supported. The Actor does not determine the business meaning of a price or availability change.

### Results

After a completed run, use the Output links to open:

| Output | Contents |
| --- | --- |
| Default dataset | One comparison summary row with added, removed, changed and unchanged counts |
| `OUTPUT` | JSON comparison under `data`, with summary counts, added/removed products, changed fields, normalization information and integrity metadata |
| `OUTPUT-CSV` | CSV change table with `change_type`, `key`, `field`, `before_present`, `before_json`, `after_present` and `after_json` columns |
| `RUN-STATUS` | Application completion state and any billing or error status available for the run |

Unchanged products are counted rather than copied into the change table. A product with several changed fields counts once in the summary and has one CSV row per changed field. Each added or removed product has one CSV row containing its record as JSON. JSON-encoded cells preserve value types, and formula-like CSV cells are escaped for spreadsheet use. Use the JSON report for programmatic processing.

Check the application status before using output from a failed or interrupted run. A partial file alone does not establish a completed report or a confirmed charge. Results describe differences in the data you supplied; they do not verify supplier accuracy or export completeness.

### Pricing

**US$0.50 per completed comparison report**, including a complete report showing no changes. The report charge uses one `feed-report-completed` event after both JSON and CSV have been saved and verified.

There are no Actor startup or dataset-item charges. Input rejected before the completion charge, or a partial delivery that stops before that charge, incurs no Actor event charge. Platform usage for the run is included in the event pricing; it is not added as a separate run-usage charge. Your Apify subscription and any account charges for retained storage, later API access or downloads, and other services remain subject to your Apify plan. Check the Actor's Pricing tab and your account terms before running it.

Starting a new run is a new comparison and can incur another report charge, even with identical inputs. If a run has an unresolved billing status, retain its run reference and request help before repeating it. Billing questions and refund requests are handled through Apify's applicable process; a refund is not automatic.

### Data and privacy

Use only public or authorized, non-sensitive catalog data. Do not submit customer records, credentials, access tokens, payment details, health information or other sensitive personal data.

Apify hosts the supplied input, outputs, run metadata and recovery records. Reports contain values from your snapshots. The comparison code does not write raw catalog rows to application logs; diagnostics use fixed error codes and limited row coordinates. The Actor makes no external model calls, web scraping requests or automatic store updates.

Access, sharing, retention and deletion are governed by the run owner's Apify account and resource settings. Use the native Apify account controls to manage or delete the relevant run and storage resources, and export reports you need before retention expires. This Actor does not set a separate automatic deletion timer. Do not post private input, output or download links in public issues. See [Apify storage and retention](https://docs.apify.com/storage) and [resource access rights](https://docs.apify.com/account/collaboration/access-rights).

### Support and terms

Report product problems through this Actor's **Issues** tab in Apify. Include the run reference, error code and a small synthetic example that reproduces the problem. Do not include real catalog rows, credentials or private download links in a public issue. Use Apify's support channels for account, platform-access or billing assistance.

Use of the Actor is governed by the [Apify Standard Actor Contract](https://docs.apify.com/legal/standard-actor-contract), alongside the applicable Apify platform terms. This description explains the service's behavior; it does not replace those terms or add an availability guarantee.

Each comparison requires both snapshots. The Actor does not select a previous baseline, create a schedule or send notifications. You can incorporate its reports into your own workflow using Apify's supported tools.

# Actor input Schema

## `comparison` (type: `object`):

Required baseline and current; optional keyField (default sku), fields, delimiter. At most 5,000 rows per snapshot and 2 MiB combined serialized input.

## `rightsConfirmed` (type: `boolean`):

The prefilled synthetic example is authorized. If you replace it, confirm you have permission to process your data. Use only non-sensitive catalogs, never customer records or credentials.

## Actor input object example

```json
{
  "comparison": {
    "baseline": [
      {
        "sku": "A-001",
        "price": "29.00",
        "stock": "12"
      }
    ],
    "current": [
      {
        "sku": "A-001",
        "price": "31.00",
        "stock": "8"
      }
    ],
    "keyField": "sku"
  },
  "rightsConfirmed": true
}
```

# Actor output Schema

## `comparisonSummary` (type: `string`):

One summary row with counts for the completed comparison. Full changes are in the JSON and CSV reports.

## `jsonReport` (type: `string`):

Report under data, with counts, additions, removals and field changes, plus run identity and SHA-256 integrity hash.

## `csvReport` (type: `string`):

Download the verified CSV. JSON-encoded cells preserve scalar types and distinguish missing, null and empty values.

## `runStatus` (type: `string`):

Application completion or rejection state, with billing outcome and a safe error code when relevant.

# 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 = {
    "comparison": {
        "baseline": [
            {
                "sku": "A-001",
                "price": "29.00",
                "stock": "12"
            }
        ],
        "current": [
            {
                "sku": "A-001",
                "price": "31.00",
                "stock": "8"
            }
        ],
        "keyField": "sku"
    },
    "rightsConfirmed": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("autonome_bots/supplier-feed-change-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 = {
    "comparison": {
        "baseline": [{
                "sku": "A-001",
                "price": "29.00",
                "stock": "12",
            }],
        "current": [{
                "sku": "A-001",
                "price": "31.00",
                "stock": "8",
            }],
        "keyField": "sku",
    },
    "rightsConfirmed": True,
}

# Run the Actor and wait for it to finish
run = client.actor("autonome_bots/supplier-feed-change-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 '{
  "comparison": {
    "baseline": [
      {
        "sku": "A-001",
        "price": "29.00",
        "stock": "12"
      }
    ],
    "current": [
      {
        "sku": "A-001",
        "price": "31.00",
        "stock": "8"
      }
    ],
    "keyField": "sku"
  },
  "rightsConfirmed": true
}' |
apify call autonome_bots/supplier-feed-change-checker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,autonome_bots/supplier-feed-change-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/dNKdjtn2Jx7FP2DxZ/builds/fGp4K8IdgIm2E5YHm/openapi.json
