CRM Contact Cleanup & Dedupe Prep avatar

CRM Contact Cleanup & Dedupe Prep

Pricing

$0.10 / 1,000 processed rows

Go to Apify Store
CRM Contact Cleanup & Dedupe Prep

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

Critical Distinction

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 days ago

Last modified

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 version 2.0, and contact-cleanup-output-v3 describe 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, and RUN_SUMMARY.json;
  • final OUTPUT uses contact-cleanup-output-v3 and 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 OUTPUT with 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

  1. Choose one input route: inline records, a file, an Apify Dataset, or a Key-Value Store record.
  2. Map your recordId, url, email, and address columns when their source names differ. Every other source field remains part of the preserved row.
  3. For a source route, preview first with previewOnly: true. Set sourceMaxRows to at most 1000.
  4. Choose an export mode and format under workflow.
  5. Run the workflow, then open the four files listed under Your four workflow files.
  6. Resolve review decisions before reimporting CLEANED_CONTACT_REVIEW.csv or CLEANED_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.

RouteRequired inputMappingQualified use
InlinerecordsFixed supported namesUp to 1,000 accepted rows
Filesource.type = "file" and source.fileOptional source.fieldMapPreview, then execute at no more than 1,000 accepted rows
Datasetsource.type = "dataset" and source.datasetIdOptional source.fieldMapReads complete object rows from an optional offset
Key-Value Storesource.type = "keyValueStore", storeId, and recordKeyOptional source.fieldMapReads 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

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:

FileUse it forImportant boundary
CLEANED_CONTACT_REVIEW.csv or .jsonReview the whole file and reimport after decisions are resolvedThis is the primary whole-file artifact
RECORDS_TO_REVIEW.jsonWork only the rows that need attention or carry a human decisionIncludes blank/rejected identities that are intentionally absent from the Dataset
POSSIBLE_MATCH_GROUPS.jsonReview same-run URL, email, or address candidatesGroups are evidence for a person, never merge instructions
RUN_SUMMARY.jsonConfirm route, format, counts, and exact artifact keysWritten 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

  1. Read RUN_SUMMARY.json and confirm the source route, source format, export mode, export format, source count, accepted count, review count, possible match count, and four artifact keys.
  2. Open RECORDS_TO_REVIEW.json. Use identity.sourceRowNumber and an optional business ID to locate each source row. Resolve every review_required item and preserve the resolution outside this immutable run artifact.
  3. Open POSSIBLE_MATCH_GROUPS.json. Compare every member of each group. normalized_value_unvalidated and context_only explicitly mean candidate evidence, not a verified duplicate.
  4. Inspect the corresponding rows in CLEANED_CONTACT_REVIEW.*. In side_by_side, compare the source and generated fields. In replace_supported_fields, compare replaced cells with the displaced original fields.
  5. 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 stateWhat is knownFirst safe action
Deterministic Dataset rejectionFour artifacts and RUN_SUMMARY.json were acknowledged; the attempted Dataset batch committed zero itemsGET the four KVS records and inspect the recorded Dataset attempt before any new Dataset POST
Dataset transport/5xx failureFour artifacts were acknowledged; the attempted Dataset batch may or may not have committedGET the Dataset and four KVS records; reconcile source-row identities and counts before deciding whether any write is safe
Final OUTPUT write failureBuyer artifacts and exact Dataset batches were acknowledged; final status commit is unknownGET OUTPUT, the four KVS records, and Dataset items before considering an overwrite
Hard process deathOnly the last separately acknowledged durable milestone is knownInspect 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.