# CSV Version Diff — Added, Removed and Changed Records (`mick_mouse/my-actor-2`) Actor

Compare two CSV snapshots by unique composite keys. Detect added and removed records, changed fields and schema changes. Preserve leading-zero identifiers and exact text values. Deterministic JSON for agents and automation.

- **URL**: https://apify.com/mick_mouse/my-actor-2.md
- **Developed by:** [Miguel Stuardo](https://apify.com/mick_mouse) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $50.00 / 1,000 completed csv comparison reports

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

## CSV Version Diff

Compare two CSV snapshots using unique keys and receive added records, removed records, and before/after values for changed fields. Useful for inventory exports, product catalog snapshots, and automation checks. This compares text data; it does not reconcile payments or infer transaction identity.

### Run locally

Python 3.11+; the local CLI uses only the standard library.

```bash
python compare.py < example_input.json > result.json
python -m unittest -v
```

Successful runs write one JSON object to stdout and exit 0. Invalid inputs write a generic JSON error and exit 2. Run from this directory. No network service, credentials or payment setup is needed locally.

### Input

`leftCsv` is the earlier snapshot, `rightCsv` the later one, `keys` a nonempty list of exact header names. `delimiter` is comma by default; semicolon, tab and pipe are supported. Supply CSV text, not URLs or paths. Both files use the same delimiter. Column names must be nonempty and unique; key values must be nonempty and unique within each snapshot. A UTF-8 BOM is accepted at the start. Blank physical lines are skipped.

All values, including IDs such as `001`, remain strings. Whitespace, capitalization, and number formatting are significant. Headers and values are not trimmed or normalized. A key `001` is different from `1`. Composite keys follow the order of `keys`.

### Output

`added` contains records only in the right snapshot; `removed` contains records only in the left. `changed` includes each shared key with changes to shared non-key columns. Added/removed columns appear in `schemaChanges`; schema-only differences do not count as changed records. `unchangedCommonFields` counts shared records without changes to the compared shared fields, including when there are no shared non-key fields. Ordering is deterministic lexicographic string-key order, not numeric order. CSV source row order is not compared.

### Limits and exclusions

- Maximum serialized JSON input: 1,000,000 UTF-8 bytes.
- At most 10,000 data records and 200 columns per file.
- Maximum serialized report: 8,000,000 UTF-8 bytes.
- Duplicate/empty keys, inconsistent row widths, duplicate/empty headers and malformed quoted CSV are rejected.
- No fuzzy matching, Excel/PDF parsing, type/date inference, formulas, URL fetching, or external system writes.

The CLI processes input in memory and does not save it itself. Shell redirection saves the output only where the caller requests. The optional Apify adapter stores inputs, output dataset and platform metadata under Apify's policies; it does not provide zero retention. Avoid uploading data you are not authorized to process. The application does not log CSV contents.

### Hosted pricing and operation

One completed report is one `comparison-report` event, independent of changed row count. Check the Pricing tab for the current configured price and automatic start event charge. Invalid input is rejected before requesting the custom report event. No custom per-row event is requested. Platform start or usage charges can still apply.

The Actor requires positive pay-per-event pricing and rejects a separate default dataset item charge. It checks the available event budget before writing output. If a restarted run already contains a report, no second report event is requested. Dataset storage and charging are not atomic: an interruption between writing and charging may leave an unbilled report. Review run billing before retrying a failed delivery.

The hosted version stores inputs, reports and metadata on Apify. Manage access and retention through the platform. It does not fetch external URLs, execute formulas or call a language model. Local tests do not establish cloud deployment, sales, buyer demand or revenue.

# Actor input Schema

## `leftCsv` (type: `string`):

CSV text including a header. No URLs.

## `rightCsv` (type: `string`):

CSV text including a header. Same key column names.

## `keys` (type: `array`):

Nonempty unique composite keys; exact header spelling.

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

Same delimiter on both sides.

## Actor input object example

```json
{
  "leftCsv": "id,name\n001,Ana\n002,Ben",
  "rightCsv": "id,name\n001,Anne\n003,Cam",
  "keys": [
    "id"
  ],
  "delimiter": ","
}
```

# Actor output Schema

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

Dataset array containing one complete report.

# 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 = {
    "leftCsv": `id,name
001,Ana
002,Ben`,
    "rightCsv": `id,name
001,Anne
003,Cam`,
    "keys": [
        "id"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mick_mouse/my-actor-2").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 = {
    "leftCsv": """id,name
001,Ana
002,Ben""",
    "rightCsv": """id,name
001,Anne
003,Cam""",
    "keys": ["id"],
}

# Run the Actor and wait for it to finish
run = client.actor("mick_mouse/my-actor-2").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 '{
  "leftCsv": "id,name\\n001,Ana\\n002,Ben",
  "rightCsv": "id,name\\n001,Anne\\n003,Cam",
  "keys": [
    "id"
  ]
}' |
apify call mick_mouse/my-actor-2 --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mick_mouse/my-actor-2"
        }
    }
}
```

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/Q8bm37W8dfkxmaJJ1/builds/7uPmNftZnu2iFkN8H/openapi.json
