Merge & Deduplicate Datasets: Remove Duplicates, Only New Items
Pricing
from $0.10 / 1,000 output rows
Merge & Deduplicate Datasets: Remove Duplicates, Only New Items
Merge Apify datasets, CSV and JSON files into one, remove duplicates by any field, output only new items since the last run, filter, rename and flatten. $0.10 per 1,000 rows.
Pricing
from $0.10 / 1,000 output rows
Rating
0.0
(0)
Developer
Giorgos Myrianthous
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
20 hours ago
Last modified
Categories
Share
Merge datasets and remove duplicates from Apify datasets, CSV and JSON files, and output only new items since your last run, which is perfect for scheduled scrapers feeding Google Sheets, CRMs and Slack.
💲 $0.10 per 1,000 output rows. Duplicates and filtered rows are free. Pay only for results. No subscription, and the Apify free plan's monthly credit covers small jobs.
Also known as: merge datasets, deduplicate dataset, remove duplicates, dedup CSV, only new items, combine scraper runs, JSON to CSV, dataset transformer.
Quick start
- Click Start. The prefilled input works as is.
- Or paste this input (JSON tab):
{"inlineItems": [{"url": "https://example.com/a","title": "A"},{"url": "https://example.com/b","title": "B"},{"url": "https://example.com/a","title": "A (duplicate)"}],"dedupFields": ["url"]}
Output (one dataset item):
{"url": "https://example.com/a","title": "A"}
Use it from the API, AI agents (MCP), n8n, Make or Zapier
curl -X POST "https://api.apify.com/v2/acts/gmyri~dataset-merge-dedup/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H 'Content-Type: application/json' \-d '{"datasetIds":["<DATASET_ID_1>","<DATASET_ID_2>"],"dedupFields":["url"],"onlyNewItems":true}'
- AI agents / MCP: connect
https://mcp.apify.com/?actors=gmyri/dataset-merge-dedupto Claude, Cursor, ChatGPT or any MCP client. The input schema is fully described for tool calling. - Python:
ApifyClient(token).actor("gmyri/dataset-merge-dedup").call(run_input={...}) - n8n / Make / Zapier: use the Apify "Run Actor" action with
gmyri/dataset-merge-dedup, then read the dataset items.
Quick FAQ
- How does 'only new items' work? The keys of rows already output are stored in a named key-value store (
stateStoreName). The next run outputs only rows it has never seen, so you can schedule a scraper and get just the new results. - Can it read my other Actors' datasets? Yes. Pass dataset IDs in
datasetIds. The Actor runs with limited permissions and only reads the datasets you select. - What if I set a spending limit? The Actor stops cleanly at your Max cost per run and you're never charged above it.
Details
Combine the outputs of several scraper runs, CSV exports and JSON files into one clean dataset:
- remove duplicates by any fields
- output only the rows that are new since your last run
- filter, keep, drop, rename and flatten fields
- export to an Apify dataset, CSV or JSON
You pay only for rows that make it into the output. Duplicates and filtered rows are free.
Why this Actor
- Reliable. Rows are streamed in batches of 500, a missing or broken source never kills the run (it is reported in
SUMMARY), and a spending limit stops the run cleanly instead of failing it. - Incremental pipelines. Schedule a scraper, chain this Actor after it with
onlyNewItems: true, and send only fresh rows to Slack, Sheets or your CRM. Dedup keys are remembered in a named key-value store between runs. - Mixed sources. Read Apify datasets, CSV/TSV (delimiter auto-detected), JSON arrays,
{ "items": [...] }wrappers, JSON Lines and inline JSON, all in one run. - Agent-friendly. Inline items plus a simple JSON filter language make it a handy cleaning tool for AI agents through the Apify MCP server.
Typical uses
- Merge 10 daily runs of a product or price scraper and keep the newest row per URL (
keepOccurrence: "last"). - Dedup a lead or company list by
domain(case- and whitespace-insensitive). - Turn nested JSON into a flat CSV for Excel (
flattenNested+saveCsvFile). - Keep only rows with
price < 100that contain"mug"intitle.
Input example
{"datasetIds": ["<dataset-id-run-1>", "<dataset-id-run-2>"],"fileUrls": ["https://example.com/export.csv"],"dedupFields": ["url"],"keepOccurrence": "last","filters": [{ "field": "price", "op": "lt", "value": 100 }],"omitFields": ["debug"],"renameFields": { "meta.brand": "brand" },"flattenNested": true,"saveCsvFile": true}
Options
| Field | Default | Description |
|---|---|---|
datasetIds | – | Apify datasets to merge, in order |
fileUrls | – | CSV, TSV, JSON or JSONL URLs (Google Sheets "publish to web" CSV links work) |
inlineItems | – | JSON array of rows |
deduplicate | true | Remove duplicate rows |
dedupFields | whole row | Fields that define a duplicate (dot paths such as address.city work) |
dedupCaseInsensitive / dedupTrimWhitespace | true / true | Normalise values before comparing |
keepOccurrence | first | first or last (newest data wins) |
onlyNewItems | false | Skip rows already output in previous runs |
stateStoreName | dataset-dedup-state | Named store that remembers keys between runs. Use one per pipeline. |
filters | – | [{field, op, value}]. Ops: eq ne contains notContains in notIn gt gte lt lte exists notExists regex |
pickFields / omitFields / renameFields | – | Reshape rows |
flattenNested, trimStrings, dropEmptyFields, addSourceField | false | Extra clean-up |
inferCsvTypes | true | Turn CSV "12" into 12 and "true" into true |
maxOutputItems | 0 | Cap on output rows |
saveCsvFile / saveJsonFile | false | Also save OUTPUT.csv / OUTPUT.json in the key-value store |
Output
- The default dataset holds the cleaned rows.
SUMMARY(key-value store) holds the counts, for example:{ "inputRows": 11, "filteredOut": 1, "duplicates": 4, "seenInPreviousRuns": 0, "outputRows": 6,"sources": [{ "source": "dataset:abc", "rows": 2 }], "sourceErrors": [] }OUTPUT.csvandOUTPUT.jsonare saved if requested.
Pricing (pay per event)
| Event | Price | When |
|---|---|---|
row-output | $0.0001 ($0.10 per 1,000 rows) | Each row written to the output |
apify-actor-start | $0.00005 | Platform default, once per run |
Input rows, duplicates and filtered-out rows are not charged. Example: merging 60,000 rows down to 25,970 unique rows costs about $2.60. Set a maximum cost per run, and the Actor stops output cleanly at the limit.
Integrations
- Chain after a scraper: add an Apify webhook or integration on your scraper's
RUN.SUCCEEDEDevent and pass{"datasetIds": ["{{resource.defaultDatasetId}}"], "onlyNewItems": true}. - MCP:
https://mcp.apify.com/?tools=<your-username>/dataset-merge-dedup. The Actor uses pay-per-event pricing only and limited permissions, with no Standby, so it is eligible for agentic payments.
Notes and limits
- In
keepOccurrence: "last"mode, rows are held in memory until all sources are read. Use 1–4 GB of memory for multi-million-row merges. - Rows whose dedup fields are all empty are always kept. In incremental mode they are remembered by their full content.
- With limited permissions, the Actor can read only the datasets you pick in the input.