CRM Contact Cleanup & Dedupe Prep
Pricing
$0.10 / 1,000 processed rows
CRM Contact Cleanup & Dedupe Prep
Clean supplied URL, email, and address fields for contact records, preserving one row per input with changed-field, review, dedupe-key, and cross-field signals. Does not scrape, find, verify, enrich, geocode, score confidence, choose survivors, or merge contacts.
Pricing
$0.10 / 1,000 processed rows
Rating
0.0
(0)
Developer
Critical Distinction
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
7 days ago
Last modified
Categories
Share
Turn a supplied contact file into a reimport-ready cleaned file plus focused review queues. Contact Cleanup normalizes the URL, email, and U.S.-leaning address values already present in your records. It preserves the rest of each row and never scrapes, finds, verifies, enriches, geocodes, ranks, chooses a survivor, deletes, or merges contacts.
Contact 2.0 package: Cargo
2.0.0, Actor version2.0, andcontact-cleanup-output-v3describe one whole-file workflow contract. Deployment availability, Store visibility, and pricing are point-in-time Apify properties; confirm them before starting a run.
Migrating from Contact 1.0
Existing inline and source input shapes remain accepted. Omitted workflow
uses deterministic side-by-side CSV defaults, and the accepted compatibility
controls are not runtime-version selectors.
Contact 2.0 changes the output package:
- the Dataset is an accepted-row review projection, not the whole-file
reimport file; blank and rejected source identities remain in
RECORDS_TO_REVIEW.json; - the default Key-Value Store leads with one cleaned reimport file,
RECORDS_TO_REVIEW.json,POSSIBLE_MATCH_GROUPS.json, andRUN_SUMMARY.json; - final
OUTPUTusescontact-cleanup-output-v3and is written only after those KVS artifacts and accepted Dataset batches are acknowledged; and - caught cross-storage failures may leave a committed or commit-unknown
prefix. Inspect KVS, Dataset, and
OUTPUTwith GET requests before deciding whether any retry or overwrite is safe.
Consumers moving from Contact 1.0 should validate their Dataset and OUTPUT
readers against these shapes, use the Actor Output links for file discovery,
and preserve source backups until review and reimport are complete.
Start here
- Choose one input route: inline
records, a file, an Apify Dataset, or a Key-Value Store record. - Map your
recordId,url,email, andaddresscolumns when their source names differ. Every other source field remains part of the preserved row. - For a source route, preview first with
previewOnly: true. SetsourceMaxRowsto at most1000. - Choose an export mode and format under
workflow. - Run the workflow, then open the four files listed under Your four workflow files.
- Resolve review decisions before reimporting
CLEANED_CONTACT_REVIEW.csvorCLEANED_CONTACT_REVIEW.json.
The qualified local support profiles are 1,000 accepted rows at 6 source fields and 261 source fields at 12 rows. Their cross-product was not qualified. These are one-host, fixture-backed profiles, not live throughput or an unlimited-volume claim. Physical blank CSV and JSONL lines do not consume the accepted-row cap; an accepted row whose mapped cleanup fields are empty still does.
Minimal inline example
{"records": [{"recordId": "crm-1001","url": " example.invalid/about/?utm_source=crm ","email": "Person@Example.Invalid","address": "900 cedar street chicago il 60601","accountOwner": "Synthetic Team"}],"workflow": {"exportMode": "side_by_side","exportFormat": "csv","generatedFieldNamespace": "contactCleanup"}}
Inline records use the fixed recordId, url, email, and address names.
The committed Console prefill and smoke input contain 12 fictional rows that
exercise safe changes, review-required values, and possible-match groups.
API, task, CLI, and scheduler callers must submit their own input because
Console prefill is a UI convenience, not a runtime default.
Choose one input route
Routes are mutually exclusive. Do not combine inline records with source.
For file and Key-Value Store routes, declare csv, jsonl, or json_array,
or use auto when the record name, extension, or content type is sufficient.
Dataset rows are already JSON objects and do not take a format selector.
| Route | Required input | Mapping | Qualified use |
|---|---|---|---|
| Inline | records | Fixed supported names | Up to 1,000 accepted rows |
| File | source.type = "file" and source.file | Optional source.fieldMap | Preview, then execute at no more than 1,000 accepted rows |
| Dataset | source.type = "dataset" and source.datasetId | Optional source.fieldMap | Reads complete object rows from an optional offset |
| Key-Value Store | source.type = "keyValueStore", storeId, and recordKey | Optional source.fieldMap | Reads one selected text record |
auto is a selector for a supported resolved format; it is not an additional
format. The maintained equivalence suite closes these eight resolved cells:
inline JSON object, file CSV/JSONL/JSON array, Dataset JSON object, and
Key-Value Store CSV/JSONL/JSON array.
File preview
{"source": {"type": "file","file": "apify://key-value-stores/synthetic-source/records/contacts.csv","format": "csv","fieldMap": {"recordId": "crm_id","url": "website","email": "email_address","address": "mailing_address"}},"previewOnly": true,"sourceMaxRows": 1000,"rowLimitBehavior": "fail_over_limit","workflow": {"exportMode": "side_by_side","exportFormat": "csv"}}
Preview performs bounded reads and local workflow preparation but writes no
buyer artifacts, Dataset items, final OUTPUT, or custom charge. A successful
preview does not prove provider storage, a live price, or a later execution.
Dataset execution
{"source": {"type": "dataset","datasetId": "synthetic-dataset-name","offset": 0,"fieldMap": {"recordId": "crm_id","url": "website","email": "email_address","address": "mailing_address"}},"previewOnly": false,"sourceMaxRows": 1000,"workflow": {"exportMode": "replace_supported_fields","exportFormat": "json"}}
The input schema retains a parser/runtime guard as high as 10,000 for backward
compatibility. That guard is not a supported buyer ceiling: the current
qualification failed the 10,000-row candidate at the single-record KVS
publication boundary. Set sourceMaxRows <= 1000; do not infer support from
the schema maximum or the omitted-field runtime fallback.
The row-limit policy is always fail_over_limit. The first excess accepted
row fails before output rather than silently truncating the source.
Choose the cleaned-file shape
side_by_side (recommended for review)
Every original source field appears first and remains unchanged. Generated
fields are appended under a collision-safe namespace such as
contactCleanupCleanedUrl, contactCleanupReviewNeed, and
contactCleanupHumanDecision.
This mode makes the old and proposed values easy to compare. It does not replace a supported source value automatically.
replace_supported_fields
Only a mapped url, email, or address cell with an exact safe,
no_review replacement changes in place. The generated namespace retains the
displaced original supported values and the same decision fields. Original
fields outside those three mapped targets remain exact.
A missing safe replacement, a review-required result, blank input, or rejected row is never turned into an automatic replacement. This mode is deterministic projection, not verification, merge, or survivor selection.
csv
The CSV export is UTF-8 with a header. CSV-origin columns and order are preserved, followed by generated fields. JSON-origin source values are encoded as compact JSON text inside CSV cells so numbers, booleans, nulls, strings, arrays, and objects remain distinguishable. For example, a JSON string source value is represented by JSON text including its quote characters; it is not silently flattened to an untyped value.
json
The JSON export is a compact UTF-8 array. It preserves native JSON source types and source-defined field order under the workflow's deterministic projection contract.
CSV and JSON are semantically equivalent workflow choices, but different serializations are not byte-identical to each other. Replaying the same input and the same selected format produces the same maintained artifact bytes.
Your four workflow files
The default Key-Value Store contains the buyer workflow package:
| File | Use it for | Important boundary |
|---|---|---|
CLEANED_CONTACT_REVIEW.csv or .json | Review the whole file and reimport after decisions are resolved | This is the primary whole-file artifact |
RECORDS_TO_REVIEW.json | Work only the rows that need attention or carry a human decision | Includes blank/rejected identities that are intentionally absent from the Dataset |
POSSIBLE_MATCH_GROUPS.json | Review same-run URL, email, or address candidates | Groups are evidence for a person, never merge instructions |
RUN_SUMMARY.json | Confirm route, format, counts, and exact artifact keys | Written at artifacts_ready, before Dataset publication |
The Dataset is a secondary accepted-row review surface. It preserves each accepted original row as typed JSON beside safe cleaned values, workflow facts, and possible-match references. It is not the reimport file and excludes structurally blank or rejected source rows.
The final structured OUTPUT is written only after the four Key-Value Store
records and all Dataset batches are acknowledged. It records the final
operation state, not a storage readback, live price, or exactly-once
transaction proof.
See docs/output-examples.md for concrete rows and a complete review/reimport walkthrough.
Review and reimport
- Read
RUN_SUMMARY.jsonand confirm the source route, source format, export mode, export format, source count, accepted count, review count, possible match count, and four artifact keys. - Open
RECORDS_TO_REVIEW.json. Useidentity.sourceRowNumberand an optional business ID to locate each source row. Resolve everyreview_requireditem and preserve the resolution outside this immutable run artifact. - Open
POSSIBLE_MATCH_GROUPS.json. Compare every member of each group.normalized_value_unvalidatedandcontext_onlyexplicitly mean candidate evidence, not a verified duplicate. - Inspect the corresponding rows in
CLEANED_CONTACT_REVIEW.*. Inside_by_side, compare the source and generated fields. Inreplace_supported_fields, compare replaced cells with the displaced original fields. - Reimport the cleaned file only after your review system has applied or reconciled its decisions. Keep your source backup and use your CRM's own validation and rollback controls.
humanDecision begins as unreviewed; the Actor does not invent an approval
or rejection. A possible-match group never deletes a row or chooses which row
should survive.
Recovery: inspect first, never retry blindly
Key-Value Store publication is ordered before Dataset publication, and final
OUTPUT is last. There is no cross-storage transaction, rollback, or
exactly-once guarantee. If execution returns a caught failure,
RECOVERY_STATE.json records the last acknowledged durable milestone and the
first read-only action.
| Observed state | What is known | First safe action |
|---|---|---|
| Deterministic Dataset rejection | Four artifacts and RUN_SUMMARY.json were acknowledged; the attempted Dataset batch committed zero items | GET the four KVS records and inspect the recorded Dataset attempt before any new Dataset POST |
| Dataset transport/5xx failure | Four artifacts were acknowledged; the attempted Dataset batch may or may not have committed | GET the Dataset and four KVS records; reconcile source-row identities and counts before deciding whether any write is safe |
Final OUTPUT write failure | Buyer artifacts and exact Dataset batches were acknowledged; final status commit is unknown | GET OUTPUT, the four KVS records, and Dataset items before considering an overwrite |
| Hard process death | Only the last separately acknowledged durable milestone is known | Inspect KVS, Dataset, and OUTPUT; do not infer later steps from local preparation |
GET-only inspection is the common first step. For deterministic rejection,
recorded Dataset cardinality is zero_rejected.
For transport or server ambiguity, it is unknown_commit and
committedDatasetItemCount is null. Both states set
automaticDatasetRetryForbidden: true. A successful GET inspection can inform
an operator decision, but it cannot retroactively prove a transaction or
erase an unknown commit.
Cost and qualification boundary
The selected local qualification profiles are separate:
- 1,000 accepted rows at 6 exercised source fields; and
- 12 accepted rows at 261 exercised source fields.
Their 1,000-row by 261-field cross-product was not qualified. The same
production-facade window also passed all eight resolved input route/format
cells, both export modes, both export formats, and exact same-format replay
for all four buyer artifacts. The 1,000-row profile has a local configured
estimate of $0.100000 for 1,000 synthetic default Dataset-item event
units.
That number is a deterministic local estimate derived from the configured fixture price. It is not an Actor price, a bill, or a settled charged-event count. Check the current Actor pricing in Apify immediately before a run.
$0.125000 is reserved only as a candidate cap for a separately authorized
later live test. It is not this package's price and it does not authorize a
run. No custom charge call occurs in the locally qualified workflow; any
synthetic default Dataset-item billing remains platform-owned and must be
proved on the live surface that owns it.
The 1,000-row run completed locally in about 0.178 seconds with a measured peak working set of 47,427,584 bytes. Those values describe one qualification host and fixture, not an SLA, production latency, concurrency, or memory guarantee.
If the current Actor is offered as Pay Per Event, the platform owns the synthetic default Dataset-item event charge. Check the current price and your run cap in Apify before execution.
Supported cleanup semantics
- URL: safe structural normalization such as scheme/host normalization and removal of known tracking fragments. The Actor does not crawl or verify the destination.
- Email: conservative syntax normalization and deterministic review signals. The Actor does not send mail, verify deliverability, prove inbox existence, or prove ownership.
- Address: conservative U.S.-leaning normalization with unit-aware comparison signals. The Actor does not geocode or certify postal deliverability.
- Possible matches: deterministic same-run candidate groups with stable IDs and reason codes. These do not prove identity and never merge records.
Unknown source fields are preserved as data; they are not interpreted as additional cleanup targets. The workflow is deterministic and does not call external enrichment or verification providers.
Integration recipes
API or task input
Submit the same JSON shapes shown above. Do not depend on Console prefill.
Use a fixed file/KVS reference or Dataset ID, explicit mappings, an explicit
sourceMaxRows <= 1000, and your chosen workflow object.
Reading results
Use Actor Output links or Key-Value Store GETs for the four named records. Use the Dataset review view for accepted-row exploration. Dataset views change presentation only; they do not create a new export or replace the whole-file artifact.
Scheduled runs
Treat each run as a separately reviewed package. Store the run ID, source identity, selected workflow controls, exact build, and artifact keys. Do not automatically replay failed Dataset writes or infer version, price, or output behavior from a schedule, task, or moving build selector.
Explicit nonclaims
Contact Cleanup does not claim:
- deployment, Store availability, or price without a current Apify check;
- current live pricing or charged-event settlement;
- unlimited volume, production throughput, or an SLA;
- website reachability, email or postal deliverability, ownership, or identity;
- enrichment, geocoding, confidence scoring, or external verification;
- automatic merge, deletion, ranking, or survivor selection;
- cross-storage transactions, rollback, exactly-once delivery, or storage readback; or
- that a generated schema, fixture, report, or successful local command proves live consumer behavior.
Permissions
The Actor runs with limited permissions. It reads only the input resources you select, writes its run-scoped Dataset and Key-Value Store outputs, and does not contact enrichment, verification, geocoding, or scraping providers.
Maintained evidence
The examples in this package are projected from
.actor/smoke_input.json through the same Contact 2.0 production workflow and
frozen in
tests/fixtures/workflow_v3_buyer_workflow_package.json. A causal regression
test fails if the runtime projection, fixture, buyer documentation markers,
four schema discovery surfaces, supported ceiling, pricing nonclaim, or
recovery guidance drifts.
For release history, see CHANGELOG.md.