Dataset Sync to Notion, Slack, Supabase & CRM — with Dedupe
Pricing
from $3.50 / 1,000 row written to your destinations
Dataset Sync to Notion, Slack, Supabase & CRM — with Dedupe
Send any Apify dataset to Notion, Slack, Supabase, HubSpot or any MCP-connected app — writing only the rows that aren't already there. Deterministic deduplication against the destination, explicit field mapping, no LLM and no token cost. Pay only for rows actually written.
Pricing
from $3.50 / 1,000 row written to your destinations
Rating
0.0
(0)
Developer
K O
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
Send any Apify dataset straight into the app your team actually works in — and write only the rows that aren't already there.
Scrapers leave you with a dataset. Getting that dataset into Notion, Supabase, HubSpot or Slack is the part that stays manual: export a CSV, open the destination, figure out what's already in there, paste the rest. Do it on a schedule and you either re-import duplicates or you hand-check every row.
This Actor does that last mile in one run, and it deduplicates against the destination itself — not just against its own history.
Why this one and not an AI uploader
| This Actor | LLM-agent uploaders | |
|---|---|---|
| Behavior | Deterministic — same input, same writes | Non-deterministic |
| Duplicate rows | Skipped by key, never written | No guarantee |
| Cost | Flat per synced row | Per token, scales with data size |
| Wrong writes to your CRM | Not possible — explicit field map | Possible |
There's no model in the loop. It reads what's at the destination, compares keys, and writes the difference.
How it works
- Connect your app (Notion, Slack, Supabase, HubSpot, …) under Integrations in Apify Console.
- Run this Actor in
list-toolsmode to see what that connector can do. - Run it in
syncmode with the tool name, your dataset ID, and a dedupe key.
Credentials never reach this Actor. It talks to the destination through Apify's MCP proxy, which holds the real tokens and enforces that the Actor can only call the tools it declared.
Quick start
Step 1 — discover the destination's tools
{"destination": "<your connector>","mode": "list-tools"}
The dataset comes back with every tool name, description and input schema. Pick the one that creates a record.
Step 2 — sync
{"destination": "<your connector>","mode": "sync","datasetId": "<dataset from any Actor>","writeTool": "create_page","readTool": "query_database","readToolArgs": { "database_id": "abc123" },"writeToolExtraArgs": { "database_id": "abc123" },"dedupeKey": "licenseNumber","fieldMap": { "title": "companyName", "phone": "contact.phone" }}
Set dryRun: true first — it reports exactly which rows it would write, so you can check your field mapping before anything lands in a live database.
Examples
Google Maps results → Notion CRM, no repeats
Point datasetId at any Google Maps scraper run, set dedupeKey to placeId, and schedule it. New places show up in Notion; ones you already have are skipped.
New leads → Supabase table
writeTool: "insert", readTool: "select", readToolArgs: { "table": "leads" }, dedupeKey: "email".
Only genuinely new items → Slack
writeTool: "send_message", writeToolExtraArgs: { "channel": "#leads" }, dedupeKey: "url". Because dedupe runs first, the channel only ever sees things nobody has posted before.
Input
| Field | Required | Description |
|---|---|---|
destination | yes | The MCP connector to write to |
mode | sync (default) or list-tools | |
datasetId | for sync | Source Apify dataset — any Actor's |
writeTool | for sync | Destination tool called once per new row |
dedupeKey | Field identifying a record. Dot paths supported. Default id | |
readTool | Tool that lists existing records — enables true destination dedupe | |
readToolArgs | JSON args for the read tool | |
fieldMap | Destination arg name → source field path. Empty passes rows through | |
writeToolExtraArgs | Constant args merged into every write | |
maxItems | Cap on rows written per run. Default 1000 | |
dryRun | Plan the sync, write nothing | |
writeKeyless | Also write rows missing the dedupe key. Default off |
Output
One row per record handled:
{ "synced": true, "key": "roc-123456", "args": { "title": "Acme Builders", "phone": "480-555-0100" } }
Failures are recorded rather than silently dropped, and one rejected row never aborts the rest of the run:
{ "synced": false, "key": "roc-123457", "error": "Destination tool \"create_page\" returned an error: ..." }
Dedupe, precisely
- With
readTool— reads current destination state each run. Safe even if records were added by someone else, or the Actor's own history was lost. - Without
readTool— falls back to remembering keys it wrote in previous runs. - Keys are trimmed and case-folded, so
"Acme LLC "and"acme llc"are one record. - Rows duplicated inside the source are collapsed too.
- Rows with no key are skipped by default, because writing an unidentifiable row is how duplicates get created.
Pricing
$5 per 1,000 rows actually written to the destination — and nothing else.
There is no per-run fee. Duplicates, skipped rows, dry runs, and scheduled runs over a source that hasn't changed are all free. You pay for records that landed, or you pay nothing.
FAQ
Does this Actor see my Notion/Slack token? No. Apify's MCP proxy holds the credentials and attaches them to outbound calls.
Which apps work? Any service exposed as an MCP connector in your Apify account.
What if I don't know my destination's tool names? Run list-tools mode.
Can an AI agent call this? Yes — it's exposed through the Apify MCP server. list-tools then sync is a natural two-step for an agent.
What if the destination rejects a row? It's logged to the dataset with the error, and the run continues.