# Shopify CSV Change Review (`mathe_carv/shopify-csv-change-review`) Actor

Review a proposed Shopify product CSV against an existing export before importing it. Get a change report and CSVs of detected issues and changes.

- **URL**: https://apify.com/mathe\_carv/shopify-csv-change-review.md
- **Developed by:** [Matheus Carvalho](https://apify.com/mathe_carv) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.50 / completed comparison

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?

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

### Review Shopify CSV changes before importing

Compare a current Shopify product export with a proposed update and see what changed before you import it. **Shopify CSV Change Review** highlights cleared fields, unexpected edits, large price drops and option changes that may affect variant identities.

The review uses only the CSV text you supply. It does not connect to Shopify, change a store, fetch product URLs or send your product data to a language model. You receive a readable report and structured files you can use in an existing review workflow.

### Run a review

1. Keep a fresh product export from your store. Paste its contents into **Current product export**.
2. Paste the proposed import file into **Proposed product CSV**. Select whether you intend to update existing products or create new ones.
3. Optionally enter the exact column names you intended to change. Replace the prefilled sample values with your own. To skip that check, use JSON input and omit `expectedChangedColumns`. Review the run price and set a budget that covers one report.
4. Run the Actor. Open the **Output** tab to read the report or download the JSON, changes CSV and issues CSV.

The prefilled example uses fictional products and can be run unchanged. The same input object can also be used through Apify's API or saved in an Apify task.

### What you receive

| Output | Contents |
|---|---|
| Readable review report | HTML showing the summary, detected issues and before/after changes. |
| Complete JSON report | Structured issues, changes, summary, rules version and coverage limitations. |
| Detected changes CSV | One row per reported change, with original and proposed values. |
| Detected issues CSV | One row per reported issue, with severity and explanation. |
| Comparison summary | One dataset item for the completed report. |

CSV outputs are **review documents**, not import files. Cells that might be interpreted as spreadsheet formulas are prefixed with an apostrophe. JSON preserves the original values.

### Input settings and limits

| Field | Purpose |
|---|---|
| `proposedCsv` | Required UTF-8, comma-separated product CSV text, including its header. |
| `currentCsv` | Optional current product export. Supply it for before/after comparison. |
| `mode` | `update` for existing products, or `create` for new products. Default: `update`. |
| `expectedChangedColumns` | Optional exact header names you intended to change. Omit this field to skip the intended-column check. An explicitly empty list means no changes were intended. |
| `priceChangeThresholdPercent` | Warn about comparable price drops at or above this percentage. Default: `30`. Values above `100` suppress these warnings. |
| `maxRows` | Maximum data rows accepted in each file, from 1 to 10,000. Default: `10000`. |

Each file may contain at most **10,000 data rows, 5 MiB of UTF-8 data and 200 columns**. Files over these row, byte or column limits are rejected before report generation, without the report fee. Invalid values in supported price, weight and inventory fields, including values longer than 64 non-padding characters, are reported as validation errors in a completed, chargeable report. Supply CSV text, not a URL, local file path, access token or storage identifier.

Current headers such as `URL handle`, `SKU` and `Price`, and common legacy headers such as `Handle`, `Variant SKU` and `Variant Price`, are supported. Product continuation rows and rows containing additional images are treated separately from the first product row.

### Copyable example

This fictional update changes an option value, clears a vendor, reduces prices and changes a product to draft. Only price and inventory changes were intended.

```json
{
  "currentCsv": "URL handle,Title,Description,Vendor,Option1 name,Option1 value,SKU,Price,Inventory quantity,Status\nlinen-shirt,Linen shirt,Lightweight everyday shirt,North Studio,Size,S,SH-001-S,79.90,12,active\nlinen-shirt,,,,Size,M,SH-001-M,79.90,8,\ncanvas-tote,Canvas tote,Reusable cotton tote,North Studio,Title,Default Title,TB-010,29.90,40,active\n",
  "proposedCsv": "URL handle,Title,Description,Vendor,Option1 name,Option1 value,SKU,Price,Inventory quantity,Status\nlinen-shirt,Linen shirt,Lightweight everyday shirt,,Size,Small,SH-001-S,7.99,12,active\nlinen-shirt,,,,Size,M,SH-001-M,79.90,8,\ncanvas-tote,Canvas tote,Reusable cotton tote,North Studio,Title,Default Title,TB-010,0.00,40,draft\n",
  "mode": "update",
  "priceChangeThresholdPercent": 30,
  "expectedChangedColumns": ["Price", "Inventory quantity"],
  "maxRows": 10000
}
```

The current ruleset produces this summary for that input:

```json
[
  {
    "schemaVersion": "1.0",
    "status": "review_required",
    "rulesetVersion": "2026-09-10.1",
    "proposedRows": 3,
    "currentRows": 3,
    "products": 2,
    "variants": 3,
    "errors": 0,
    "warnings": 8,
    "info": 0,
    "comparisonAvailable": true,
    "issueCount": 8,
    "changeCount": 5
  }
]
```

The five changes are accompanied by eight warnings because one change can trigger more than one check. For example, setting the tote's price to zero triggers both a zero-price warning and a price-drop warning.

### API, n8n and Make

Use the example JSON object above directly as the POST body, without an `INPUT` wrapper. Store authentication in your workflow's credential manager.

```http
POST https://api.apify.com/v2/actors/mathe_carv~shopify-csv-change-review/runs?build=0.1.2&memory=512&timeout=60&maxTotalChargeUsd=0.50&restartOnError=false&waitForFinish=0
Content-Type: application/json
Authorization: Bearer <your protected Apify credential>

GET https://api.apify.com/v2/actor-runs/<runId>?waitForFinish=30
GET https://api.apify.com/v2/key-value-stores/<defaultKeyValueStoreId>/records/<filename>
GET https://api.apify.com/v2/datasets/<defaultDatasetId>/items?format=json&clean=true
```

1. Configure an HTTP request in n8n or Make with the POST URL and JSON body. The response describes a run; it is not the report.
2. Save `data.id` as `runId`, plus `data.defaultKeyValueStoreId` and `data.defaultDatasetId`. Poll that run until terminal. Do not repeat a POST with an uncertain outcome: reconcile it first to avoid another chargeable run.
3. After `SUCCEEDED`, retrieve `REPORT.json`, `REPORT.html`, `CHANGES.csv` and `ISSUES.csv` using the store ID. The JSON report is an object; the dataset contains one summary. A successful run without report files is not completed delivery.
4. Map `summary` and `truncated` into your review workflow or Google Sheets, updating by `runId` to avoid duplicate rows. Keep human review before importing. These n8n/Make workflows have not been tested for this Actor.

See the official [run API](https://docs.apify.com/api/v2/actors-runs-post), [file retrieval](https://docs.apify.com/api/v2/key-value-store-record-get), [n8n integration](https://docs.apify.com/integrations/n8n) and [Make integration](https://docs.apify.com/integrations/make).

### Pricing and completed reports

**US$0.50 per completed comparison, including platform usage.** Pay-per-event pricing is active. Check the price shown in Apify before starting a run; the minimum run budget is US$0.50.

One completed comparison produces one report, whether you supply one CSV or a pair, within the limits above. The price is per completed report, with no charge per row, issue or change. All four downloadable report files are included, with no separate platform usage fee.

A completed report is chargeable when it contains validation errors or warnings, finds no issues, or has no current export to compare. A parseable current file that cannot be compared reliably can also produce a chargeable report explaining that limitation. A report with explicitly truncated issue or change details is still a completed, chargeable report. Input rejection before report generation does not trigger the report fee. If the run budget cannot cover one complete report, the Actor stops without producing or charging for that report.

No separate trial allowance is implemented. The documented input and output limits apply equally to users of different plans. Any available Apify account credits are governed by Apify's plan terms.

### Interpret the result

`review_required` means a covered check needs attention. `no_detected_issues` means this ruleset found no issue; it does **not** approve an import or guarantee that it is safe. Check `comparisonAvailable` to confirm that a current-export comparison actually occurred.

Missing columns and empty cells can have different meanings during an update. An absent row alone does not prove that Shopify will delete a product or variant. Matching uses product handles and option values, with unique SKU evidence for potential option changes. Ambiguous matches are reported instead of guessed.

The full JSON report includes the ruleset version, coverage limitations and truncation flags. Reports include at most **5,000 issue details and 5,000 change details**. The summary retains the full detected counts. If details were truncated, do not treat the visible list as complete; review smaller files while keeping all rows belonging to each product together. Each additional completed report follows the same pricing rule.

### Coverage and data handling

This version checks selected CSV formatting, product and variant dependencies, and before/after differences. It does not simulate Shopify's full importer or validate every metafield, market, sales channel, inventory location, image URL or third-party app dependency. A CSV alone cannot prove every variant identity mapping or external integration consequence.

No automatic correction or import file is produced. Keep a fresh export, inspect flagged differences and follow Shopify's import guidance before making changes to a store.

On Apify, the supplied CSV text and generated reports are stored in the run's default storages under the customer's account settings. Do not include passwords, API tokens or unrelated personal data. For a reproducible support example, replace sensitive catalog values with fictional values while preserving the relevant CSV structure.

The rules were checked against [Shopify's product CSV documentation](https://help.shopify.com/en/manual/products/import-export/using-csv) on September 10, 2026. This product is independent and is not endorsed by Shopify.

# Actor input Schema

## `proposedCsv` (type: `string`):

Paste the CSV you intend to import, including its header row. Maximum 5 MiB encoded as UTF-8 and 200 columns; oversized input is rejected without charging.

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

Paste a current Shopify product export to compare with the proposed CSV. Without it, only checks possible from the proposed file are performed. Maximum 5 MiB encoded as UTF-8 and 200 columns.

## `mode` (type: `string`):

Select update for changes to existing products, or create for a new-product import.

## `maxRows` (type: `integer`):

Reject a file above this number of data rows instead of silently truncating it. The hard maximum is 10,000 per file.

## `priceChangeThresholdPercent` (type: `number`):

Warn when a comparable variant price drops by at least this percentage. Values above 100 suppress these price-drop warnings.

## `expectedChangedColumns` (type: `array`):

Exact CSV header names that you expect to change, such as Variant Price. Other detected changes are highlighted for review.

## Actor input object example

```json
{
  "proposedCsv": "URL handle,Title,Description,Vendor,Option1 name,Option1 value,SKU,Price,Inventory quantity,Status\nlinen-shirt,Linen shirt,Lightweight everyday shirt,,Size,Small,SH-001-S,7.99,12,active\nlinen-shirt,,,,Size,M,SH-001-M,79.90,8,\ncanvas-tote,Canvas tote,Reusable cotton tote,North Studio,Title,Default Title,TB-010,0.00,40,draft\n",
  "currentCsv": "URL handle,Title,Description,Vendor,Option1 name,Option1 value,SKU,Price,Inventory quantity,Status\nlinen-shirt,Linen shirt,Lightweight everyday shirt,North Studio,Size,S,SH-001-S,79.90,12,active\nlinen-shirt,,,,Size,M,SH-001-M,79.90,8,\ncanvas-tote,Canvas tote,Reusable cotton tote,North Studio,Title,Default Title,TB-010,29.90,40,active\n",
  "mode": "update",
  "maxRows": 10000,
  "priceChangeThresholdPercent": 30,
  "expectedChangedColumns": [
    "Price",
    "Inventory quantity"
  ]
}
```

# Actor output Schema

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

No description

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

No description

## `changes` (type: `string`):

No description

## `issues` (type: `string`):

No description

## `summary` (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 = {
    "proposedCsv": `URL handle,Title,Description,Vendor,Option1 name,Option1 value,SKU,Price,Inventory quantity,Status
linen-shirt,Linen shirt,Lightweight everyday shirt,,Size,Small,SH-001-S,7.99,12,active
linen-shirt,,,,Size,M,SH-001-M,79.90,8,
canvas-tote,Canvas tote,Reusable cotton tote,North Studio,Title,Default Title,TB-010,0.00,40,draft`,
    "currentCsv": `URL handle,Title,Description,Vendor,Option1 name,Option1 value,SKU,Price,Inventory quantity,Status
linen-shirt,Linen shirt,Lightweight everyday shirt,North Studio,Size,S,SH-001-S,79.90,12,active
linen-shirt,,,,Size,M,SH-001-M,79.90,8,
canvas-tote,Canvas tote,Reusable cotton tote,North Studio,Title,Default Title,TB-010,29.90,40,active`,
    "mode": "update",
    "maxRows": 10000,
    "priceChangeThresholdPercent": 30,
    "expectedChangedColumns": [
        "Price",
        "Inventory quantity"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mathe_carv/shopify-csv-change-review").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 = {
    "proposedCsv": """URL handle,Title,Description,Vendor,Option1 name,Option1 value,SKU,Price,Inventory quantity,Status
linen-shirt,Linen shirt,Lightweight everyday shirt,,Size,Small,SH-001-S,7.99,12,active
linen-shirt,,,,Size,M,SH-001-M,79.90,8,
canvas-tote,Canvas tote,Reusable cotton tote,North Studio,Title,Default Title,TB-010,0.00,40,draft
""",
    "currentCsv": """URL handle,Title,Description,Vendor,Option1 name,Option1 value,SKU,Price,Inventory quantity,Status
linen-shirt,Linen shirt,Lightweight everyday shirt,North Studio,Size,S,SH-001-S,79.90,12,active
linen-shirt,,,,Size,M,SH-001-M,79.90,8,
canvas-tote,Canvas tote,Reusable cotton tote,North Studio,Title,Default Title,TB-010,29.90,40,active
""",
    "mode": "update",
    "maxRows": 10000,
    "priceChangeThresholdPercent": 30,
    "expectedChangedColumns": [
        "Price",
        "Inventory quantity",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("mathe_carv/shopify-csv-change-review").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 '{
  "proposedCsv": "URL handle,Title,Description,Vendor,Option1 name,Option1 value,SKU,Price,Inventory quantity,Status\\nlinen-shirt,Linen shirt,Lightweight everyday shirt,,Size,Small,SH-001-S,7.99,12,active\\nlinen-shirt,,,,Size,M,SH-001-M,79.90,8,\\ncanvas-tote,Canvas tote,Reusable cotton tote,North Studio,Title,Default Title,TB-010,0.00,40,draft\\n",
  "currentCsv": "URL handle,Title,Description,Vendor,Option1 name,Option1 value,SKU,Price,Inventory quantity,Status\\nlinen-shirt,Linen shirt,Lightweight everyday shirt,North Studio,Size,S,SH-001-S,79.90,12,active\\nlinen-shirt,,,,Size,M,SH-001-M,79.90,8,\\ncanvas-tote,Canvas tote,Reusable cotton tote,North Studio,Title,Default Title,TB-010,29.90,40,active\\n",
  "mode": "update",
  "maxRows": 10000,
  "priceChangeThresholdPercent": 30,
  "expectedChangedColumns": [
    "Price",
    "Inventory quantity"
  ]
}' |
apify call mathe_carv/shopify-csv-change-review --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mathe_carv/shopify-csv-change-review"
        }
    }
}
```

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/3MIYsff7skgYbowQt/builds/vc5vdRRwc6AiFaOG6/openapi.json
